Decompiled source of TokenSkulls v1.0.0

TokenSkulls.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
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(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("TokenSkulls")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TokenSkulls")]
[assembly: AssemblyTitle("TokenSkulls")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 TokenSkulls
{
	internal sealed class ConfigUI
	{
		private const float PosRange = 5f;

		private const float RotRange = 180f;

		private const float ScaleMin = 0.05f;

		private const float ScaleMax = 10f;

		private const string IconFile = "icon.png";

		private PluginConfigurator config;

		private BoolField enabledField;

		public Action<bool> OnEnabledChanged;

		public Action OnPlacementChanged;

		public bool IsEnabled => enabledField == null || enabledField.value;

		public void Setup()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			config = PluginConfigurator.Create("Token Skulls", "com.scout.tokenskulls");
			Sprite val = LoadIcon("icon.png");
			if ((Object)(object)val != (Object)null)
			{
				config.image = val;
			}
			enabledField = new BoolField(config.rootPanel, "Enabled", "enabled", true);
			ConfigDivision settings = new ConfigDivision(config.rootPanel, "settings");
			((ConfigField)settings).hidden = !enabledField.value;
			enabledField.onValueChange += (BoolValueChangeEventDelegate)delegate(BoolValueChangeEvent e)
			{
				((ConfigField)settings).hidden = !e.value;
				OnEnabledChanged?.Invoke(e.value);
			};
			ConfigPanel panel = new ConfigPanel((ConfigPanel)(object)settings, "World Skull Placement", "world_settings");
			BuildPlacement(panel, "world", TokenSkullsPlugin.World);
			ConfigPanel panel2 = new ConfigPanel((ConfigPanel)(object)settings, "Held Skull Placement", "held_settings");
			BuildPlacement(panel2, "held", TokenSkullsPlugin.Held);
		}

		private Sprite LoadIcon(string fileName)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
			if (!File.Exists(path))
			{
				TokenSkullsPlugin.Log.LogWarning((object)"No icon which how???");
				return null;
			}
			byte[] array = File.ReadAllBytes(path);
			Texture2D val = new Texture2D(2, 2);
			ImageConversion.LoadImage(val, array);
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}

		private void BuildPlacement(ConfigPanel panel, string prefix, TokenSkullsPlugin.Placement p)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			new ConfigHeader(panel, "Position Offset", 20);
			Slider(panel, "Position X", prefix + "_pos_x", p.posX, -5f, 5f, 2, delegate(float v)
			{
				p.posX = v;
			});
			Slider(panel, "Position Y", prefix + "_pos_y", p.posY, -5f, 5f, 2, delegate(float v)
			{
				p.posY = v;
			});
			Slider(panel, "Position Z", prefix + "_pos_z", p.posZ, -5f, 5f, 2, delegate(float v)
			{
				p.posZ = v;
			});
			new ConfigHeader(panel, "Rotation Offset", 20);
			Slider(panel, "Rotation X", prefix + "_rot_x", p.rotX, -180f, 180f, 1, delegate(float v)
			{
				p.rotX = v;
			});
			Slider(panel, "Rotation Y", prefix + "_rot_y", p.rotY, -180f, 180f, 1, delegate(float v)
			{
				p.rotY = v;
			});
			Slider(panel, "Rotation Z", prefix + "_rot_z", p.rotZ, -180f, 180f, 1, delegate(float v)
			{
				p.rotZ = v;
			});
			new ConfigHeader(panel, "Size Multiplier", 20);
			Slider(panel, "Scale", prefix + "_scale", p.scale, 0.05f, 10f, 2, delegate(float v)
			{
				p.scale = v;
			});
		}

		private void Slider(ConfigPanel panel, string label, string guid, float def, float min, float max, int decimals, Action<float> apply)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			FloatSliderField val = new FloatSliderField(panel, label, guid, new Tuple<float, float>(min, max), def, decimals);
			val.onValueChange += (OnValueChangeEventDelegate)delegate(FloatSliderValueChangeEvent e)
			{
				apply(e.newValue);
				OnPlacementChanged?.Invoke();
			};
			apply(val.value);
		}
	}
	[BepInPlugin("com.scout.tokenskulls", "Token Skulls", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class TokenSkullsPlugin : BaseUnityPlugin
	{
		private class Variant
		{
			public GameObject prefab;

			public Vector3 pos;

			public Quaternion rot;

			public Vector3 scale;
		}

		public class Placement
		{
			public float posX;

			public float posY;

			public float posZ;

			public float rotX;

			public float rotY;

			public float rotZ;

			public float scale = 1f;

			public Vector3 PosOffset => new Vector3(posX, posY, posZ);

			public Vector3 RotOffset => new Vector3(rotX, rotY, rotZ);
		}

		private class SkullTag : MonoBehaviour
		{
			public Transform clone;

			public Renderer hidden;

			public Variant variant;

			public bool wasHeld;
		}

		public const string GUID = "com.scout.tokenskulls";

		public const string NAME = "Token Skulls";

		public const string VERSION = "1.0.0";

		private const string BundleFile = "tokenskulls.bundle";

		private const string PrefabRed = "TokenSkullRed";

		private const string PrefabBlue = "TokenSkullBlue";

		private const string PrefabSingle = "TokenSkull";

		public static readonly Placement World = new Placement();

		public static readonly Placement Held = new Placement();

		private static Variant redVariant;

		private static Variant blueVariant;

		private static bool modelReady;

		private static bool placementDirty;

		private static bool warnedNoAnchor;

		private static readonly List<SkullTag> live = new List<SkullTag>();

		private static ConfigUI ui;

		internal static ManualLogSource Log;

		private Harmony harmony;

		private static bool IsEnabled => ui != null && ui.IsEnabled;

		private void Awake()
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ui = new ConfigUI();
			ui.Setup();
			ui.OnEnabledChanged = OnEnabledToggled;
			ui.OnPlacementChanged = delegate
			{
				placementDirty = true;
			};
			LoadModel();
			if (!modelReady)
			{
				Log.LogError((object)"Model never loaded");
				return;
			}
			try
			{
				harmony = new Harmony("com.scout.tokenskulls");
				harmony.PatchAll();
				Log.LogInfo((object)"Patched Skull.Awake");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Harmony patch failed: {arg}");
			}
		}

		private Variant TryLoad(AssetBundle bundle, string name)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = bundle.LoadAsset<GameObject>(name);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			if (val.GetComponentsInChildren<Renderer>(true).Length == 0)
			{
				Log.LogWarning((object)(name + " has no renderers anywhere"));
				return null;
			}
			return new Variant
			{
				prefab = val,
				pos = val.transform.localPosition,
				rot = val.transform.localRotation,
				scale = val.transform.localScale
			};
		}

		private void LoadModel()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = Path.Combine(directoryName, "tokenskulls.bundle");
			if (!File.Exists(text))
			{
				Log.LogError((object)("Bundle missing in " + text));
				return;
			}
			AssetBundle val = AssetBundle.LoadFromFile(text);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)"Bundle failed to load");
				return;
			}
			redVariant = TryLoad(val, "TokenSkullRed");
			blueVariant = TryLoad(val, "TokenSkullBlue");
			Variant variant = TryLoad(val, "TokenSkull");
			if (redVariant == null)
			{
				redVariant = variant ?? blueVariant;
			}
			if (blueVariant == null)
			{
				blueVariant = variant ?? redVariant;
			}
			if (redVariant == null || blueVariant == null)
			{
				Log.LogError((object)("No prefabs, need TokenSkullRed and TokenSkullBlue. Bundle only has: " + string.Join(", ", val.GetAllAssetNames())));
				return;
			}
			if ((Object)(object)redVariant.prefab == (Object)(object)blueVariant.prefab)
			{
				Log.LogWarning((object)"Only one prefab found, add TokenSkullRed and TokenSkullBlue");
			}
			modelReady = true;
			Log.LogInfo((object)("Loaded " + ((Object)redVariant.prefab).name + " and " + ((Object)blueVariant.prefab).name));
		}

		internal static void OnSkullAwake(Skull skull)
		{
			if (modelReady && IsEnabled && Object.op_Implicit((Object)(object)skull))
			{
				Dress(skull);
			}
		}

		private static void Dress(Skull skull)
		{
			Transform val = ((IEnumerable<Transform>)((Component)skull).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "NewSkull"));
			if (!Object.op_Implicit((Object)(object)val))
			{
				if (!warnedNoAnchor)
				{
					warnedNoAnchor = true;
					Log.LogWarning((object)(((Object)skull).name + " has no NewSkull child"));
				}
			}
			else if (!Object.op_Implicit((Object)(object)((Component)val).GetComponent<SkullTag>()))
			{
				Variant variant = (((Object)skull).name.ToLower().Contains("red") ? redVariant : blueVariant);
				SkullTag skullTag = ((Component)val).gameObject.AddComponent<SkullTag>();
				skullTag.variant = variant;
				skullTag.hidden = ((Component)val).GetComponent<Renderer>();
				if (Object.op_Implicit((Object)(object)skullTag.hidden))
				{
					skullTag.hidden.enabled = false;
				}
				GameObject val2 = Object.Instantiate<GameObject>(variant.prefab, val, false);
				((Object)val2).name = "TokenSkullModel";
				skullTag.clone = val2.transform;
				live.Add(skullTag);
				Place(skullTag, force: true);
			}
		}

		private static void Place(SkullTag tag, bool force)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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)
			//IL_0083: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			bool flag = ((Object)((Component)tag).transform.root).name == "Player";
			if (force || flag != tag.wasHeld)
			{
				tag.wasHeld = flag;
				Placement placement = (flag ? Held : World);
				Variant variant = tag.variant;
				Transform clone = tag.clone;
				clone.localPosition = variant.pos + placement.PosOffset;
				clone.localRotation = variant.rot * Quaternion.Euler(placement.RotOffset);
				clone.localScale = variant.scale * placement.scale;
			}
		}

		private void Update()
		{
			if (live.Count == 0)
			{
				placementDirty = false;
				return;
			}
			bool force = placementDirty;
			for (int num = live.Count - 1; num >= 0; num--)
			{
				SkullTag skullTag = live[num];
				if (!Object.op_Implicit((Object)(object)skullTag) || !Object.op_Implicit((Object)(object)skullTag.clone))
				{
					live.RemoveAt(num);
				}
				else
				{
					if (Object.op_Implicit((Object)(object)skullTag.hidden) && skullTag.hidden.enabled)
					{
						skullTag.hidden.enabled = false;
					}
					Place(skullTag, force);
				}
			}
			placementDirty = false;
		}

		private static void OnEnabledToggled(bool on)
		{
			if (!modelReady)
			{
				return;
			}
			if (on)
			{
				Skull[] array = Object.FindObjectsOfType<Skull>();
				foreach (Skull val in array)
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						Dress(val);
					}
				}
			}
			else
			{
				RestoreAll();
			}
		}

		private static void RestoreAll()
		{
			foreach (SkullTag item in live)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					if (Object.op_Implicit((Object)(object)item.clone))
					{
						Object.Destroy((Object)(object)((Component)item.clone).gameObject);
					}
					if (Object.op_Implicit((Object)(object)item.hidden))
					{
						item.hidden.enabled = true;
					}
					Object.Destroy((Object)(object)item);
				}
			}
			live.Clear();
		}
	}
	[HarmonyPatch(typeof(Skull), "Awake")]
	internal static class SkullAwakePatch
	{
		private static void Postfix(Skull __instance)
		{
			TokenSkullsPlugin.OnSkullAwake(__instance);
		}
	}
}