Decompiled source of ColorCrew v0.3.0

plugins/ColorCrew.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ColorCrew")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("ColorCrew")]
[assembly: AssemblyTitle("ColorCrew")]
[assembly: AssemblyVersion("0.1.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 ColorCrew
{
	[BepInPlugin("com.hunter.colorcrew", "Color Crew", "0.3.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.hunter.colorcrew";

		public const string Version = "0.3.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<string> CycleButton;

		internal static ConfigEntry<KeyCode> CycleKey;

		internal static ConfigEntry<float> DiscoFast;

		internal static ConfigEntry<float> DiscoSmooth;

		internal static ConfigEntry<float> PoliceSeconds;

		private void Awake()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("ColorCrew", "Enabled", true, "Master switch for the color quick-changer.");
			CycleButton = ((BaseUnityPlugin)this).Config.Bind<string>("ColorCrew", "CycleButton", "leftStickPress", "Controller button that steps to the next color option (default = clicking the left stick, L3). Options: leftStickPress, rightStickPress, select, dpadUp/Down/Left/Right, buttonNorth/South/East/West, leftShoulder, rightShoulder. Empty = off.");
			CycleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("ColorCrew", "CycleKey", (KeyCode)99, "Keyboard key that steps to the next color option (handy when testing without a pad).");
			DiscoFast = ((BaseUnityPlugin)this).Config.Bind<float>("ColorCrew", "DiscoFastSeconds", 0.08f, "Disco (fast): seconds each color is held before flicking to the next. Lower = faster strobe.");
			DiscoSmooth = ((BaseUnityPlugin)this).Config.Bind<float>("ColorCrew", "DiscoSmoothSeconds", 0.6f, "Disco (smooth): seconds each color is held while flowing through the palette in rainbow order. Higher = a lazier gradient sweep.");
			PoliceSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("ColorCrew", "PoliceSeconds", 0.25f, "Police mode: seconds each color is held while flashing between red and blue. Lower = faster flash.");
			ColorChanger.PatchAll(new Harmony("com.hunter.colorcrew"));
			Log.LogInfo((object)(string.Format("Color Crew {0} loaded. Press {1} (or {2}) to cycle ", "0.3.0", CycleButton.Value, CycleKey.Value) + "your color: each palette color, then Disco-Fast, then Disco-Smooth. Everyone (incl. vanilla) sees it."));
		}
	}
	internal static class ColorChanger
	{
		private static Type _netType;

		private static Type _pcmType;

		private static Type _ccType;

		private static MethodInfo _miSetIndex;

		private static FieldInfo _fPcmRef;

		private static FieldInfo _fPlayerColors;

		private static FieldInfo _fCcColor;

		private static FieldInfo _fCcName;

		private static bool _ready;

		private static bool _failed;

		private static int _option;

		private static int _paletteCount = -1;

		private static int[] _hueOrder;

		private static int _redIdx;

		private static int _blueIdx;

		private static int _lastInputFrame = -1;

		private static bool _prevPad;

		private static bool _prevKey;

		internal static void PatchAll(Harmony h)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			Init();
			if (_failed)
			{
				Plugin.Log.LogWarning((object)"Color Crew: required types not found — quick-changer disabled.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(_netType, "OnUpdatePresentationEarly", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				_failed = true;
				Plugin.Log.LogWarning((object)"Color Crew: OnUpdatePresentationEarly not found — disabled.");
			}
			else
			{
				h.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ColorChanger).GetMethod("Pre_ColorEarly", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"Color Crew: patched PlayerColorManagerNetwork.OnUpdatePresentationEarly (per-player color override).");
			}
		}

		private static void Init()
		{
			if (!_ready)
			{
				_ready = true;
				_netType = AccessTools.TypeByName("PlayerColorManagerNetwork");
				_pcmType = AccessTools.TypeByName("PlayerColorManager");
				_ccType = AccessTools.TypeByName("ColorChoice");
				if (_netType != null)
				{
					_miSetIndex = AccessTools.Method(_netType, "set_NetworkactivePlayerColorIndex", (Type[])null, (Type[])null);
					_fPcmRef = AccessTools.Field(_netType, "playerColorManager");
				}
				if (_pcmType != null)
				{
					_fPlayerColors = AccessTools.Field(_pcmType, "playerColors");
				}
				if (_ccType != null)
				{
					_fCcColor = AccessTools.Field(_ccType, "color");
					_fCcName = AccessTools.Field(_ccType, "name");
				}
				_failed = _netType == null || _miSetIndex == null || _fPcmRef == null || _fPlayerColors == null;
			}
		}

		private static bool Pre_ColorEarly(object __instance)
		{
			if (_failed || !Plugin.Enabled.Value)
			{
				return true;
			}
			try
			{
				NetworkBehaviour val = (NetworkBehaviour)((__instance is NetworkBehaviour) ? __instance : null);
				if ((Object)(object)val == (Object)null || !val.isLocalPlayer)
				{
					return true;
				}
				EnsurePalette(__instance);
				int frameCount = Time.frameCount;
				if (frameCount != _lastInputFrame)
				{
					_lastInputFrame = frameCount;
					PollInput();
				}
				if (_option == 0 || _paletteCount <= 0)
				{
					return true;
				}
				int num = ComputeIndex();
				_miSetIndex.Invoke(__instance, new object[1] { num });
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Color Crew: " + ex.Message));
				return true;
			}
		}

		private static void EnsurePalette(object net)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			if (_paletteCount > 0)
			{
				return;
			}
			try
			{
				object value = _fPcmRef.GetValue(net);
				if (value == null || !(_fPlayerColors.GetValue(value) is IList { Count: not 0 } list))
				{
					return;
				}
				_paletteCount = list.Count;
				float[] array = new float[_paletteCount];
				int[] array2 = new int[_paletteCount];
				_redIdx = -1;
				_blueIdx = -1;
				float num = 999f;
				float num2 = 999f;
				for (int i = 0; i < _paletteCount; i++)
				{
					array2[i] = i;
					float num3 = 0f;
					float num4 = 0f;
					float num5 = 0f;
					if (_fCcColor != null && list[i] != null)
					{
						Color.RGBToHSV((Color)_fCcColor.GetValue(list[i]), ref num3, ref num4, ref num5);
					}
					array[i] = ((num4 < 0.05f) ? (10f + num5) : num3);
					string obj = ((_fCcName != null && list[i] != null) ? (_fCcName.GetValue(list[i]) as string) : null);
					if (obj == "Red")
					{
						_redIdx = i;
					}
					if (obj == "Blue")
					{
						_blueIdx = i;
					}
					if (num4 > 0.2f)
					{
						num = Mathf.Min(num, Mathf.Min(num3, 1f - num3));
						num2 = Mathf.Min(num2, Mathf.Abs(num3 - 0.6f));
					}
				}
				if (_redIdx < 0)
				{
					float num6 = default(float);
					float num7 = default(float);
					float num8 = default(float);
					for (int j = 0; j < _paletteCount; j++)
					{
						Color.RGBToHSV((Color)_fCcColor.GetValue(list[j]), ref num6, ref num7, ref num8);
						if (num7 > 0.2f && Mathf.Min(num6, 1f - num6) <= num + 0.0001f)
						{
							_redIdx = j;
							break;
						}
					}
				}
				if (_blueIdx < 0)
				{
					float num9 = default(float);
					float num10 = default(float);
					float num11 = default(float);
					for (int k = 0; k < _paletteCount; k++)
					{
						Color.RGBToHSV((Color)_fCcColor.GetValue(list[k]), ref num9, ref num10, ref num11);
						if (num10 > 0.2f && Mathf.Abs(num9 - 0.6f) <= num2 + 0.0001f)
						{
							_blueIdx = k;
							break;
						}
					}
				}
				if (_redIdx < 0)
				{
					_redIdx = 0;
				}
				if (_blueIdx < 0)
				{
					_blueIdx = ((_paletteCount > 1) ? 1 : 0);
				}
				Array.Sort(array, array2);
				_hueOrder = array2;
				Plugin.Log.LogInfo((object)("Color Crew: palette has " + _paletteCount + " colors (rainbow order resolved; red=" + _redIdx + " blue=" + _blueIdx + ")."));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Color Crew palette: " + ex.Message));
			}
		}

		private static int ComputeIndex()
		{
			if (_option <= _paletteCount)
			{
				return _option - 1;
			}
			if (_option == _paletteCount + 1)
			{
				return (int)(Time.unscaledTime / Mathf.Max(0.01f, Plugin.DiscoFast.Value)) % _paletteCount;
			}
			if (_option == _paletteCount + 2)
			{
				int num = (int)(Time.unscaledTime / Mathf.Max(0.01f, Plugin.DiscoSmooth.Value)) % _paletteCount;
				if (_hueOrder == null)
				{
					return num;
				}
				return _hueOrder[num];
			}
			if ((int)(Time.unscaledTime / Mathf.Max(0.01f, Plugin.PoliceSeconds.Value)) % 2 != 0)
			{
				return _blueIdx;
			}
			return _redIdx;
		}

		private static void PollInput()
		{
			bool num = PadPressed();
			bool flag = KeyPressed();
			if (((num && !_prevPad) || (flag && !_prevKey)) && _paletteCount > 0)
			{
				_option = (_option + 1) % (_paletteCount + 4);
				Plugin.Log.LogInfo((object)("Color Crew: option -> " + OptionName()));
			}
			_prevPad = num;
			_prevKey = flag;
		}

		private static string OptionName()
		{
			if (_option == 0)
			{
				return "Default (your saved color)";
			}
			if (_option <= _paletteCount)
			{
				return "Color " + (_option - 1);
			}
			if (_option == _paletteCount + 1)
			{
				return "Disco (fast)";
			}
			if (_option == _paletteCount + 2)
			{
				return "Disco (smooth rainbow)";
			}
			return "Police (red/blue)";
		}

		private static bool PadPressed()
		{
			Gamepad current = Gamepad.current;
			if (current == null)
			{
				return false;
			}
			ButtonControl val = NamedButton(current, Plugin.CycleButton.Value);
			if (val != null)
			{
				return val.isPressed;
			}
			return false;
		}

		private static bool KeyPressed()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return false;
			}
			try
			{
				KeyControl val = current[(Key)Enum.Parse(typeof(Key), ((object)Plugin.CycleKey.Value/*cast due to .constrained prefix*/).ToString(), ignoreCase: true)];
				return val != null && ((ButtonControl)val).isPressed;
			}
			catch
			{
				return current.cKey != null && ((ButtonControl)current.cKey).isPressed;
			}
		}

		private static ButtonControl NamedButton(Gamepad pad, string name)
		{
			if (pad == null || string.IsNullOrEmpty(name))
			{
				return null;
			}
			switch (name)
			{
			case "leftStickPress":
				return pad.leftStickButton;
			case "rightStickPress":
				return pad.rightStickButton;
			case "select":
				return pad.selectButton;
			case "buttonNorth":
				return pad.buttonNorth;
			case "buttonSouth":
				return pad.buttonSouth;
			case "buttonEast":
				return pad.buttonEast;
			case "buttonWest":
				return pad.buttonWest;
			case "leftShoulder":
				return pad.leftShoulder;
			case "rightShoulder":
				return pad.rightShoulder;
			case "dpadUp":
				if (pad.dpad == null)
				{
					return null;
				}
				return pad.dpad.up;
			case "dpadDown":
				if (pad.dpad == null)
				{
					return null;
				}
				return pad.dpad.down;
			case "dpadLeft":
				if (pad.dpad == null)
				{
					return null;
				}
				return pad.dpad.left;
			case "dpadRight":
				if (pad.dpad == null)
				{
					return null;
				}
				return pad.dpad.right;
			default:
				try
				{
					return ((InputControl)pad).TryGetChildControl<ButtonControl>(name);
				}
				catch
				{
					return null;
				}
			}
		}
	}
}