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;
}
}
}
}
}