Decompiled source of PartialPrints v0.4.3

m75partialprints.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Text;
using Microsoft.CodeAnalysis;
using SOD.Common;
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.4.0.0")]
[assembly: AssemblyInformationalVersion("0.4.0")]
[assembly: AssemblyProduct("m75partialprints")]
[assembly: AssemblyTitle("m75partialprints")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.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.4.0";
	}
}
namespace partialprints
{
	[BepInPlugin("m75partialprints", "m75partialprints", "0.4.0")]
	public class PartialPrints : BasePlugin
	{
		private static ConfigEntryCache<int> ConfigCodeLength;

		private static ConfigEntryCache<int> ConfigLettersPerDigit;

		private static ConfigEntryCache<int> ConfigSmudgeMin;

		private static ConfigEntryCache<int> ConfigSmudgeMax;

		public static ConfigEntryCache<BelongsToMode> ConfigBelongsToMode;

		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()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			InitializeConfig();
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(18, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("m75partialprints");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!");
			}
			log.LogInfo(val);
			Harmony val2 = new Harmony("m75partialprints");
			val2.PatchAll();
			Lib.SaveGame.OnAfterLoad -= OnAfterLoad;
			Lib.SaveGame.OnAfterLoad += OnAfterLoad;
			InitializeStructures();
		}

		public override bool Unload()
		{
			Lib.SaveGame.OnAfterLoad -= OnAfterLoad;
			return ((BasePlugin)this).Unload();
		}

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

		private void InitializeConfig()
		{
			ConfigCodeLength = new ConfigEntryCache<int>(((BasePlugin)this).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>(((BasePlugin)this).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>(((BasePlugin)this).Config, "General", "Minimum Smudge Amount", 2, "The minimum amount of \"smudged\" letters on partial fingerprints");
			ConfigSmudgeMax = new ConfigEntryCache<int>(((BasePlugin)this).Config, "General", "Maximum Smudge Amount", 4, "The maximum amount of \"smudged\" letters on partial fingerprints");
			ConfigBelongsToMode = new ConfigEntryCache<BelongsToMode>(((BasePlugin)this).Config, "General", "Belongs To Mode", BelongsToMode.Hidden, "Determines what is done with the \"belongs to\" line on partial fingerprint notes.\n1. Hidden: The line is not shown at all. (Default)\n2. Obscured: The line is shown, but hides the person even if you know their print.\n3. Shown: If you know a person's full print, they will be shown on partial prints.");
			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 ReinitializePostLoad()
		{
			_fullPrintCache.Clear();
			_citySeedCache = GetDeterministicStringHash(CityData.Instance.seed);
		}

		private static uint GetDeterministicStringHash(string s)
		{
			uint num = 352654597u;
			uint num2 = num;
			for (int i = 0; i < s.Length; i += 2)
			{
				num = ((num << 5) + num) ^ s[i];
				if (i == s.Length - 1)
				{
					break;
				}
				num2 = ((num2 << 5) + num2) ^ s[i + 1];
			}
			return num + num2 * 1566083941;
		}

		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(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(Strings.Get("descriptors", "Type", (Casing)1, false, false, false, (Human)null));
			_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));
			}
			else
			{
				_noteBuilder.Append(Strings.Get("descriptors", "?", (Casing)0, false, false, false, (Human)null));
			}
			_noteBuilder.Append("</font>");
			switch (PartialPrints.ConfigBelongsToMode.Value)
			{
			case BelongsToMode.Shown:
				_noteBuilder.Append(Environment.NewLine);
				_noteBuilder.Append("<sprite=\"icons\" name=\"Checkbox Empty\">");
				_noteBuilder.Append(Strings.Get("descriptors", "Belongs To", (Casing)1, false, false, false, (Human)null));
				_noteBuilder.Append(": ");
				_noteBuilder.Append("<font=\"PapaManAOE SDF\">");
				_noteBuilder.Append(tiedKeys.Contains((DataKey)0) ? "|name|" : Strings.Get("descriptors", "?", (Casing)0, false, false, false, (Human)null));
				_noteBuilder.Append("</font>");
				break;
			case BelongsToMode.Obscured:
				_noteBuilder.Append(Environment.NewLine);
				_noteBuilder.Append("<sprite=\"icons\" name=\"Checkbox Empty\">");
				_noteBuilder.Append(Strings.Get("descriptors", "Belongs To", (Casing)1, false, false, false, (Human)null));
				_noteBuilder.Append(": ");
				_noteBuilder.Append("<font=\"PapaManAOE SDF\">");
				_noteBuilder.Append(Strings.Get("descriptors", "?", (Casing)0, false, false, false, (Human)null));
				_noteBuilder.Append("</font>");
				break;
			}
			__result = ((Object)_noteBuilder).ToString();
			return false;
		}
	}
	[HarmonyPatch(typeof(EvidenceFingerprint), "GetNameForDataKey")]
	public class M75GetNameForDataKeyPatch
	{
		public static string Postfix(string __result, EvidenceFingerprint __instance, List<DataKey> inputKeys)
		{
			if (((Evidence)__instance).customNames.Count <= 0 && inputKeys != null)
			{
				return "ID: " + PartialPrints.GetPrintPartial((uint)((Evidence)__instance).writer.humanID, ((Evidence)__instance).evID);
			}
			return __result;
		}
	}
	[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 = Strings.Get("evidence.generic", "Type", (Casing)1, false, false, false, (Human)null) + " " + 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;
		}
	}
	public enum BelongsToMode
	{
		Hidden,
		Obscured,
		Shown
	}
}