Decompiled source of SNCompany v1.2.0

plugins/SNCompany.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyCompany("Triangleman")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Makes grading algorithm significantly more advanced, now measuring efficiency per player. Removed fines. Configurable.")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+065aeeef79338dfd140c9201eedde8132169f565")]
[assembly: AssemblyProduct("SNCompany")]
[assembly: AssemblyTitle("com.github.triangleman.sncompany")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Triangleman1/SNCompany")]
[assembly: AssemblyVersion("1.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
internal static class LCMPluginInfo
{
	public const string PLUGIN_GUID = "com.github.triangleman.sncompany";

	public const string PLUGIN_NAME = "SNCompany";

	public const string PLUGIN_VERSION = "1.2.0";
}
namespace SNCompany
{
	public static class Grading
	{
		public static int numPlayersAtLanding;

		public static double dungeonSize;

		public static int totalScrapObjects;

		public static int scrapObjectsCollected;

		public static int scrapValueCollected;

		public static int numOfFireExits;

		public static double[] gradeThresholds;

		public static double valueFactor;

		public static double fireExitEffect;

		public static double groupInefficiency;

		public static double exteriorTime;

		public static double k;

		public static double moonDifficultyScalar;

		public static double branchLengthIncreaseWithSize;

		public static double branchTime;

		public static double mainPathTime;

		public static double interiorOffset;

		public static double interiorDifficulty;

		public static double moonDifficulty;

		public static string moonName;

		public static double shipToEntranceTravelTime;

		public static int numPlayersAtTakeoff;

		public static double numPlayers;

		public static double scrapValueRate;

		public static double scrapObjectRate;

		public static double weightedClearRate;

		public static double totalDungeonClearedBranches;

		public static double totalDungeonClearedMainPath;

		public static double numScrapInteriorOffset;

		public static double branchDistance;

		public static double mainPathDistance;

		public static double mainPathNormalization;

		public static double moonPathDistance;

		public static double totalDistanceCovered;

		public static double efficiency;

		public static double efficiencyAdjusted;

		public static string debug;

		public static Dictionary<string, double> shipToEntranceTimes;

		public static double experimentationTravelTime;

		static Grading()
		{
			numPlayersAtLanding = 4;
			scrapValueCollected = 1000;
			gradeThresholds = new double[5] { 10.0, 40.0, 60.0, 80.0, 100.0 };
			valueFactor = 0.5;
			fireExitEffect = 0.5;
			groupInefficiency = 0.7;
			exteriorTime = 3.87;
			k = 5.42;
			moonDifficultyScalar = 0.0;
			branchLengthIncreaseWithSize = 0.0;
			branchTime = 4.8;
			mainPathTime = 2.41;
			interiorOffset = 0.24;
			interiorDifficulty = 1.0;
			moonDifficulty = 0.0;
			moonName = string.Empty;
			numPlayersAtTakeoff = 4;
			debug = string.Empty;
			shipToEntranceTimes = new Dictionary<string, double>
			{
				{ "Experimentation", 50.0 },
				{ "Assurance", 56.3 },
				{ "Vow", 61.15 },
				{ "Offense", 57.25 },
				{ "March", 50.375 },
				{ "Adamance", 56.5 },
				{ "Rend", 66.5 },
				{ "Dine", 50.6 },
				{ "Titan", 37.0 },
				{ "Artifice", 50.0 },
				{ "Embrion", 67.0 },
				{ "Unknown", 54.79 }
			};
			if (!shipToEntranceTimes.ContainsKey("Experimentation") || !shipToEntranceTimes.ContainsKey("Offense"))
			{
				experimentationTravelTime = 50.0;
				shipToEntranceTravelTime = 57.25;
				Plugin.Log.LogError((object)"Cannot find keys in dictionary");
			}
			else
			{
				experimentationTravelTime = shipToEntranceTimes["Experimentation"];
				shipToEntranceTravelTime = shipToEntranceTimes["Offense"];
			}
			valueFactor = Plugin.BoundConfig.valueFactor.Value;
			groupInefficiency = 1.0 - Plugin.BoundConfig.groupInefficiency.Value;
			fireExitEffect = Plugin.BoundConfig.fireExitEffect.Value;
			numPlayers = 4.0;
			dungeonSize = 1.2;
			numOfFireExits = 1;
			weightedClearRate = 1.0;
			scrapObjectsCollected = 14;
			totalScrapObjects = 14;
			k = 1.0;
			LogGradingVariables();
			efficiency = CalculateEfficiencyPerPlayer();
			LogGradingCalculations();
			k = 100.0 / efficiency;
			Plugin.Log.LogInfo((object)$"Calculated k: {k}");
		}

		public static void PrepareForEfficiencyCalculation(int scrapCollected)
		{
			numPlayersAtTakeoff = RoundManager.Instance.playersManager.connectedPlayersAmount + 1;
			numPlayers = ((double)numPlayersAtTakeoff + (double)numPlayersAtLanding) / 2.0;
			moonName = new string(StartOfRound.Instance.currentLevel.PlanetName.SkipWhile((char c) => !char.IsLetter(c)).ToArray());
			Plugin.Log.LogInfo((object)("Moon: " + moonName + "\n"));
			if (shipToEntranceTimes.ContainsKey(moonName))
			{
				shipToEntranceTravelTime = shipToEntranceTimes[moonName];
			}
			else
			{
				shipToEntranceTravelTime = shipToEntranceTimes["Unknown"];
			}
			scrapValueCollected = scrapCollected;
			scrapValueRate = (double)scrapValueCollected / (double)RoundManager.Instance.totalScrapValueInLevel;
			scrapObjectRate = (double)scrapObjectsCollected / (double)totalScrapObjects;
			weightedClearRate = valueFactor * scrapValueRate + (1.0 - valueFactor) * scrapObjectRate;
		}

		public static void LogGradingVariables()
		{
			debug = $"\ndungeonSize: {dungeonSize}\n";
			debug += $"numofFireExits: {numOfFireExits}\n";
			debug += $"numPlayersAtTakeoff: {numPlayersAtTakeoff}\n";
			debug += $"numPlayersAtLanding: {numPlayersAtLanding}\n";
			debug += $"numPlayers: {numPlayers}\n";
			debug = debug + "moonName: " + moonName + "\n";
			debug += $"shipToEntranceTravelTime: {shipToEntranceTravelTime}\n";
			debug += $"scrapValueRate: {scrapValueRate}\n";
			debug += $"scrapObjectRate: {scrapObjectRate}\n";
			debug += $"weightedClearRate: {weightedClearRate}\n";
			debug += $"valueFactor: {valueFactor}\n";
			debug += $"branchLengthIncreaseWithSize: {branchLengthIncreaseWithSize}\n";
			debug += $"branchTime: {branchTime}\n";
			debug += $"mainPathTime: {mainPathTime}\n";
			debug += $"exteriorTime: {exteriorTime}\n";
			debug += $"interiorOffset: {interiorOffset}\n";
			debug += $"experimentationTravelTime: {experimentationTravelTime}\n";
			debug += $"fireExitEffect: {fireExitEffect}\n";
			debug += $"groupInefficiency: {groupInefficiency}\n";
			debug += $"moonDifficultyScalar: {moonDifficultyScalar}\n";
			debug += $"moonDifficulty: {moonDifficulty}\n";
			debug += $"interiorDifficulty: {interiorDifficulty}\n";
			debug += $"constant k: {k}\n";
			Plugin.Log.LogInfo((object)debug);
		}

		public static double CalculateEfficiencyPerPlayer()
		{
			totalDungeonClearedBranches = weightedClearRate * dungeonSize;
			branchDistance = Math.Pow(totalDungeonClearedBranches, 1.0 + branchLengthIncreaseWithSize);
			totalDungeonClearedMainPath = weightedClearRate * (dungeonSize / (1.0 + (double)(2 * numOfFireExits) * fireExitEffect));
			numScrapInteriorOffset = interiorOffset * (double)totalScrapObjects / dungeonSize;
			mainPathNormalization = 1.0 * (1.0 / (1.0 + 2.0 * fireExitEffect)) * (10.0 - interiorOffset * 10.0 / 1.0);
			mainPathDistance = totalDungeonClearedMainPath * ((double)scrapObjectsCollected - numScrapInteriorOffset) / mainPathNormalization;
			if (mainPathDistance < 0.0)
			{
				mainPathDistance = 0.0;
			}
			moonPathDistance = shipToEntranceTravelTime / experimentationTravelTime * (double)scrapObjectsCollected / 10.0;
			totalDistanceCovered = branchTime * branchDistance + mainPathTime * mainPathDistance + exteriorTime * moonPathDistance;
			efficiency = k * totalDistanceCovered / Math.Pow(numPlayers, groupInefficiency);
			efficiencyAdjusted = efficiency * (1.0 + moonDifficultyScalar * moonDifficulty) * interiorDifficulty;
			return efficiencyAdjusted;
		}

		public static void LogGradingCalculations()
		{
			debug = $"\ntotalDungeonCleared (branches): {totalDungeonClearedBranches}\n";
			debug += $"branchDistance: {branchDistance}\n";
			debug += $"totalDungeonCleared (main path): {totalDungeonClearedMainPath}\n";
			debug += $"numScrapInteriorOffset: {numScrapInteriorOffset}\n";
			debug += $"mainPathNormalizationFactor: {mainPathNormalization}\n";
			debug += $"mainPathDistance: {mainPathDistance}\n";
			debug += $"moonPathDistance: {moonPathDistance}\n";
			debug += $"totalDistanceCovered: {totalDistanceCovered}\n";
			debug += $"efficiency: {efficiency}\n";
			debug += $"efficiencyDifficultyAdjusted: {efficiencyAdjusted}\n";
			Plugin.Log.LogInfo((object)debug);
		}

		public static int FindNumOfFireExits()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			Scene sceneByName = SceneManager.GetSceneByName(StartOfRound.Instance.currentLevel.sceneName);
			GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
			GameObject[] array = rootGameObjects;
			foreach (GameObject val in array)
			{
				EntranceTeleport[] componentsInChildren = val.GetComponentsInChildren<EntranceTeleport>();
				num += componentsInChildren.Length;
			}
			return num / 2 - 1;
		}
	}
	[BepInPlugin("com.github.triangleman.sncompany", "SNCompany", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public static ManualLogSource Log;

		public static Texture2D mainLogo;

		internal static SNConfig BoundConfig { get; private set; }

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Harmony val = new Harmony("com.github.triangleman.sncompany");
			BoundConfig = new SNConfig(((BaseUnityPlugin)this).Config);
			if (BoundConfig.vandalizeLogo.Value)
			{
				AssetBundle val2 = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "sncompany.assetbundle"));
				if ((Object)(object)val2 != (Object)null)
				{
					mainLogo = val2.LoadAsset<Texture2D>("ShawnNewman.png");
				}
				else
				{
					Log.LogError((object)"Failed to load bundle");
				}
			}
			try
			{
				val.PatchAll();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to patch: " + ex));
			}
			Log.LogInfo((object)"Plugin SNCompany is loaded!");
		}
	}
	internal class SNConfig
	{
		public readonly ConfigEntry<bool> vandalizeLogo;

		public readonly ConfigEntry<bool> removeFines;

		public readonly ConfigEntry<bool> advancedGrading;

		public readonly ConfigEntry<double> valueFactor;

		public readonly ConfigEntry<double> groupInefficiency;

		public readonly ConfigEntry<double> fireExitEffect;

		public SNConfig(ConfigFile cfg)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			cfg.SaveOnConfigSet = false;
			vandalizeLogo = cfg.Bind<bool>("General", "VandalizeLogo", false, "Whether I smear my full, actual name across your screen. I set this to true. Not sure why you'd want to.");
			removeFines = cfg.Bind<bool>("General", "RemoveFines", true, "If true, removes fines.");
			advancedGrading = cfg.Bind<bool>("General", "AdvancedGrading", true, "If true, replaces vanilla grading algorithm with a custom one. Prioiritizes effort and efficiency over pure completion.");
			valueFactor = cfg.Bind<double>("Grading Parameters", "ValueFactor", 0.5, new ConfigDescription("To determine dungeon clear rate, a weighted average is taken of the percentage of scrap objects found and the percentage of scrap value found. The value factor is that weight. A higher value factor prioritizes value, while a lower value factor prioritizes the quantity of objects. \nNote: Even with a value factor of 1, the amount of objects found still has an effect elsewhere, when modeling the number of trips made back to the ship. Therefore, quantity is still more influential than value with a value factor of 0.5.\nAcceptable Values: 0 to 1", (AcceptableValueBase)null, Array.Empty<object>()));
			groupInefficiency = cfg.Bind<double>("Grading Parameters", "GroupInefficiency", 0.3, new ConfigDescription("Ideally, twice as many players will be twice as efficient at scavenging and retrieving scrap. In practice, due to lower pressure, caution, chaos, and confusion, this rarely occurs. Group Inefficiency corrects the relationship between player count and score. At 0, it will expect a perfectly linear relationship, with twice as many players accomplishing twice as much. At 1, player count will not affect score at all.\nNote: Grade letter thresholds are calculated for 4 players. A lower groupInefficiency will grade easier for less players, and harder for many players. A high groupInefficiency will do the opposite.\nAcceptable Values: 0 to 1", (AcceptableValueBase)null, Array.Empty<object>()));
			fireExitEffect = cfg.Bind<double>("Grading Parameters", "fireExitEffect", 0.5, new ConfigDescription("A fireExitEffect of 1 assumes perfect placement and utilization of fire exits. A fireExitEffect of 0 will entirely remove fire exits from the equation.\nAcceptable Values: 0 to 1", (AcceptableValueBase)null, Array.Empty<object>()));
			ClearOrphanedEntries(cfg);
			cfg.Save();
			cfg.SaveOnConfigSet = true;
		}

		private static void ClearOrphanedEntries(ConfigFile cfg)
		{
			PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries");
			Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(cfg);
			dictionary.Clear();
		}
	}
}
namespace SNCompany.Patches
{
	[HarmonyPatch]
	internal static class GradingPatches
	{
		[HarmonyPatch(typeof(StartOfRound), "openingDoorsSequence")]
		[HarmonyPostfix]
		public static void SavePlayersAndFireExitsAtStart()
		{
			Grading.numPlayersAtLanding = HUDManager.Instance.playersManager.livingPlayers;
			Plugin.Log.LogDebug((object)$"Number of players saved as {Grading.numPlayersAtLanding}");
			Plugin.Log.LogDebug((object)"FindNumOfFireExitsPatch Running");
			Grading.numOfFireExits = Grading.FindNumOfFireExits();
			Plugin.Log.LogDebug((object)$"Number of fire exits saved as {Grading.numOfFireExits}");
		}

