Decompiled source of PartialPrints v0.6.0

m75partialprints.dll

Decompiled 3 months ago
using System;
using System.Collections.Generic;
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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Text;
using Microsoft.CodeAnalysis;
using SOD.Common;
using SOD.Common.BepInEx;
using SOD.Common.Extensions;
using SOD.Common.Helpers;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("m75partialprints")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("0.6.0.0")]
[assembly: AssemblyInformationalVersion("0.6.0")]
[assembly: AssemblyProduct("m75partialprints")]
[assembly: AssemblyTitle("m75partialprints")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.6.0.0")]
[module: UnverifiableCode]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace m75partialprints
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "m75partialprints";

		public const string PLUGIN_NAME = "m75partialprints";

		public const string PLUGIN_VERSION = "0.6.0";
	}
}
namespace partialprints
{
	[BepInPlugin("m75partialprints", "m75partialprints", "0.6.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class PartialPrints : PluginController<PartialPrints>
	{
		private static ConfigEntryCache<int> ConfigCodeLength;

		private static ConfigEntryCache<int> ConfigLettersPerDigit;

		private static ConfigEntryCache<int> ConfigSmudgeMin;

		private static ConfigEntryCache<int> ConfigSmudgeMax;

		public static readonly HashSet<MatchPreset> ProcessedMatchPresets = new HashSet<MatchPreset>();

		private static readonly Dictionary<uint, string> _fullPrintCache = new Dictionary<uint, string>();

		private static int[] _partialIndicesOriginal;

		private static int[] _partialIndicesShuffled;

		private static string _lastFullPrint;

		private static uint _lastFullCitizen;

		private static string _lastPartialPrint;

		private static uint _lastPartialCitizen;

		private static string _lastPartialEvidence;

		private static readonly StringBuilder _builder = new StringBuilder();

		private static uint _citySeedCache;

		public override void Load()
		{
			InitializeConfig();
			((PluginController<PartialPrints, IEmptyBindings>)(object)this).Harmony.PatchAll(Assembly.GetExecutingAssembly());
			PluginController<PartialPrints, IEmptyBindings>.Log.LogInfo((object)"Plugin is patched.");
			Lib.SaveGame.OnAfterNewGame -= OnAfterNewGame;
			Lib.SaveGame.OnAfterNewGame += OnAfterNewGame;
			Lib.SaveGame.OnAfterLoad -= OnAfterLoad;
			Lib.SaveGame.OnAfterLoad += OnAfterLoad;
			InitializeStructures();
		}

		public override bool Unload()
		{
			Lib.SaveGame.OnAfterNewGame -= OnAfterNewGame;
			Lib.SaveGame.OnAfterLoad -= OnAfterLoad;
			return ((PluginController<PartialPrints, IEmptyBindings>)(object)this).Unload();
		}

		private void OnAfterNewGame(object sender, EventArgs e)
		{
			Reinitialize();
		}

		private void OnAfterLoad(object save, SaveGameArgs args)
		{
			Reinitialize();
		}

		private void InitializeConfig()
		{
			ConfigCodeLength = new ConfigEntryCache<int>(base.Config, "General", "Code Length", 5, "How long each fingerprint code is, in characters.\nNOTE: There is no logic to prevent duplicate codes! If the code is too short there is a chance of duplicates.");
			ConfigLettersPerDigit = new ConfigEntryCache<int>(base.Config, "General", "Letters Per Digit", 26, "How many letters of the alphabet the fingerprint codes can use. Default uses all 26 letters, but decreasing the amount can add some ambiguity to prints.\nFor example, setting it to 10 would limit the codes to letters to A to J. Increasing this above 26 may cause odd behaviour.\nNOTE: As stated above, duplicate codes can exist. If you decrease this, it is recommended to increase the codes length.");
			ConfigSmudgeMin = new ConfigEntryCache<int>(base.Config, "General", "Minimum Smudge Amount", 2, "The minimum amount of \"smudged\" letters on partial fingerprints");
			ConfigSmudgeMax = new ConfigEntryCache<int>(base.Config, "General", "Maximum Smudge Amount", 4, "The maximum amount of \"smudged\" letters on partial fingerprints");
			ConfigSmudgeMin.Value = Mathf.Clamp(ConfigSmudgeMin.Value, 0, ConfigCodeLength.Value);
			ConfigSmudgeMax.Value = Mathf.Clamp(ConfigSmudgeMax.Value, 0, ConfigCodeLength.Value);
			if (ConfigSmudgeMin.Value > ConfigSmudgeMax.Value)
			{
				int value = ConfigSmudgeMin.Value;
				ConfigSmudgeMin.Value = ConfigSmudgeMax.Value;
				ConfigSmudgeMax.Value = value;
			}
		}

		private void InitializeStructures()
		{
			int value = ConfigCodeLength.Value;
			_partialIndicesOriginal = new int[value];
			_partialIndicesShuffled = new int[value];
			for (int i = 0; i < value; i++)
			{
				_partialIndicesOriginal[i] = i;
				_partialIndicesShuffled[i] = i;
			}
			ProcessedMatchPresets.Clear();
		}

		private void Reinitialize()
		{
			_fullPrintCache.Clear();
			_citySeedCache = GetDeterministicStringHash(CityData.Instance.seed);
		}

		private static uint GetDeterministicStringHash(string s)
		{
			return Lib.SaveGame.GetUniqueNumber(s);
		}

		private static char GetPrintCharacter(uint citizenIndex, uint letterIndex)
		{
			uint citySeedCache = _citySeedCache;
			citySeedCache ^= citySeedCache << 13;
			citySeedCache ^= citySeedCache >> 17;
			citySeedCache ^= citySeedCache << 5;
			citySeedCache += (uint)(-1640531535 * (int)citizenIndex);
			citySeedCache ^= citySeedCache << 13;
			citySeedCache ^= citySeedCache >> 17;
			citySeedCache ^= citySeedCache << 5;
			citySeedCache += 1629267613 * letterIndex;
			citySeedCache ^= citySeedCache << 13;
			citySeedCache ^= citySeedCache >> 17;
			citySeedCache ^= citySeedCache << 5;
			citySeedCache *= 334214467;
			return (char)(65 + citySeedCache % ConfigLettersPerDigit.Value);
		}

		private static int ShufflePartialIndices(uint citizenIndex, string evidenceID)
		{
			uint citySeedCache = _citySeedCache;
			citySeedCache ^= citySeedCache << 13;
			citySeedCache ^= citySeedCache >> 17;
			citySeedCache ^= citySeedCache << 5;
			citySeedCache += (uint)(-5 * (int)citizenIndex);
			citySeedCache ^= citySeedCache << 13;
			citySeedCache ^= citySeedCache >> 17;
			citySeedCache ^= citySeedCache << 5;
			citySeedCache += (uint)(-1640531527 * (int)GetDeterministicStringHash(evidenceID));
			citySeedCache ^= citySeedCache << 13;
			citySeedCache ^= citySeedCache >> 17;
			citySeedCache ^= citySeedCache << 5;
			int result = (int)(citySeedCache % (ConfigSmudgeMax.Value - ConfigSmudgeMin.Value + 1)) + ConfigSmudgeMin.Value;
			Array.Copy(_partialIndicesOriginal, _partialIndicesShuffled, ConfigCodeLength.Value);
			for (int num = _partialIndicesShuffled.Length - 1; num > 0; num--)
			{
				citySeedCache *= 2166136261u;
				citySeedCache ^= citySeedCache << 13;
				citySeedCache ^= citySeedCache >> 17;
				citySeedCache ^= citySeedCache << 5;
				int num2 = (int)(citySeedCache % (num + 1));
				int num3 = _partialIndicesShuffled[num];
				_partialIndicesShuffled[num] = _partialIndicesShuffled[num2];
				_partialIndicesShuffled[num2] = num3;
			}
			return result;
		}

		private static string ApplyPartialDashes(string fingerprint, int dashCount)
		{
			_builder.Clear();
			_builder.Append(fingerprint);
			for (int i = 0; i < dashCount; i++)
			{
				_builder[_partialIndicesShuffled[i]] = '-';
			}
			return ((Object)_builder).ToString();
		}

		public static string GetPrintFull(uint citizenIndex)
		{
			if (citizenIndex == _lastFullCitizen)
			{
				return _lastFullPrint;
			}
			_lastFullCitizen = citizenIndex;
			string text = default(string);
			if (_fullPrintCache.TryGetValue(citizenIndex, ref text))
			{
				_lastFullPrint = text;
				return text;
			}
			_builder.Clear();
			for (int i = 0; i < ConfigCodeLength.Value; i++)
			{
				_builder.Append(GetPrintCharacter(citizenIndex, (uint)i));
			}
			text = ((Object)_builder).ToString();
			_fullPrintCache[citizenIndex] = text;
			_lastFullPrint = text;
			return text;
		}

		public static string GetPrintPartial(uint citizenIndex, string evidenceID)
		{
			if (citizenIndex == _lastPartialCitizen && evidenceID == _lastPartialEvidence)
			{
				return _lastPartialPrint;
			}
			_lastPartialCitizen = citizenIndex;
			_lastPartialEvidence = evidenceID;
			string printFull = GetPrintFull(citizenIndex);
			int dashCount = ShufflePartialIndices(citizenIndex, evidenceID);
			return _lastPartialPrint = ApplyPartialDashes(printFull, dashCount);
		}
	}
	[HarmonyPatch(typeof(Evidence), "AddFactLink", new Type[]
	{
		typeof(Fact),
		typeof(DataKey),
		typeof(bool)
	})]
	internal class Evidence_AddFactLinkSingle
	{
		[HarmonyPrefix]
		internal static bool Prefix(Fact newFact, DataKey newKey)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)newKey == 2 && ((Object)newFact.preset).name.Equals("FingerprintBelongsTo"))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Evidence), "AddFactLink", new Type[]
	{
		typeof(Fact),
		typeof(List<DataKey>),
		typeof(bool)
	})]
	internal class Evidence_AddFactLinkMulti
	{
		[HarmonyPrefix]
		internal static bool Prefix(Fact newFact, List<DataKey> newKey)
		{
			if (((Object)newFact.preset).name.Equals("FingerprintBelongsTo") && EnumerableExtensions.AsEnumerable<DataKey>(newKey).Any((DataKey a) => (int)a == 2))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(EvidenceFingerprint), "GetNote")]
	public class M75GetNotePatch
	{
		private static readonly StringBuilder _noteBuilder = new StringBuilder();

		private const string SPRITE_EMPTY = "<sprite=\"icons\" name=\"Checkbox Empty\">";

		private const string SPRITE_CHECKED = "<sprite=\"icons\" name=\"Checkbox Checked\">";

		private const string PREFIX_FONT = "<font=\"PapaManAOE SDF\">";

		private const string SUFFIX_FONT = "</font>";

		public static bool Prefix(ref string __result, EvidenceFingerprint __instance, List<DataKey> keys)
		{
			_noteBuilder.Clear();
			List<DataKey> tiedKeys = ((Evidence)__instance).GetTiedKeys(keys);
			string text = ((!tiedKeys.Contains((DataKey)2)) ? "<sprite=\"icons\" name=\"Checkbox Empty\">" : "<sprite=\"icons\" name=\"Checkbox Checked\">");
			_noteBuilder.Append(text);
			_noteBuilder.Append("Fingerprint");
			_noteBuilder.Append(": ");
			_noteBuilder.Append("<font=\"PapaManAOE SDF\">");
			if (tiedKeys.Contains((DataKey)2) && (Object)(object)((Evidence)__instance).writer != (Object)null)
			{
				_noteBuilder.Append(PartialPrints.GetPrintPartial((uint)((Evidence)__instance).writer.humanID, ((Evidence)__instance).evID));
				_noteBuilder.Append("</font>");
				_noteBuilder.Append(Environment.NewLine);
				_noteBuilder.Append("<sprite=\"icons\" name=\"Checkbox Checked\">");
				_noteBuilder.Append("Description: <font=\"PapaManAOE SDF\">A partial fingerprint.");
				_noteBuilder.Append("</font>");
			}
			else
			{
				_noteBuilder.Append(Strings.Get("descriptors", "?", (Casing)0, false, false, false, (Human)null));
			}
			__result = ((Object)_noteBuilder).ToString();
			return false;
		}
	}
	[HarmonyPatch(typeof(EvidenceFingerprint), "GetNameForDataKey")]
	public class M75GetNameForDataKeyPatch
	{
		public static string Postfix(string __result, EvidenceFingerprint __instance, List<DataKey> inputKeys)
		{
			return "Fingerprint (" + PartialPrints.GetPrintPartial((uint)((Evidence)__instance).writer.humanID, ((Evidence)__instance).evID) + ")";
		}
	}
	[HarmonyPatch(typeof(EvidenceFingerprintController), "CheckEnabled")]
	public class M75EvidenceFingerprintControllerPatch
	{
		public static void Postfix(EvidenceFingerprintController __instance)
		{
			if (__instance.parentWindow.evidenceKeys.Contains((DataKey)2))
			{
				((TMP_Text)__instance.identifierText).text = "ID: " + PartialPrints.GetPrintFull((uint)__instance.parentWindow.passedEvidence.writer.humanID);
			}
		}
	}
	[HarmonyPatch(typeof(GameplayController), "AddNewMatch")]
	public class M75FactMatchesPatch
	{
		public static bool Prefix(MatchPreset match, Evidence newEntry)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			if (PartialPrints.ProcessedMatchPresets.Contains(match))
			{
				return true;
			}
			for (int num = match.matchConditions.Count - 1; num >= 0; num--)
			{
				if ((int)match.matchConditions._items[num] == 1)
				{
					match.matchConditions._items[num] = (MatchCondition)3;
				}
			}
			PartialPrints.ProcessedMatchPresets.Add(match);
			return true;
		}
	}
	public class ConfigEntryCache<T>
	{
		public T Value;

		public ConfigEntryCache(ConfigFile file, string section, string key, T defaultValue, string description)
		{
			ConfigEntry<T> val = file.Bind<T>(section, key, defaultValue, description);
			Value = val.Value;
		}
	}
}