using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DynamicRepoGrabBeam.ColorLogic; using DynamicRepoGrabBeam.Patches; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("DynamicRepoGrabBeam")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6889657beff0cf2372a6596cd72fce66319da01b")] [assembly: AssemblyProduct("DynamicRepoGrabBeam")] [assembly: AssemblyTitle("DynamicRepoGrabBeam")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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; } } } [BepInPlugin("com.repo.DynamicRepoGrabBeam", "Grab Beam Mod", "1.0.0")] public class Plugin : BaseUnityPlugin { public static Plugin Instance; public static ConfigEntry LightMax; public static ConfigEntry HeavyMin; public static ConfigEntry LightColor; public static ConfigEntry MediumColor; public static ConfigEntry HeavyColor; public static ConfigEntry PlayerGrabColor; public static ConfigEntry RotationModeColor; public static ConfigEntry MaxStunVisualForce; public static ConfigEntry ForceSaturationScale; public static ConfigEntry ForceBrightnessScale; public static ConfigEntry ForceAlphaScale; public static ConfigEntry EnableDebugLogs; public static ManualLogSource Log { get { Plugin instance = Instance; if (instance == null) { return null; } return ((BaseUnityPlugin)instance).Logger; } } private void Awake() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) Instance = this; BeamColorManager.Initialize(); LightMax = ((BaseUnityPlugin)this).Config.Bind("Weight Thresholds", "LightMax", 2f, "Max mass for light objects"); HeavyMin = ((BaseUnityPlugin)this).Config.Bind("Weight Thresholds", "HeavyMin", 3f, "Min mass for heavy objects"); LightColor = ((BaseUnityPlugin)this).Config.Bind("Colors", "LightWeight", new Color(0f, 1f, 0f, 0.5f), "Beam color for light objects (50% opacity)"); MediumColor = ((BaseUnityPlugin)this).Config.Bind("Colors", "MediumWeight", new Color(1f, 1f, 0f, 0.5f), "Beam color for medium objects (50% opacity)"); HeavyColor = ((BaseUnityPlugin)this).Config.Bind("Colors", "HeavyWeight", new Color(1f, 0f, 0f, 0.5f), "Beam color for heavy objects (50% opacity)"); PlayerGrabColor = ((BaseUnityPlugin)this).Config.Bind("Colors", "PlayerGrabBeam", new Color(0f, 1f, 1f, 0.5f), "Beam color when grabbing another player (50% opacity)"); RotationModeColor = ((BaseUnityPlugin)this).Config.Bind("Colors", "RotationModeBeam", new Color(1f, 0.5f, 1f, 0.5f), "Beam color override while rotating (used instead of default purple)"); MaxStunVisualForce = ((BaseUnityPlugin)this).Config.Bind("Force", "MaxStunVisualForce", 15f, "Force value that causes full saturation intensity"); ForceSaturationScale = ((BaseUnityPlugin)this).Config.Bind("Force", "SaturationScale", 0.2f, "How much saturation increases with normalized impact force"); ForceBrightnessScale = ((BaseUnityPlugin)this).Config.Bind("Force", "BrightnessScale", 0.03f, "How much brightness increases with normalized impact force"); ForceAlphaScale = ((BaseUnityPlugin)this).Config.Bind("Force", "AlphaScale", 0.3f, "How much transparency (alpha) increases with normalized impact force"); EnableDebugLogs = ((BaseUnityPlugin)this).Config.Bind("Debug", "EnableDebugLogs", false, "Enable force debug output"); if (EnableDebugLogs.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Debug logging is ENABLED."); } new Harmony("com.repo.DynamicRepoGrabBeam").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Grab Beam Mod v1.0.0 initialized successfully"); } } public class BeamColorObserver : MonoBehaviour { private readonly Dictionary lastGrabs = new Dictionary(); private readonly Dictionary lastRotating = new Dictionary(); private readonly Dictionary lastColorStates = new Dictionary(); private readonly List cachedGrabbers = new List(); private float updateInterval = 0.2f; private float timer; private float rescanInterval = 10f; private float rescanTimer; private void Awake() { RescanGrabbers(); } private void Update() { timer -= Time.deltaTime; rescanTimer -= Time.deltaTime; if (rescanTimer <= 0f) { RescanGrabbers(); rescanTimer = rescanInterval; } if (timer > 0f) { return; } timer = updateInterval; Rigidbody val = default(Rigidbody); foreach (PhysGrabber cachedGrabber in cachedGrabbers) { if ((Object)(object)cachedGrabber == (Object)null) { continue; } PhysGrabObject grabbedObject = cachedGrabber.GetGrabbedObject(); if ((Object)(object)grabbedObject == (Object)null) { lastGrabs.Remove(cachedGrabber); lastRotating.Remove(cachedGrabber); lastColorStates.Remove(cachedGrabber); continue; } if (!((Component)grabbedObject).TryGetComponent(ref val)) { Plugin.Log.LogWarning((object)("[DynamicRepoGrabBeam] Delaying recolor: Rigidbody missing for object '" + ((Object)grabbedObject).name + "' (grabber '" + ((Object)cachedGrabber).name + "')")); continue; } int instanceID = ((Object)grabbedObject).GetInstanceID(); bool isRotating = cachedGrabber.isRotating; int colorState = cachedGrabber.colorState; int value; bool num = !lastGrabs.TryGetValue(cachedGrabber, out value) || value != instanceID; bool value2; bool flag = !lastRotating.TryGetValue(cachedGrabber, out value2) || value2 != isRotating; int value3; bool flag2 = !lastColorStates.TryGetValue(cachedGrabber, out value3) || value3 != colorState; if (num || flag || flag2) { BeamColorManager.UpdateBeamFor(cachedGrabber, grabbedObject); } lastGrabs[cachedGrabber] = instanceID; lastRotating[cachedGrabber] = isRotating; lastColorStates[cachedGrabber] = colorState; } } private void RescanGrabbers() { cachedGrabbers.Clear(); cachedGrabbers.AddRange(Object.FindObjectsOfType()); } } namespace DynamicRepoGrabBeam.Patches { public static class PhysGrabberAccessors { private static readonly FieldInfo grabbedObjField; private static readonly FieldInfo beamField; private static readonly FieldInfo isPlayerField; private static readonly Func BreakForceGetter; private static readonly Func FragilityGetter; static PhysGrabberAccessors() { grabbedObjField = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject"); beamField = AccessTools.Field(typeof(PhysGrabber), "physGrabBeam"); isPlayerField = AccessTools.Field(typeof(PhysGrabObject), "isPlayer"); BreakForceGetter = CreateFieldGetter("breakForce"); FragilityGetter = CreateFieldGetter("impactFragilityMultiplier"); if (BreakForceGetter == null) { Debug.LogError((object)"[DynamicRepoGrabBeam] BreakForceGetter delegate failed!"); } if (FragilityGetter == null) { Debug.LogError((object)"[DynamicRepoGrabBeam] FragilityGetter delegate failed!"); } } public static bool IsPlayer(this PhysGrabObject obj) { if (isPlayerField != null) { return (bool)isPlayerField.GetValue(obj); } return false; } public static PhysGrabObject GetGrabbedObject(this PhysGrabber instance) { object? value = grabbedObjField.GetValue(instance); return (PhysGrabObject)((value is PhysGrabObject) ? value : null); } public static GameObject GetBeamObject(this PhysGrabber instance) { object? value = beamField.GetValue(instance); return (GameObject)((value is GameObject) ? value : null); } public static float GetBreakForce(this PhysGrabObjectImpactDetector det) { return BreakForceGetter(det); } public static float GetFragility(this PhysGrabObjectImpactDetector det) { return FragilityGetter(det); } private static Func CreateFieldGetter(string fieldName) { try { ParameterExpression parameterExpression = Expression.Parameter(typeof(PhysGrabObjectImpactDetector), "target"); return Expression.Lambda>(Expression.Field(parameterExpression, fieldName), new ParameterExpression[1] { parameterExpression }).Compile(); } catch (Exception ex) { Debug.LogError((object)("[DynamicRepoGrabBeam] Failed to create delegate for '" + fieldName + "': " + ex.Message)); return (PhysGrabObjectImpactDetector _) => default(T); } } } } namespace DynamicRepoGrabBeam.ColorLogic { public class PlayerGrabColorStrategy : IBeamColorStrategy { public bool Applies(PhysGrabber grabber, PhysGrabObject obj) { return obj.IsPlayer(); } public Color Modify(Color current, PhysGrabber grabber, PhysGrabObject obj) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Plugin.PlayerGrabColor.Value; } public Color ModifyFast(Color current, PhysGrabber grabber, PhysGrabObject obj, float impact, BeamContext ctx) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Plugin.PlayerGrabColor.Value; } } public class MassColorStrategy : IBeamColorStrategy { public bool Applies(PhysGrabber grabber, PhysGrabObject obj) { if (obj.IsPlayer()) { return false; } Rigidbody val = default(Rigidbody); return ((Component)obj).TryGetComponent(ref val); } public Color Modify(Color current, PhysGrabber grabber, PhysGrabObject obj) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Rigidbody val = default(Rigidbody); if (!((Component)obj).TryGetComponent(ref val)) { return current; } float mass = val.mass; float value = Plugin.LightMax.Value; float value2 = Plugin.HeavyMin.Value; if (mass < value) { return Plugin.LightColor.Value; } if (mass > value2) { return Plugin.HeavyColor.Value; } return Plugin.MediumColor.Value; } public Color ModifyFast(Color current, PhysGrabber grabber, PhysGrabObject obj, float impact, BeamContext ctx) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return Modify(current, grabber, obj); } } public class RotationLightenStrategy : IBeamColorStrategy { public bool Applies(PhysGrabber grabber, PhysGrabObject obj) { return grabber.isRotating; } public Color Modify(Color current, PhysGrabber grabber, PhysGrabObject obj) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Plugin.RotationModeColor.Value; } public Color ModifyFast(Color current, PhysGrabber grabber, PhysGrabObject obj, float impact, BeamContext ctx) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!grabber.isRotating) { return current; } if (Plugin.EnableDebugLogs.Value) { Plugin.Log.LogInfo((object)"[Rotation] Overriding beam with RotationModeColor"); } return Plugin.RotationModeColor.Value; } } public class BeamContext { public PhysGrabObject GrabbedObject { get; } public Renderer BeamRenderer { get; } public float H0 { get; } public float S0 { get; } public float V0 { get; } public float MaxForce { get; } public float SaturationScale { get; } public float BrightnessScale { get; } public float AlphaScale { get; } public Color BaseColor { get; } public BeamContext(PhysGrabObject obj, Renderer renderer, float h, float s, float v, float maxForce, float satScale, float brightScale, float alphaScale, Color baseColor) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) GrabbedObject = obj; BeamRenderer = renderer; H0 = h; S0 = s; V0 = v; MaxForce = maxForce; SaturationScale = satScale; BrightnessScale = brightScale; AlphaScale = alphaScale; BaseColor = baseColor; } } public class ForceEffectStrategy : IBeamColorStrategy { public static float ComputeImpact(PhysGrabObject obj) { PhysGrabObjectImpactDetector det = default(PhysGrabObjectImpactDetector); if (!((Component)obj).TryGetComponent(ref det)) { return 0f; } float breakForce = det.GetBreakForce(); float fragility = det.GetFragility(); return breakForce / 8f * fragility; } public bool Applies(PhysGrabber grabber, PhysGrabObject obj) { PhysGrabObjectImpactDetector val = default(PhysGrabObjectImpactDetector); return ((Component)obj).TryGetComponent(ref val); } public Color Modify(Color current, PhysGrabber grabber, PhysGrabObject obj) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return current; } public Color ModifyFast(Color current, PhysGrabber grabber, PhysGrabObject obj, float ignoredImpact, BeamContext ctx) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) float num = ComputeImpact(obj); float num2 = Mathf.Clamp01(num / ctx.MaxForce); if (Plugin.EnableDebugLogs.Value) { Plugin.Log.LogInfo((object)$"[ForceEffectStrategy] Impact = {num:F2}, Strength = {num2:F2}"); } float h = ctx.H0; float s = ctx.S0; float v = ctx.V0; s = Mathf.Clamp01(s + num2 * ctx.SaturationScale); v = Mathf.Clamp01(v + num2 * ctx.BrightnessScale); Color result = Color.HSVToRGB(h, s, v); result.a = Mathf.Lerp(0.1f, 1f, num2 * ctx.AlphaScale); return result; } } public interface IBeamColorStrategy { bool Applies(PhysGrabber grabber, PhysGrabObject obj); Color Modify(Color current, PhysGrabber grabber, PhysGrabObject obj); Color ModifyFast(Color current, PhysGrabber grabber, PhysGrabObject obj, float impact, BeamContext ctx); } public static class BeamColorManager { [HarmonyPatch(typeof(PhysGrabber), "Update")] private static class Hook_LateUpdate { private static void Postfix(PhysGrabber __instance) { PhysGrabObject grabbedObject = __instance.GetGrabbedObject(); if ((Object)(object)grabbedObject == (Object)null) { _ctx = null; lastObj = null; return; } if (_ctx == null || (Object)(object)grabbedObject != (Object)(object)lastObj) { lastObj = grabbedObject; BuildContext(__instance, grabbedObject); } UpdateBeam(__instance); } } [HarmonyPatch(typeof(PhysGrabber), "ColorStateSetColor")] private static class Hook_ColorStateSetColor { private static void Postfix(PhysGrabber __instance) { RefreshFromEvent(__instance); } } [HarmonyPatch(typeof(PhysGrabber), "ResetBeam")] private static class Hook_ResetBeam { private static void Postfix(PhysGrabber __instance) { RefreshFromEvent(__instance); } } [HarmonyPatch(typeof(PhysGrabber), "PhysGrabBeamActivateRPC")] private static class Hook_BeamActivate { private static void Postfix(PhysGrabber __instance) { RefreshFromEvent(__instance); } } [HarmonyPatch(typeof(PhysGrabber), "PhysGrabBeamDeactivateRPC")] private static class Hook_BeamDeactivate { private static void Prefix(PhysGrabber __instance) { RefreshFromEvent(__instance); } } private static readonly List allStrategies = new List { new PlayerGrabColorStrategy(), new MassColorStrategy(), new ForceEffectStrategy(), new RotationLightenStrategy() }; private static BeamContext _ctx; private static List _active; private static PhysGrabObject lastObj = null; private static readonly FieldInfo healingField = AccessTools.Field(typeof(PhysGrabber), "healing"); public static void Initialize() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("BeamColorObserver") { hideFlags = (HideFlags)61 }; val.AddComponent(); val.SetActive(true); Plugin.Log.LogInfo((object)"[DynamicRepoGrabBeam] BeamColorObserver GameObject created and observing."); } private static void BuildContext(PhysGrabber grabber, PhysGrabObject obj) { //IL_001d: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) GameObject beamObject = grabber.GetBeamObject(); Renderer val = ((beamObject != null) ? beamObject.GetComponentInChildren() : null); if ((Object)(object)val == (Object)null) { return; } Color val2 = Color.white; foreach (IBeamColorStrategy allStrategy in allStrategies) { if (allStrategy is ForceEffectStrategy) { break; } if (allStrategy.Applies(grabber, obj)) { val2 = allStrategy.Modify(val2, grabber, obj); } } float h = default(float); float s = default(float); float v = default(float); Color.RGBToHSV(val2, ref h, ref s, ref v); _ctx = new BeamContext(obj, val, h, s, v, Plugin.MaxStunVisualForce.Value, Plugin.ForceSaturationScale.Value, Plugin.ForceBrightnessScale.Value, Plugin.ForceAlphaScale.Value, val2); _active = allStrategies.ToList(); } private static void UpdateBeam(PhysGrabber grabber) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0073: 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_009c: Unknown result type (might be due to invalid IL or missing references) float impact = 0f; PhysGrabObjectImpactDetector val = default(PhysGrabObjectImpactDetector); if (((Component)_ctx.GrabbedObject).TryGetComponent(ref val)) { impact = ForceEffectStrategy.ComputeImpact(_ctx.GrabbedObject); } Color val2 = Color.HSVToRGB(_ctx.H0, _ctx.S0, _ctx.V0); foreach (IBeamColorStrategy item in _active) { val2 = item.ModifyFast(val2, grabber, _ctx.GrabbedObject, impact, _ctx); } ApplyBeamColor(_ctx.BeamRenderer, val2); } private static void RefreshFromEvent(PhysGrabber grabber) { if ((Object)(object)grabber == (Object)null || IsHealing(grabber)) { return; } PhysGrabObject grabbedObject = grabber.GetGrabbedObject(); if (!((Object)(object)grabbedObject == (Object)null)) { if (_ctx == null || (Object)(object)grabbedObject != (Object)(object)lastObj) { lastObj = grabbedObject; BuildContext(grabber, grabbedObject); } UpdateBeam(grabber); } } private static bool IsHealing(PhysGrabber grabber) { if (healingField != null) { return (bool)healingField.GetValue(grabber); } return false; } public static void ApplyBeamColor(Renderer rend, Color color) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Material material = rend.material; material.SetColor("_Color", color); material.SetColor("_EmissionColor", color); } public static void UpdateBeamFor(PhysGrabber grabber, PhysGrabObject obj) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)obj == (Object)null) { return; } GameObject beamObject = grabber.GetBeamObject(); Renderer val = ((beamObject != null) ? beamObject.GetComponentInChildren() : null); if ((Object)(object)val == (Object)null) { return; } Rigidbody val2 = default(Rigidbody); bool num = ((Component)obj).TryGetComponent(ref val2); float num2 = (num ? val2.mass : (-1f)); Color val3; if (!num || num2 <= 0f) { val3 = Plugin.MediumColor.Value; Plugin.Log.LogWarning((object)("[DynamicRepoGrabBeam] Applying fallback color for '" + ((Object)obj).name + "' grabbed by '" + ((Object)grabber).name + "' (missing Rigidbody)")); } else { val3 = Color.white; foreach (IBeamColorStrategy allStrategy in allStrategies) { if (allStrategy is ForceEffectStrategy) { break; } if (allStrategy.Applies(grabber, obj)) { val3 = allStrategy.Modify(val3, grabber, obj); } } } float num3 = default(float); float num4 = default(float); float num5 = default(float); Color.RGBToHSV(val3, ref num3, ref num4, ref num5); BeamContext ctx = new BeamContext(obj, val, num3, num4, num5, Plugin.MaxStunVisualForce.Value, Plugin.ForceSaturationScale.Value, Plugin.ForceBrightnessScale.Value, Plugin.ForceAlphaScale.Value, val3); float impact = 0f; PhysGrabObjectImpactDetector val4 = default(PhysGrabObjectImpactDetector); if (((Component)obj).TryGetComponent(ref val4)) { impact = ForceEffectStrategy.ComputeImpact(obj); } Color val5 = Color.HSVToRGB(num3, num4, num5); foreach (IBeamColorStrategy allStrategy2 in allStrategies) { val5 = allStrategy2.ModifyFast(val5, grabber, obj, impact, ctx); } ApplyBeamColor(val, val5); } } }