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 Enabled; internal static ConfigEntry CycleButton; internal static ConfigEntry CycleKey; internal static ConfigEntry DiscoFast; internal static ConfigEntry DiscoSmooth; internal static ConfigEntry 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("ColorCrew", "Enabled", true, "Master switch for the color quick-changer."); CycleButton = ((BaseUnityPlugin)this).Config.Bind("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("ColorCrew", "CycleKey", (KeyCode)99, "Keyboard key that steps to the next color option (handy when testing without a pad)."); DiscoFast = ((BaseUnityPlugin)this).Config.Bind("ColorCrew", "DiscoFastSeconds", 0.08f, "Disco (fast): seconds each color is held before flicking to the next. Lower = faster strobe."); DiscoSmooth = ((BaseUnityPlugin)this).Config.Bind("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("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(name); } catch { return null; } } } } }