using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using GoinGrabber;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.Players.Subsystems;
using Il2CppRUMBLE.Utilities;
using MelonLoader;
using Microsoft.CodeAnalysis;
using RumbleModdingAPI;
using UnityEngine;
using UnityEngine.XR;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "GoinGrabber", "1.2.0", "Roaby", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: MelonColor(50, 168, 164, 255)]
[assembly: MelonAuthorColor(50, 168, 164, 255)]
[assembly: VerifyLoaderVersion(0, 6, 6, true)]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GoinGrabber")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+7ceffbc0a8cc109b0c18606887033e5315ca4186")]
[assembly: AssemblyProduct("GoinGrabber")]
[assembly: AssemblyTitle("GoinGrabber")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace GoinGrabber
{
internal class BuildInfo
{
public const string ModName = "GoinGrabber";
public const string Author = "Roaby";
public const string ModVersion = "1.2.0";
}
public class Core : MelonMod
{
[HarmonyPatch(typeof(PlayerBoxInteractionSystem))]
[HarmonyPatch("ExecuteFistBumpReward")]
public static class FistBumpBonusPatch
{
[HarmonyPrefix]
public static bool Prefix(PlayerBoxInteractionSystem __instance, Vector3 interactionPosition)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)__instance.onFistBumpBonusVFX != (Object)null)
{
AnimateGoinReplacer(interactionPosition);
__instance.onFistBumpBonusVFX = null;
}
if ((Object)(object)__instance.onFistBumpBonusSFX != (Object)null)
{
__instance.onFistBumpBonusSFX = null;
}
return true;
}
}
private string currentScene = "Loader";
private bool lookingForNewObjects;
private HashSet<int> knownInstanceIDs = new HashSet<int>();
private static Vector3 gymGoinPosition = new Vector3(0f, 1.6f, 0f);
public static Instance Logger { get; private set; }
public override void OnInitializeMelon()
{
Logger = ((MelonBase)this).LoggerInstance;
Logger.Msg("GoinGrabber: Initialized.");
new GoinManager();
}
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
currentScene = sceneName;
lookingForNewObjects = false;
if (!ModResources.Initialized)
{
ModResources.LoadResources();
}
if (currentScene.Equals("Gym") || currentScene.Equals("Map0") || currentScene.Equals("Map1"))
{
MelonCoroutines.Start(CreateGoinInteractionObjects());
}
}
public override void OnUpdate()
{
}
private static void AnimateGoinReplacer(Vector3 position)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
GoinManager.Instance.CreateReplacementFistBumpGoin(position);
ModResources.InstantiateFistbumpRing(position);
}
private IEnumerator CreateGoinInteractionObjects()
{
yield return (object)new WaitForSeconds(5f);
Transform child = ((Component)Singleton<PlayerManager>.instance.localPlayer.Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(2)
.GetChild(0)
.GetChild(0)
.GetChild(0);
Transform child2 = ((Component)Singleton<PlayerManager>.instance.localPlayer.Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(1)
.GetChild(0)
.GetChild(0)
.GetChild(0);
ModResources.InstantiateHandSlapper(child, localPlayer: true, rightHand: true);
ModResources.InstantiateHandSlapper(child2, localPlayer: true, rightHand: false);
if (Singleton<PlayerManager>.instance.AllPlayers.Count > 1)
{
Transform child3 = ((Component)Singleton<PlayerManager>.instance.AllPlayers[1].Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(2)
.GetChild(0)
.GetChild(0)
.GetChild(0);
Transform child4 = ((Component)Singleton<PlayerManager>.instance.AllPlayers[1].Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(1)
.GetChild(0)
.GetChild(0)
.GetChild(0);
ModResources.InstantiateHandSlapper(child3, localPlayer: false, rightHand: true);
ModResources.InstantiateHandSlapper(child4, localPlayer: false, rightHand: false);
}
}
}
[RegisterTypeInIl2Cpp]
public class GoinHandler : MonoBehaviour
{
public float initialUpwardVelocity = 4f;
public float tossGravity = -9.81f;
public float spinSpeed = 500f;
public AudioSource flipAudioSource;
public GameObject catchPoint;
public float hoverDuration = 0.5f;
private float hoverTimer;
private bool isHovering;
private float verticalVelocity;
private bool isFalling;
private bool isLaunched;
private Rigidbody rb;
private bool caught;
private Transform remotePlayerLeftHand;
private Transform remotePlayerRightHand;
private Transform localPlayerLeftHand;
private Transform localPlayerRightHand;
private Transform remotePlayerRightMiddleFinger;
private Transform remotePlayerLeftMiddleFinger;
private bool localRightHandTriggerPressedEarly;
private bool localLeftHandTriggerPressedEarly;
private bool remoteRightHandTriggerPressedEarly;
private bool remoteLeftHandTriggerPressedEarly;
private void Awake()
{
rb = ((Component)this).GetComponent<Rigidbody>();
flipAudioSource = ((Component)this).gameObject.GetComponent<AudioSource>();
if (Singleton<PlayerManager>.instance.AllPlayers.Count > 1)
{
remotePlayerRightHand = ((Component)Singleton<PlayerManager>.instance.AllPlayers[1].Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(2)
.GetChild(0)
.GetChild(0)
.GetChild(0);
remotePlayerLeftHand = ((Component)Singleton<PlayerManager>.instance.AllPlayers[1].Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(1)
.GetChild(0)
.GetChild(0)
.GetChild(0);
remotePlayerRightMiddleFinger = remotePlayerRightHand.GetChild(0).GetChild(0);
remotePlayerLeftMiddleFinger = remotePlayerLeftHand.GetChild(0).GetChild(0);
}
localPlayerRightHand = ((Component)Singleton<PlayerManager>.instance.localPlayer.Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(2)
.GetChild(0)
.GetChild(0)
.GetChild(0);
localPlayerLeftHand = ((Component)Singleton<PlayerManager>.instance.localPlayer.Controller).transform.GetChild(0).GetChild(1).GetChild(0)
.GetChild(4)
.GetChild(0)
.GetChild(1)
.GetChild(0)
.GetChild(0)
.GetChild(0);
}
private void Update()
{
//IL_0134: 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)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: 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_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
if (isLaunched)
{
if (!isFalling)
{
if (!isHovering)
{
verticalVelocity += tossGravity * Time.deltaTime;
Transform transform = ((Component)this).transform;
transform.position += Vector3.up * verticalVelocity * Time.deltaTime;
((Component)this).transform.Rotate(Vector3.up, spinSpeed * Time.deltaTime);
if (verticalVelocity <= 0f)
{
isHovering = true;
hoverTimer = hoverDuration;
verticalVelocity = 0f;
rb.isKinematic = false;
rb.angularVelocity = new Vector3(0f, 10f, 0f);
}
}
else
{
hoverTimer -= Time.deltaTime;
if (hoverTimer <= 0f)
{
isHovering = false;
isFalling = true;
verticalVelocity = 0f;
}
}
}
else
{
rb.useGravity = true;
isLaunched = false;
}
}
if (((Component)this).transform.position.y < -20f && !caught)
{
GoinManager.Instance.DestroyGoin(((Component)this).gameObject);
}
}
private void OnTriggerEnter(Collider other)
{
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
if (!rb.isKinematic)
{
if (((Object)other).name == "localRightCatcher" && (double)RightController.GetGrip() > 0.6)
{
localRightHandTriggerPressedEarly = true;
}
else if (((Object)other).name == "localLeftCatcher" && (double)LeftController.GetGrip() > 0.6)
{
localLeftHandTriggerPressedEarly = true;
}
else if (((Object)other).name == "remoteRightCatcher" && ((Component)remotePlayerRightMiddleFinger).transform.rotation.x > 70f && ((Component)remotePlayerRightMiddleFinger).transform.rotation.x < 90f)
{
remoteRightHandTriggerPressedEarly = true;
}
else if (((Object)other).name == "remoteLeftCatcher" && ((Component)remotePlayerLeftMiddleFinger).transform.rotation.x > 60f && ((Component)remotePlayerLeftMiddleFinger).transform.rotation.x < 80f)
{
remoteLeftHandTriggerPressedEarly = true;
}
}
}
private void OnTriggerStay(Collider other)
{
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
if (!rb.isKinematic)
{
if (((Object)other).name == "localRightCatcher" && (double)RightController.GetGrip() > 0.6 && !localRightHandTriggerPressedEarly)
{
VibrationUtil.Vibrate((XRNode)5);
TriggerCatchAnimation();
}
else if (((Object)other).name == "localLeftCatcher" && (double)LeftController.GetGrip() > 0.6 && !localLeftHandTriggerPressedEarly)
{
VibrationUtil.Vibrate((XRNode)4);
TriggerCatchAnimation();
}
else if (((Object)other).name == "remoteRightCatcher" && ((Component)remotePlayerRightMiddleFinger).transform.rotation.x > 70f && ((Component)remotePlayerRightMiddleFinger).transform.rotation.x < 90f && !remoteRightHandTriggerPressedEarly)
{
TriggerCatchAnimation();
}
else if (((Object)other).name == "remoteLeftCatcher" && ((Component)remotePlayerLeftMiddleFinger).transform.rotation.x > 60f && ((Component)remotePlayerLeftMiddleFinger).transform.rotation.x < 80f && !remoteLeftHandTriggerPressedEarly)
{
TriggerCatchAnimation();
}
}
}
private void OnTriggerExit(Collider other)
{
if (!rb.isKinematic)
{
if (((Object)other).name == "localRightCatcher")
{
localRightHandTriggerPressedEarly = false;
}
else if (((Object)other).name == "localLeftCatcher")
{
localLeftHandTriggerPressedEarly = false;
}
else if (((Object)other).name == "remoteRightCatcher")
{
remoteRightHandTriggerPressedEarly = false;
}
else if (((Object)other).name == "remoteLeftCatcher")
{
remoteLeftHandTriggerPressedEarly = false;
}
}
}
private void TriggerCatchAnimation()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
catchPoint = ModResources.InstantiateCatchPoint(((Component)this).transform.position);
catchPoint.GetComponent<AudioSource>().Play();
Object.Destroy((Object)(object)catchPoint, catchPoint.GetComponent<AudioSource>().clip.length);
isLaunched = false;
isFalling = false;
GoinManager.Instance.DestroyGoin(((Component)this).gameObject);
caught = true;
}
private void OnCollisionEnter(Collision collision)
{
//IL_0049: 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)
//IL_0056: 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_0068: Unknown result type (might be due to invalid IL or missing references)
HandVelocityTracker handVelocityTracker = default(HandVelocityTracker);
if (((Object)collision.gameObject).name.EndsWith("Slapper") && !caught && collision.gameObject.TryGetComponent<HandVelocityTracker>(ref handVelocityTracker))
{
hoverTimer = 0f;
ContactPoint val = ((Il2CppArrayBase<ContactPoint>)(object)collision.contacts)[0];
rb.AddForceAtPosition(handVelocityTracker.Velocity * handVelocityTracker.slapForce, ((ContactPoint)(ref val)).point, (ForceMode)1);
if (((Object)collision.gameObject).name.StartsWith("localRight"))
{
VibrationUtil.Vibrate((XRNode)5, 0.8f, 0.3f);
}
else if (((Object)collision.gameObject).name.StartsWith("localLeft"))
{
VibrationUtil.Vibrate((XRNode)4, 0.8f, 0.3f);
}
}
}
public void Launch()
{
verticalVelocity = initialUpwardVelocity;
isLaunched = true;
isFalling = false;
caught = false;
flipAudioSource.Play();
rb.isKinematic = true;
rb.useGravity = false;
}
}
public class GoinManager
{
public float initialTossUpwardVelocity = 3.5f;
public float tossGravity = -15f;
public float tossSpinSpeed = 500f;
public float tossHoverDuration = 0.5f;
public static GoinManager Instance { get; private set; }
public List<GameObject> activeGoins { get; private set; } = new List<GameObject>();
public int maxGoins { get; set; } = 10;
public GoinManager()
{
Instance = this;
}
public void CreateReplacementFistBumpGoin(Vector3 position)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
GoinHandler component = AddGoinToScene(position).GetComponent<GoinHandler>();
component.initialUpwardVelocity = initialTossUpwardVelocity;
component.tossGravity = tossGravity;
component.spinSpeed = tossSpinSpeed;
component.hoverDuration = tossHoverDuration;
component.Launch();
}
public GameObject AddGoinToScene(Vector3 position)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
GameObject val = ModResources.InstantiateGoin(position);
val.AddComponent<GoinHandler>();
if (activeGoins.Count == 0)
{
EnableGoinPhysicsInteractions(enable: true);
}
activeGoins.Add(val);
if (activeGoins.Count > maxGoins)
{
GameObject obj = activeGoins[0];
activeGoins.RemoveAt(0);
Object.Destroy((Object)(object)obj);
}
return val;
}
public void DestroyGoin(GameObject target)
{
if (activeGoins.Remove(target))
{
Object.Destroy((Object)(object)target);
}
if (activeGoins.Count == 0)
{
EnableGoinPhysicsInteractions(enable: false);
}
}
public void ClearGoins()
{
activeGoins.Clear();
}
public void EnableGoinPhysicsInteractions(bool enable)
{
Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Default"), LayerMask.NameToLayer("Default"), !enable);
Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Default"), LayerMask.NameToLayer("CombatFloor"), !enable);
Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Default"), LayerMask.NameToLayer("Floor"), !enable);
}
}
[RegisterTypeInIl2Cpp]
public class HandVelocityTracker : MonoBehaviour
{
public float slapForce = 0.5f;
private Vector3 lastPosition;
public Vector3 Velocity { get; private set; }
private void Start()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
lastPosition = ((Component)this).transform.position;
}
private void Update()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: 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)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: 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)
Velocity = (((Component)this).transform.position - lastPosition) / Time.deltaTime;
lastPosition = ((Component)this).transform.position;
}
}
internal class ModResources
{
public static Il2CppAssetBundle Bundle;
public static GameObject GoinPrefab;
private static bool initialized;
public static bool Initialized => initialized;
public static void LoadResources(bool reload = false)
{
if (!initialized || reload)
{
Bundle = Il2CppAssetBundleManager.LoadFromFile("UserData/goingrabberbundle");
initialized = true;
}
}
public static GameObject InstantiateGoin(Vector3 position)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(Bundle.LoadAsset<GameObject>("Goin"));
obj.transform.position = position;
((Object)obj).name = "CustomGoin";
return obj;
}
public static GameObject InstantiateCatchPoint(Vector3 position)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(Bundle.LoadAsset<GameObject>("CatchPoint"));
obj.transform.position = position;
((Object)obj).name = "CatchPoint";
return obj;
}
public static GameObject InstantiateFistbumpRing(Vector3 position)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(Bundle.LoadAsset<GameObject>("FistbumpRing"));
obj.transform.position = position;
obj.AddComponent<RingDissolver>();
((Object)obj).name = "FistbumpRing";
return obj;
}
public static GameObject InstantiateHandSlapper(Transform parent, bool localPlayer, bool rightHand)
{
//IL_0080: 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_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
GameObject val = Object.Instantiate<GameObject>(Bundle.LoadAsset<GameObject>("HandSlapper"), parent);
((Object)val).name = "HandSlapper";
Transform val2 = val.transform.Find("GoinCatcher");
if ((Object)(object)val2 != (Object)null)
{
string text = (localPlayer ? "local" : "remote");
text += (rightHand ? "RightCatcher" : "LeftCatcher");
((Object)val2).name = text;
}
if (!rightHand)
{
val.transform.localRotation = Quaternion.Euler(0f, 165f, 15f);
Vector3 localPosition = val.transform.localPosition;
localPosition.x = 0f - localPosition.x;
val.transform.localPosition = localPosition;
}
Transform val3 = val.transform.Find("SlapCollider");
if ((Object)(object)val3 != (Object)null)
{
((Component)val3).gameObject.AddComponent<HandVelocityTracker>();
string text2 = (localPlayer ? "local" : "remote");
text2 += (rightHand ? "RightSlapper" : "LeftSlapper");
((Object)val3).name = text2;
}
((Component)val.transform.Find("VisualCapsule")).gameObject.SetActive(false);
((Component)val.transform.Find("VisualHand")).gameObject.SetActive(false);
return val;
}
}
[RegisterTypeInIl2Cpp]
internal class RingDissolver : MonoBehaviour
{
public Material material;
public float dissolveTime = 1f;
private float startTime;
private void Start()
{
material = ((Component)this).GetComponent<Renderer>().material;
startTime = Time.time;
}
private void Update()
{
float num = Time.time - startTime;
float num2 = Mathf.Clamp01(num / dissolveTime);
float num3 = Mathf.Lerp(0.1f, 1f, num2);
material.SetFloat("_DissolveAmount", num3);
if (num >= dissolveTime)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
}
public static class VibrationUtil
{
public static void Vibrate(XRNode node, float amplitude = 0.5f, float duration = 0.2f)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
try
{
InputDevice deviceAtXRNode = InputDevices.GetDeviceAtXRNode(node);
((InputDevice)(ref deviceAtXRNode)).SendHapticImpulse(0u, amplitude, duration);
}
catch (Exception ex)
{
Core.Logger.Error("Failed to send haptic feedback: " + ex.Message);
}
}
}
}