		[HarmonyPatch(typeof(RoundManager), "GenerateNewFloor")]
		[HarmonyPostfix]
		public static void SaveDungeonSize()
		{
			Grading.dungeonSize = RoundManager.Instance.currentLevel.factorySizeMultiplier;
			Plugin.Log.LogDebug((object)$"mapSizeMultiplier is {RoundManager.Instance.mapSizeMultiplier}");
			Plugin.Log.LogDebug((object)$"[currentDungeonType].MapTileSize as {RoundManager.Instance.dungeonFlowTypes[RoundManager.Instance.currentDungeonType].MapTileSize}");
			Plugin.Log.LogDebug((object)$"Dungeon length saved as {Grading.dungeonSize} (currentLevel.factorySizeMultiplier)");
		}

		[HarmonyPatch(typeof(RoundManager), "SyncScrapValuesClientRpc")]
		[HarmonyPostfix]
		public static void SaveTotalScrapAmount(GameObject[] spawnedScrap)
		{
			Grading.totalScrapObjects = spawnedScrap.Length;
			Plugin.Log.LogDebug((object)$"Scrap Quantity saved as {Grading.totalScrapObjects}");
		}

		[HarmonyPatch(typeof(StartOfRound), "EndOfGameClientRpc")]
		[HarmonyPrefix]
		public static void SaveCollectedScrapAmount()
		{
			Plugin.Log.LogDebug((object)"Running SaveCollectedScrapAmount()");
			Grading.scrapObjectsCollected = RoundManager.Instance.scrapCollectedThisRound.Count;
			Plugin.Log.LogDebug((object)$"Scrap Objects Collected saved as {Grading.scrapObjectsCollected}");
		}

