Decompiled source of FirstDayCompany v1.0.0

Solon.FirstDayCompany.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FirstDayCompany.Compat;
using FirstDayCompany.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Solon.FirstDayCompany")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FirstDayCompany")]
[assembly: AssemblyTitle("Solon.FirstDayCompany")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FirstDayCompany
{
	internal static class FirstDayRouter
	{
		private static bool _warnedMissingMoon;

		public static bool TryGetForcedLevel(StartOfRound round, out int levelIndex, out SelectableLevel level)
		{
			levelIndex = -1;
			level = null;
			if (Plugin.Cfg == null || !Plugin.Cfg.ForceFirstDay.Value)
			{
				return false;
			}
			if ((Object)(object)round == (Object)null || !((NetworkBehaviour)round).IsServer)
			{
				return false;
			}
			if (round.isChallengeFile)
			{
				Plugin.DebugLog("Challenge file — leaving the route alone.");
				return false;
			}
			int num = ((round.gameStats != null) ? round.gameStats.daysSpent : (-1));
			if (num != 0)
			{
				Plugin.DebugLog($"Not day 1 (days spent: {num}) — " + "passing control to " + RandomMoonFxCompat.RouteOwner + ".");
				return false;
			}
			if (RandomMoonFxCompat.IsLastDayOfQuota())
			{
				Plugin.Log.LogInfo((object)"Day 1 is also the last day of the quota — leaving the Company routing to RandomMoonFX.");
				return false;
			}
			string value = Plugin.Cfg.FirstDayMoon.Value;
			level = MoonHelper.Find(round, value, out levelIndex);
			if ((Object)(object)level == (Object)null)
			{
				if (!_warnedMissingMoon)
				{
					_warnedMissingMoon = true;
					ManualLogSource log = Plugin.Log;
					SelectableLevel[] levels = round.levels;
					log.LogWarning((object)($"'{value}' not found among the {((levels != null) ? levels.Length : 0)} " + "available moons — skipping force. Check the [General] FirstDayMoon config against the moon names in your terminal."));
				}
				return false;
			}
			return true;
		}

		public static bool Route(StartOfRound round, int levelIndex)
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			int num = (((Object)(object)val != (Object)null) ? val.groupCredits : 0);
			round.ChangeLevelServerRpc(levelIndex, num);
			return round.travellingToNewLevel;
		}
	}
	internal static class MoonHelper
	{
		private static readonly string[] CompanyAliases = new string[4] { "gordion", "71gordion", "companybuilding", "company" };

		public static SelectableLevel Find(StartOfRound round, string wantedName, out int index)
		{
			index = -1;
			SelectableLevel[] array = round?.levels;
			if (array == null || array.Length == 0)
			{
				return null;
			}
			string text = Normalize(wantedName);
			if (text.Length == 0)
			{
				return null;
			}
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null && Normalize(array[i].PlanetName) == text)
				{
					return Result(array, i, out index);
				}
			}
			for (int j = 0; j < array.Length; j++)
			{
				if (!((Object)(object)array[j] == (Object)null) && (Normalize(array[j].sceneName) == text || Normalize(((Object)array[j]).name) == text))
				{
					return Result(array, j, out index);
				}
			}
			if (Array.IndexOf(CompanyAliases, text) >= 0)
			{
				for (int k = 0; k < array.Length; k++)
				{
					if ((Object)(object)array[k] != (Object)null && !array[k].planetHasTime && !array[k].spawnEnemiesAndScrap)
					{
						Plugin.DebugLog("'" + wantedName + "' matched no name; using '" + array[k].PlanetName + "' (no day cycle, nothing spawns) as the Company building.");
						return Result(array, k, out index);
					}
				}
			}
			return null;
		}

		private static SelectableLevel Result(SelectableLevel[] levels, int i, out int index)
		{
			index = i;
			return levels[i];
		}

		public static string Normalize(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return string.Empty;
			}
			int i;
			for (i = 0; i < name.Length && char.IsDigit(name[i]); i++)
			{
			}
			if (i >= name.Length)
			{
				i = 0;
			}
			StringBuilder stringBuilder = new StringBuilder(name.Length - i);
			for (int j = i; j < name.Length; j++)
			{
				char c = name[j];
				if (c != ' ' && c != '-' && c != '_')
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}
	}
	[BepInPlugin("Solon.FirstDayCompany", "FirstDayCompany", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static PluginConfig Cfg { get; private set; }

		private void Awake()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new PluginConfig(((BaseUnityPlugin)this).Config);
			RandomMoonFxCompat.Scan();
			_harmony = new Harmony("Solon.FirstDayCompany");
			_harmony.PatchAll(typeof(StartOfRoundPatches));
			if (!Cfg.ForceFirstDay.Value)
			{
				Log.LogInfo((object)"FirstDayCompany v1.0.0 loaded, but ForceFirstDay is off — the first day is left alone.");
			}
			else
			{
				Log.LogInfo((object)("FirstDayCompany v1.0.0 loaded. Day 1 of a new save will route to '" + Cfg.FirstDayMoon.Value + "'. " + RandomMoonFxCompat.Describe()));
			}
		}

		internal static void DebugLog(string message)
		{
			if (Cfg != null && Cfg.DebugMode.Value)
			{
				Log.LogInfo((object)("[Debug] " + message));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal sealed class PluginConfig
	{
		public readonly ConfigEntry<bool> ForceFirstDay;

		public readonly ConfigEntry<string> FirstDayMoon;

		public readonly ConfigEntry<float> TakeoffDelay;

		public readonly ConfigEntry<bool> DebugMode;

		public PluginConfig(ConfigFile file)
		{
			ForceFirstDay = file.Bind<bool>("General", "ForceFirstDay", true, "Force the ship's first departure of a save file to go to the Company building.\nOnly the very first day counts (the game's own \"days spent\" counter is still 0);\nfrom the second day on the route is decided by whatever else is installed.\nTurn this off to disable the mod without uninstalling it.");
			FirstDayMoon = file.Bind<string>("General", "FirstDayMoon", "Gordion", "Which moon the first day routes to. Matched against the moon's displayed name\n(the leading number is ignored, so \"Gordion\" matches \"71 Gordion\"), then against\nits scene name, so modded moons work too. If the moon cannot be found the mod\nlogs a warning and does nothing, leaving the departure to the other mods.");
			TakeoffDelay = file.Bind<float>("General", "TakeoffDelay", 1.5f, "Seconds to wait after the ship arrives at the forced moon before it starts landing.\nThis is the same breather RandomMoonFX leaves after its own routing animation.\nRaise it if a moon-visuals mod (Celestial Tint, Chameleon) has a longer animation.");
			DebugMode = file.Bind<bool>("General", "DebugMode", false, "Log every departure decision — which day the game thinks it is, which moon was\nresolved and who is handling the route. Off by default to keep the log quiet.");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Solon.FirstDayCompany";

		public const string PLUGIN_NAME = "FirstDayCompany";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace FirstDayCompany.Patches
{
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatches
	{
		private static bool _forcedRoute;

		[HarmonyPrefix]
		[HarmonyPatch("StartGame")]
		[HarmonyPriority(800)]
		[HarmonyBefore(new string[] { "zigzag.randommoonfx" })]
		private static bool StartGamePrefix(StartOfRound __instance)
		{
			if (_forcedRoute)
			{
				_forcedRoute = false;
				if (!FirstDayRouter.TryGetForcedLevel(__instance, out var levelIndex, out var _) || __instance.currentLevelID == levelIndex)
				{
					RandomMoonFxCompat.SuppressNextRandomization();
					return true;
				}
			}
			if (!FirstDayRouter.TryGetForcedLevel(__instance, out var levelIndex2, out var level2))
			{
				return true;
			}
			if (__instance.currentLevelID == levelIndex2)
			{
				Plugin.Log.LogInfo((object)("Day 1 detected — already routed to " + level2.PlanetName + ", taking off."));
				RandomMoonFxCompat.SuppressNextRandomization();
				return true;
			}
			Plugin.Log.LogInfo((object)("Day 1 detected — forcing route to " + level2.PlanetName + "."));
			if (!FirstDayRouter.Route(__instance, levelIndex2))
			{
				Plugin.Log.LogWarning((object)"The game refused the reroute (already travelling, or the level was locked) — leaving this departure to the other mods.");
				return true;
			}
			_forcedRoute = true;
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch("TravelToLevelEffects")]
		private static IEnumerator TravelToLevelEffectsPostfix(IEnumerator result)
		{
			while (result.MoveNext())
			{
				yield return result.Current;
			}
			if (!_forcedRoute)
			{
				yield break;
			}
			StartOfRound round = StartOfRound.Instance;
			if (!((Object)(object)round == (Object)null) && ((NetworkBehaviour)round).IsServer)
			{
				StartMatchLever val = Object.FindObjectOfType<StartMatchLever>();
				InteractTrigger trigger = (((Object)(object)val != (Object)null) ? val.triggerScript : null);
				if ((Object)(object)trigger != (Object)null)
				{
					trigger.interactable = false;
				}
				float num = Mathf.Max(0f, Plugin.Cfg.TakeoffDelay.Value);
				if (num > 0f)
				{
					yield return (object)new WaitForSeconds(num);
				}
				if ((Object)(object)trigger != (Object)null)
				{
					trigger.interactable = true;
				}
				Plugin.DebugLog("Arrived at " + round.currentLevel?.PlanetName + " — starting the landing.");
				round.StartGameServerRpc();
			}
		}
	}
}
namespace FirstDayCompany.Compat
{
	internal static class RandomMoonFxCompat
	{
		internal const string Guid = "zigzag.randommoonfx";

		private const string PluginTypeName = "RandomMoonFX.Plugin";

		private static bool _bound;

		private static bool _warnedNotBound;

		private static FieldInfo _instanceField;

		private static FieldInfo _isStartingField;

		private static MethodInfo _lastDayOfQuota;

		public static bool Present => _bound;

		public static bool RandomizesDepartures { get; private set; }

		public static string RouteOwner
		{
			get
			{
				if (!Present)
				{
					return "the game";
				}
				return "RandomMoonFX";
			}
		}

		public static void Scan()
		{
			if (_bound)
			{
				return;
			}
			try
			{
				Type type = AccessTools.TypeByName("RandomMoonFX.Plugin");
				if (type == null)
				{
					if (!_warnedNotBound && Chainloader.PluginInfos.ContainsKey("zigzag.randommoonfx"))
					{
						_warnedNotBound = true;
						Plugin.Log.LogWarning((object)"RandomMoonFX is loaded but its Plugin type was not found — running as if it were absent.");
					}
					return;
				}
				_instanceField = AccessTools.Field(type, "instance");
				_isStartingField = AccessTools.Field(type, "IsStarting");
				_lastDayOfQuota = AccessTools.Method(type, "LastDayOfQuota", (Type[])null, (Type[])null);
				_bound = true;
				MethodBase methodBase = AccessTools.Method(typeof(StartOfRound), "StartGame", (Type[])null, (Type[])null);
				Patches obj = ((methodBase != null) ? Harmony.GetPatchInfo(methodBase) : null);
				RandomizesDepartures = obj != null && obj.Prefixes?.Any((Patch p) => p.owner == "zigzag.randommoonfx") == true;
				Plugin.DebugLog($"RandomMoonFX bound — instance: {_instanceField != null}, " + $"IsStarting: {_isStartingField != null}, " + $"LastDayOfQuota: {_lastDayOfQuota != null}, " + $"randomizing: {RandomizesDepartures}.");
				if (_isStartingField == null && !_warnedNotBound)
				{
					_warnedNotBound = true;
					Plugin.Log.LogWarning((object)"RandomMoonFX is installed but its IsStarting flag was not found. The first day may be randomized away from the forced moon — please report your RandomMoonFX version.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("RandomMoonFX detection failed: " + ex.Message));
			}
		}

		public static void SuppressNextRandomization()
		{
			Scan();
			if (_isStartingField == null)
			{
				return;
			}
			try
			{
				object obj = _instanceField?.GetValue(null);
				if (obj != null)
				{
					_isStartingField.SetValue(obj, true);
					Plugin.DebugLog("Told RandomMoonFX to let this departure through.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not set RandomMoonFX's IsStarting flag: " + ex.Message));
			}
		}

		public static bool IsLastDayOfQuota()
		{
			Scan();
			if (_lastDayOfQuota == null)
			{
				return false;
			}
			try
			{
				object obj = _instanceField?.GetValue(null);
				if (obj == null)
				{
					return false;
				}
				object obj2 = _lastDayOfQuota.Invoke(obj, null);
				bool flag = default(bool);
				int num;
				if (obj2 is bool)
				{
					flag = (bool)obj2;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("RandomMoonFX's last-day check failed: " + (ex.InnerException?.Message ?? ex.Message)));
				return false;
			}
		}

		public static string Describe()
		{
			if (!Present)
			{
				return "RandomMoonFX not detected — running standalone.";
			}
			if (!RandomizesDepartures)
			{
				return "RandomMoonFX detected but not randomizing departures — running standalone.";
			}
			return "RandomMoonFX detected; it keeps every other day.";
		}
	}
}