Decompiled source of SlabPlugin CCM v2.0.3

SlabPlugin_CCM.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Bounce.Singletons;
using DataModel;
using HarmonyLib;
using ModP.B64;
using ModdingTales;
using Newtonsoft.Json;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("SlabPlugin_CCM")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Nth Dimension")]
[assembly: AssemblyProduct("SlabPlugin_CCM")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("SlabPlugin_CCM")]
[assembly: ComVisible(false)]
[assembly: Guid("c303405d-e66c-4316-9cdb-4e3ca15c6360")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("2.1.0.0")]
namespace LordAshes;

[BepInPlugin("org.lordashes.plugins.slab.ccm", "Slab Plugin", "2.1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SlabPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(CreatureBoardAsset), "OnBaseLoaded")]
	public static class PatcheCreaturePresenterOnCreatureAdded
	{
		public static void Postfix(CreatureBoardAsset __instance)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			LoggingPlugin.LogInfo("Link=" + ((__instance.Link != null) ? __instance.Link : "Null"));
			if (__instance.Link != null && __instance.Link.Contains("TYPE@SLAB"))
			{
				LoggingPlugin.LogInfo("Building MultiSlab");
				Provider.multiSlab.dropX = ((Component)__instance).gameObject.transform.position.x;
				Provider.multiSlab.dropY = ((Component)__instance).gameObject.transform.position.y;
				Provider.multiSlab.dropZ = ((Component)__instance).gameObject.transform.position.z;
				CreatureManager.DeleteCreature(__instance.CreatureId, __instance.UniqueId, true);
				((MonoBehaviour)_self).StartCoroutine(BuildMultipleSlabs(Provider.multiSlab, 0.5f));
			}
		}
	}

	public static class Provider
	{
		public class SlabInfo
		{
			public string code { get; set; }

			public float offsetX { get; set; }

			public float offsetY { get; set; }

			public float offsetZ { get; set; }
		}

		public class MultiSlab
		{
			public bool autoDrop = false;

			public float dropX = 0f;

			public float dropY = 0f;

			public float dropZ = 0f;

			public List<SlabInfo> slabs = new List<SlabInfo>();
		}

		public static MultiSlab multiSlab;

		public static IEnumerator GetSlabAssets(ReadOnlyDictionary<string, AssetInfo> existingAssets, Func<Dictionary<string, AssetInfo>, IEnumerator> callback)
		{
			LoggingPlugin.LogInfo("Loading Icons");
			byte[] imageBytes = ImageConversion.EncodeToPNG(Image.LoadTexture("Kind.Slab.png", (CacheType)999));
			LoggingPlugin.LogInfo("Collecting slab files");
			string[] slabFiles = (from file in File.Catalog(false)
				where file.ToUpper().EndsWith(".SLAB")
				select file).ToArray();
			LoggingPlugin.LogInfo("Found " + slabFiles.Length + " Potential Slab Assets. Aware Of " + existingAssets.Count + " Registered Assets.");
			Dictionary<string, AssetInfo> assets = new Dictionary<string, AssetInfo>();
			LoggingPlugin.LogInfo("Building Slab Files Items");
			string[] array = slabFiles;
			foreach (string slabFile in array)
			{
				yield return (object)new WaitForEndOfFrame();
				string slabSource = File.Find(slabFile, (CacheType)999).ElementAt(0);
				string prefab = Path.GetFileNameWithoutExtension(slabFile);
				string group = Path.GetFileNameWithoutExtension(Path.GetDirectoryName(slabFile));
				string header = Path.GetFileNameWithoutExtension(Path.GetDirectoryName(Path.GetDirectoryName(slabFile)));
				if (header.ToUpper() == "CUSTOMDATA")
				{
					header = "GENERAL";
				}
				string kind = "SLAB";
				string pack2 = slabSource.Substring(Paths.PluginPath.Length + 1);
				pack2 = pack2.Substring(0, pack2.IndexOf("/", 1));
				LoggingPlugin.LogTrace("Found Asset (Kind: Slab, Category: " + kind + ", Header: " + header + ", Group: " + group + ", Pack: " + pack2 + ", Name: " + insertSpaces(prefab) + ", Prefab: " + prefab + ", File: " + slabSource + ")");
				if (!existingAssets.ContainsKey(prefab) && !assets.ContainsKey(prefab))
				{
					_self.notification = "Registering... [Provider: Slab, Pack: " + group + ", Item: " + prefab + "]";
					assets.Add(prefab.Replace(" ", ""), new AssetInfo
					{
						provider = "SLAB",
						pack = pack2,
						kind = kind,
						category = kind,
						header = header,
						groupName = group,
						name = insertSpaces(prefab),
						prefab = prefab.Replace(" ", ""),
						filename = slabFile
					});
					if (File.Exists(slabFile.Substring(0, slabFile.Length - 5) + ".png"))
					{
						File.WriteAllBytes(Paths.PluginPath + "/.cache/org.lordashes.plugins.commoncustomsmenu/Portrait." + prefab.Replace(" ", "") + ".png", ImageConversion.EncodeToPNG(Image.LoadTexture(slabFile.Substring(0, slabFile.Length - 5) + ".png", (CacheType)999)), (CacheType)999);
					}
					else
					{
						File.WriteAllBytes(Paths.PluginPath + "/.cache/org.lordashes.plugins.commoncustomsmenu/Portrait." + prefab.Replace(" ", "") + ".png", imageBytes, (CacheType)999);
					}
				}
			}
			_self.notification = null;
			((MonoBehaviour)_self).StartCoroutine(callback((from kvp in assets
				orderby kvp.Value.header, kvp.Value.category, kvp.Value.name
				select kvp).ToDictionary((KeyValuePair<string, AssetInfo> kvp) => kvp.Key, (KeyValuePair<string, AssetInfo> kvp) => kvp.Value)));
		}

		public static void SlabRequest(AssetInfo assetInfo)
		{
			if (Utility.isBoardLoaded())
			{
				LoggingPlugin.LogInfo("Requesting Slab '" + assetInfo.prefab + "'");
				string text = File.ReadAllText(assetInfo.filename, (CacheType)999);
				multiSlab = JsonConvert.DeserializeObject<MultiSlab>(text);
				if (multiSlab.autoDrop)
				{
					((MonoBehaviour)_self).StartCoroutine(BuildMultipleSlabs(multiSlab, 0.5f));
					return;
				}
				CommonCustomsMenuPlugin._self.Close();
				SpawnBluePrintWithNameAndLink("Slab", "TYPE@SLAB");
			}
			else
			{
				SystemMessage.DisplayInfoText("Slab Can Only Be Added\r\nWhen A Board Is Loaded", 2.5f, 0f);
			}
		}

		public static void SpawnBluePrintWithNameAndLink(string name, string link, string blueprintStr = "AgD_AQAAACMAYnI6MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwNzgxYTQwMDABAAAAAH6XEcbunFtBuDQeom6jhAwABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAA")
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			CreatureDataV3 creatureDataFromBlueprint = GetCreatureDataFromBlueprint(blueprintStr);
			creatureDataFromBlueprint.Alias = name;
			creatureDataFromBlueprint.Link = link;
			CreatureSpawnerBoardTool.SwitchCreatureTool(ref creatureDataFromBlueprint, false, false);
		}

		public static CreatureDataV3 GetCreatureDataFromBlueprint(string blueprintStr)
		{
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_0036: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				blueprintStr = blueprintStr.Replace('_', '/');
				NativeList<byte> val = default(NativeList<byte>);
				val..ctor(1024, AllocatorHandle.op_Implicit((Allocator)2));
				try
				{
					if (Base64.TryDecodeInto(blueprintStr, val))
					{
						Reader val2 = new Reader();
						val2.Reset(NativeList<byte>.op_Implicit(val), 0);
						ushort num = default(ushort);
						val2.Read<ushort>(ref num);
						switch (num)
						{
						default:
							Debug.Log((object)"InvalidFormat");
							return default(CreatureDataV3);
						case 2:
						{
							CreatureBlueprintDataV1 val4 = CreatureBlueprintDataV1.Deserialize(val2);
							CreatureDataV3 result2 = val4.ToCreatureDataV3InterningPackUris();
							Debug.Log((object)"Success(1)");
							return result2;
						}
						case 1:
						{
							CreatureBlueprintDataV0 val3 = CreatureBlueprintDataV0.Deserialize(val2);
							CreatureDataV3 result = val3.ToCreatureDataV3();
							Debug.Log((object)"Success(2)");
							return result;
						}
						}
					}
					Debug.Log((object)"InvalidBase64");
					return default(CreatureDataV3);
				}
				finally
				{
					((IDisposable)val).Dispose();
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				return default(CreatureDataV3);
			}
		}

		private static string insertSpaces(string camelCase)
		{
			string text = camelCase.Substring(0, 1);
			for (int i = 1; i < camelCase.Length; i++)
			{
				if (camelCase.Substring(i - 1, 1) == camelCase.Substring(i - 1, 1).ToLower() && camelCase.Substring(i, 1) == camelCase.Substring(i - 1, 1).ToUpper() && camelCase.Substring(i, 1).ToLower() != camelCase.Substring(i - 1, 1).ToUpper())
				{
					text += " ";
				}
				text += camelCase.Substring(i, 1);
			}
			return text;
		}
	}

	public static class Utility
	{
		public static bool isBoardLoaded()
		{
			return SimpleSingletonBehaviour<CameraController>.HasInstance && SingletonStateMBehaviour<BoardSessionManager, State<BoardSessionManager>>.HasInstance && !BoardSessionManager.IsLoading;
		}

		public static float ParseFloat(string value)
		{
			return float.Parse(value, CultureInfo.InvariantCulture);
		}

		public static GameObject FindInHierarchy(GameObject start, string seekName)
		{
			List<GameObject> results = new List<GameObject>();
			bool done = false;
			Traverse(start.transform, seekName, null, single: true, ref results, ref done);
			return (results.Count > 0) ? results.ElementAt(0) : null;
		}

		public static GameObject FindInHierarchyViaPartialName(GameObject start, string seekName)
		{
			List<GameObject> results = new List<GameObject>();
			bool done = false;
			Traverse(start.transform, seekName, null, single: true, ref results, ref done, partial: true);
			return (results.Count > 0) ? results.ElementAt(0) : null;
		}

		public static GameObject[] FindAllInHierarchy(GameObject start, string seekName)
		{
			List<GameObject> results = new List<GameObject>();
			bool done = false;
			Traverse(start.transform, seekName, null, single: false, ref results, ref done);
			return results.ToArray();
		}

		public static GameObject[] FindAllInHierarchyViaPartialName(GameObject start, string seekName)
		{
			List<GameObject> results = new List<GameObject>();
			bool done = false;
			Traverse(start.transform, seekName, null, single: false, ref results, ref done, partial: true);
			return results.ToArray();
		}

		public static GameObject FindWithComponentInHierarchy(GameObject start, string seekType)
		{
			List<GameObject> results = new List<GameObject>();
			bool done = false;
			Traverse(start.transform, null, seekType, single: true, ref results, ref done);
			return (results.Count > 0) ? results.ElementAt(0) : null;
		}

		public static GameObject[] FindAllWithComponentInHierarchy<T>(GameObject start, string seekType)
		{
			List<GameObject> results = new List<GameObject>();
			bool done = false;
			Traverse(start.transform, null, seekType, single: false, ref results, ref done);
			return results.ToArray();
		}

		public static void Traverse(Transform root, string seekName, string seekType, bool single, ref List<GameObject> results, ref bool done, bool partial = false)
		{
			try
			{
				if ((seekName == null || seekName == ((Object)((Component)root).gameObject).name || (partial && ((Object)((Component)root).gameObject).name.Contains(seekName))) && (seekType == null || (Object)(object)((Component)root).GetComponent(seekType) != (Object)null))
				{
					LoggingPlugin.LogTrace("Matched '" + ((Object)((Component)root).gameObject).name + "'");
					results.Add(((Component)root).gameObject);
					if (single)
					{
						done = true;
						return;
					}
				}
				foreach (Transform item in ExtensionMethods.Children(root))
				{
					if (!done)
					{
						Traverse(item, seekName, seekType, single, ref results, ref done, partial);
					}
				}
			}
			catch
			{
			}
		}

		public static object LookUp(in Dictionary<string, object> dictionary, string key)
		{
			foreach (KeyValuePair<string, object> item in dictionary)
			{
				if (item.Key.ToUpper() == key.ToUpper())
				{
					return item.Value;
				}
			}
			return null;
		}

		public static void PostOnMainPage(BaseUnityPlugin plugin)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			string text = "Lord Ashes" + ("Lord Ashes".ToUpper().EndsWith("S") ? "'" : "'s");
			ModdingUtils.Initialize(plugin, new ManualLogSource("Slab Plugin"), text, false);
		}
	}

	public const string Name = "Slab Plugin";

	public const string Guid = "org.lordashes.plugins.slab.ccm";

	public const string Version = "2.1.0.0";

	public const string Author = "Lord Ashes";

	public static SlabPlugin _self;

	private string notification = null;

	private Rect registrationMessagePos = Rect.zero;

	private GUIStyle registrationMessageStyle = new GUIStyle();

	public static IEnumerator BuildMultipleSlabs(Provider.MultiSlab multiSlab, float delay)
	{
		LoggingPlugin.LogTrace(JsonConvert.SerializeObject((object)multiSlab));
		int slabCount = 0;
		foreach (Provider.SlabInfo slab in multiSlab.slabs)
		{
			slabCount++;
			Copied copied = null;
			if ((int)BoardSessionManager.Board.PushStringToTsClipboard(slab.code, ref copied) == 0)
			{
				Copied mostRecentCopied_LocalOnly = BoardSessionManager.Board.GetMostRecentCopied_LocalOnly();
				if (mostRecentCopied_LocalOnly != null)
				{
					BoardSessionManager.Board.PasteCopied(float3.op_Implicit(new Vector3(multiSlab.dropX + slab.offsetX, multiSlab.dropY + slab.offsetY, multiSlab.dropZ + slab.offsetZ)), (byte)0, 0uL);
					yield return (object)new WaitForSeconds(delay);
				}
				else
				{
					Debug.Log((object)("Multi Paste Slabs Plugin: Unable To Process Slab " + slabCount));
				}
			}
			else
			{
				Debug.Log((object)("Multi Paste Slabs Plugin: Unable To Push Slab Code For Slab " + slabCount + " To TS Clipboard"));
			}
		}
		Provider.multiSlab = null;
		CancelSpawnTool();
	}

	public static void CancelSpawnTool()
	{
		try
		{
			Type type = Type.GetType("BoardToolManager, Bouncyrock.TaleSpire.Runtime");
			if (type == null)
			{
				LoggingPlugin.LogWarning("BoardToolManager type not found.");
				return;
			}
			Type type2 = typeof(SingletonBehaviour<>).MakeGenericType(type);
			object obj = type2.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
			if (obj == null)
			{
				LoggingPlugin.LogWarning("BoardToolManager instance not found.");
				return;
			}
			Type type3 = Type.GetType("CreatureSpawnerBoardTool, Bouncyrock.TaleSpire.Runtime");
			if (type3 == null)
			{
				LoggingPlugin.LogWarning("CreatureSpawnerBoardTool type not found.");
				return;
			}
			Type type4 = Type.GetType("DefaultBoardTool, Bouncyrock.TaleSpire.Runtime");
			if (type4 == null)
			{
				LoggingPlugin.LogWarning("DefaultBoardTool type not found.");
				return;
			}
			object obj2 = type.GetProperty("CurrentTool", BindingFlags.Instance | BindingFlags.Public)?.GetValue(obj);
			if (obj2 != null && obj2.GetType() == type3)
			{
				LoggingPlugin.LogWarning("Current tool is not CreatureSpawnerBoardTool.");
				return;
			}
			MethodInfo methodInfo = type.GetMethods().FirstOrDefault((MethodInfo m) => m.Name == "SwitchToTool" && m.IsGenericMethod);
			if (methodInfo == null)
			{
				LoggingPlugin.LogWarning("SwitchToTool method not found.");
				return;
			}
			MethodInfo methodInfo2 = methodInfo.MakeGenericMethod(type4);
			object[] parameters = new object[1] { Enum.Parse(Type.GetType("BoardToolManager+Type, Bouncyrock.TaleSpire.Runtime"), "Normal") };
			methodInfo2.Invoke(obj, parameters);
		}
		catch (Exception ex)
		{
			LoggingPlugin.LogWarning("Exception calling SwitchToTool: " + ex.Message);
		}
	}

	private void Awake()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Invalid comparison between Unknown and I4
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Expected O, but got Unknown
		_self = this;
		LoggingPlugin.SetLogLevel(((BaseUnityPlugin)this).Config.Bind<DiagnosticLevel>("Settings", "Diagnostic Level", (DiagnosticLevel)3, (ConfigDescription)null).Value);
		string? assemblyQualifiedName = ((object)this).GetType().AssemblyQualifiedName;
		DiagnosticLevel logLevel = LoggingPlugin.GetLogLevel();
		Debug.Log((object)(assemblyQualifiedName + ": Active. (Diagnostic Mode = " + ((object)(DiagnosticLevel)(ref logLevel)).ToString() + ")"));
		if ((int)LoggingPlugin.GetLogLevel() >= 4)
		{
			((MonoBehaviour)this).StartCoroutine(WarnAboutLogLevel());
		}
		string text = CommonCustomsMenuPlugin.RegisterProviderV2("SLAB", "Slabs and multislabs", "2.1.0.0", (Func<ReadOnlyDictionary<string, AssetInfo>, Func<Dictionary<string, AssetInfo>, IEnumerator>, IEnumerator>)Provider.GetSlabAssets, (Action<AssetInfo>)delegate(AssetInfo selectedAsset)
		{
			Provider.SlabRequest(selectedAsset);
		});
		string[] array = text.Split(new char[1] { ',' });
		registrationMessagePos = new Rect((float)int.Parse(array[0]), (float)int.Parse(array[1]), (float)(Screen.width - int.Parse(array[0])), (float)(Screen.height - int.Parse(array[1])));
		registrationMessageStyle.fontSize = int.Parse(array[2]);
		registrationMessageStyle.fontStyle = (FontStyle)1;
		registrationMessageStyle.active.textColor = Color.white;
		registrationMessageStyle.normal.textColor = Color.white;
		Harmony val = new Harmony("org.lordashes.plugins.slab.ccm");
		val.PatchAll();
		Utility.PostOnMainPage((BaseUnityPlugin)(object)this);
	}

	private void OnGUI()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (notification != null)
		{
			GUI.Label(registrationMessagePos, notification, registrationMessageStyle);
		}
	}

	private IEnumerator WarnAboutLogLevel()
	{
		while (true)
		{
			try
			{
				DiagnosticLevel logLevel = LoggingPlugin.GetLogLevel();
				SystemMessage.DisplayInfoText("Slab Plugin: Using '" + ((object)(DiagnosticLevel)(ref logLevel)).ToString() + "' diagnostics.\r\nUse 'Info' for better performance", 10f, 0f);
				SystemMessage.DisplayInfoText("Slab Plugin: Use 'Debug' or 'Trace' for\r\ntroubleshooting only.", 10f, 0f);
				break;
			}
			catch
			{
			}
			yield return (object)new WaitForSeconds(1f);
		}
	}
}