		[HarmonyPatch(typeof(HUDManager), "FillEndGameStats")]
		[HarmonyPostfix]
		public static void FairGrading(int scrapCollected)
		{
			if (Plugin.BoundConfig.advancedGrading.Value)
			{
				double num;
				if (StartOfRound.Instance.allPlayersDead)
				{
					num = 0.0;
					Plugin.Log.LogDebug((object)"efficiency: 0 (All Players Lost)");
				}
				else
				{
					Grading.PrepareForEfficiencyCalculation(scrapCollected);
					Grading.LogGradingVariables();
					num = Grading.CalculateEfficiencyPerPlayer();
					Grading.LogGradingCalculations();
				}
				if (num < Grading.gradeThresholds[0])
				{
					((TMP_Text)HUDManager.Instance.statsUIElements.gradeLetter).text = "F";
				}
				else if (num < Grading.gradeThresholds[1])
				{
					((TMP_Text)HUDManager.Instance.statsUIElements.gradeLetter).text = "D";
				}
				else if (num < Grading.gradeThresholds[2])
				{
					((TMP_Text)HUDManager.Instance.statsUIElements.gradeLetter).text = "C";
				}
				else if (num < Grading.gradeThresholds[3])
				{
					((TMP_Text)HUDManager.Instance.statsUIElements.gradeLetter).text = "B";
				}
				else if (num < Grading.gradeThresholds[4])
				{
					((TMP_Text)HUDManager.Instance.statsUIElements.gradeLetter).text = "A";
				}
				else
				{
					((TMP_Text)HUDManager.Instance.statsUIElements.gradeLetter).text = "S";
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Penalties
	{
		[HarmonyPatch(typeof(HUDManager), "ApplyPenalty")]
		[HarmonyPrefix]
		public static bool RemovePenalty()
		{
			if (Plugin.BoundConfig.removeFines.Value)
			{
				((TMP_Text)HUDManager.Instance.statsUIElements.penaltyAddition).text = "COMPANY PROPERTY LOST\nALL OF YOU ARE UNSATISFACTORY ASSETS";
				((TMP_Text)HUDManager.Instance.statsUIElements.penaltyTotal).text = "DUE: 0";
				Plugin.Log.LogDebug((object)"Removed Fine");
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class ReplaceLogo
	{
		[HarmonyPatch(typeof(MenuManager), "Awake")]
		[HarmonyPostfix]
		[HarmonyPriority(-100)]
		public static void MainMenuLogo(MenuManager __instance)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.isInitScene || !Plugin.BoundConfig.vandalizeLogo.Value)
			{
				return;
			}
			try
			{
				Sprite sprite = Sprite.Create(Plugin.mainLogo, new Rect(0f, 0f, (float)((Texture)Plugin.mainLogo).width, (float)((Texture)Plugin.mainLogo).height), new Vector2(0.5f, 0.5f));
				GameObject gameObject = ((Component)((Component)__instance).transform.parent).gameObject;
				Transform val = gameObject.transform.Find("MenuContainer/MainButtons/HeaderImage");
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.GetComponent<Image>().sprite = sprite;
				}
				Transform val2 = gameObject.transform.Find("MenuContainer/LoadingScreen");
				if ((Object)(object)val2 != (Object)null)
				{
					val2.localScale = new Vector3(1.02f, 1.06f, 1.02f);
					Transform val3 = val2.Find("Image");
					if ((Object)(object)val3 != (Object)null)
					{
						((Component)val3).GetComponent<Image>().sprite = sprite;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
			}
		}
	}
}