Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PocketCart v1.0.4
BepInEx/plugins/RepoPocketCart.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using PocketCart.Core; using PocketCart.Patches; using ScalerCore; using UnityEngine; using UnityEngine.SceneManagement; [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("RepoPocketCart")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.4.0")] [assembly: AssemblyInformationalVersion("1.0.4")] [assembly: AssemblyProduct("Pocket Cart")] [assembly: AssemblyTitle("RepoPocketCart")] [assembly: AssemblyVersion("1.0.4.0")] namespace PocketCart { [BepInPlugin("com.sunwu.pocket_cart", "Pocket Cart", "1.0.4")] [BepInIncompatibility("empress.repo.pocketdimensioncart")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; private void Awake() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; GameAccess.Resolve(); PatchInstaller.InstallAll(new Harmony("com.sunwu.pocket_cart")); SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)mode == 0) { VaultRegistry.Reset(); } }; Log.LogInfo((object)"Pocket Cart 1.0.4 ready - cart contents are folded into the cart (host-authoritative)."); } } internal static class PluginInfo { internal const string Guid = "com.sunwu.pocket_cart"; internal const string Name = "Pocket Cart"; internal const string Version = "1.0.4"; internal const string ReplacedGuid = "empress.repo.pocketdimensioncart"; } } namespace PocketCart.Patches { internal static class CartScreenTotal { private static bool _warned; internal static void Prefix(ValueScreen __instance, ref int newValue) { try { CartVault cartVault = VaultRegistry.FindByScreen(__instance); if (!((Object)(object)cartVault == (Object)null) && cartVault.Count != 0) { newValue += cartVault.HiddenValuableTotal(); } } catch (Exception ex) { if (!_warned) { _warned = true; Plugin.Log.LogWarning((object)("Cart screen total failed, showing the vanilla value: " + ex.Message)); } } } } internal static class CartSpawnHook { internal static void Postfix(PhysGrabCart __instance) { if (!Object.op_Implicit((Object)(object)__instance)) { return; } try { if (RunGate.IsRunLevel && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<CartVault>())) { ((Component)__instance).gameObject.AddComponent<CartVault>(); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not attach a vault to cart '" + ((Object)__instance).name + "': " + ex.Message)); } } } } namespace PocketCart.Core { internal sealed class CartVault : MonoBehaviour { private struct Slot { public PhysGrabObject Item; public int Key; public int ViewId; public Quaternion Rest; } private const float IntakeScanInterval = 0.1f; private const float IntakeSettleSeconds = 0.25f; private const float ShieldInterval = 0.5f; private const float ShieldSeconds = 1.5f; private const float GrabKickInterval = 0.25f; private const float GrabKickLockSeconds = 0.4f; private const float SpillSpacing = 0.6f; private const float SpillLift = 0.5f; private const float SpillShieldSeconds = 5f; private const float SpillImpactMuteSeconds = 1f; private const float ReintakeLockSeconds = 2.5f; private const float MirrorRetryInterval = 0.5f; private const float PinDistanceSqr = 1E-06f; private const float PinAngle = 0.05f; private static readonly int[] SpillCellOrder = new int[9] { 4, 1, 3, 5, 7, 0, 2, 6, 8 }; private readonly List<Slot> _slots = new List<Slot>(); private readonly HashSet<int> _mirrorViews = new HashSet<int>(); private readonly Dictionary<int, float> _settleSince = new Dictionary<int, float>(); private readonly HashSet<int> _seenThisScan = new HashSet<int>(); private readonly List<int> _settleStale = new List<int>(); private PhysGrabCart _cart; private PhysGrabObject _cartBody; private ItemEquippable _equip; private Transform _bay; private bool _ready; private bool _dirty; private bool _hasDockedPose; private Vector3 _dockedCenter; private Quaternion _dockedRotation = Quaternion.identity; private float _nextIntakeScan; private float _nextShield; private float _nextGrabKick; private float _nextMirrorRetry; internal int ViewId { get; private set; } internal int Count => _slots.Count; private void Start() { _cart = ((Component)this).GetComponent<PhysGrabCart>(); _cartBody = ((Component)this).GetComponent<PhysGrabObject>(); _equip = ((Component)this).GetComponent<ItemEquippable>(); _bay = ((Component)this).transform.Find("In Cart"); PhotonView component = ((Component)this).GetComponent<PhotonView>(); ViewId = (Object.op_Implicit((Object)(object)component) ? component.ViewID : 0); if (!Object.op_Implicit((Object)(object)_cart) || !Object.op_Implicit((Object)(object)_cartBody) || !Object.op_Implicit((Object)(object)_bay)) { Plugin.Log.LogWarning((object)("Cart '" + ((Object)this).name + "' has no 'In Cart' volume, leaving it vanilla.")); Object.Destroy((Object)(object)this); return; } _ready = true; VaultRegistry.Register(this, _cart.valueScreen); if (!SemiFunc.IsMultiplayer()) { return; } VaultNet.EnsureListening(); if (!SemiFunc.IsMasterClientOrSingleplayer()) { int[] array = VaultRegistry.TakePendingMirror(ViewId); if (array != null) { ApplyMirror(array); } VaultNet.RequestSnapshot(); } } private void Update() { if (_ready && RunGate.InRunLevel) { if (RunGate.IsHost) { HostTick(Time.time); } else { MirrorTick(Time.time); } } } private void LateUpdate() { if (_ready && _slots.Count != 0 && RunGate.IsHost) { PinContents(); } } private void OnDisable() { if (_ready && RunGate.IsHost && RunGate.Playing) { SpillAll("cart disabled"); } } private void OnDestroy() { if (!_ready) { return; } _ready = false; if (RunGate.IsHost) { if (RunGate.Playing) { SpillAll("cart destroyed"); } } else { ReleaseMirror(); } VaultRegistry.Unregister(this); } internal int HiddenValuableTotal() { int num = 0; for (int i = 0; i < _slots.Count; i++) { PhysGrabObject item = _slots[i].Item; if (!Object.op_Implicit((Object)(object)item)) { continue; } StashMask component = ((Component)item).GetComponent<StashMask>(); if (Object.op_Implicit((Object)(object)component) && component.Engaged) { ValuableObject component2 = ((Component)item).GetComponent<ValuableObject>(); if (Object.op_Implicit((Object)(object)component2)) { num += GameAccess.DollarValue(component2); } } } return num; } internal int[] ExportViewIds() { List<int> list = new List<int>(_slots.Count); foreach (Slot slot in _slots) { if (Object.op_Implicit((Object)(object)slot.Item) && slot.ViewId != 0) { list.Add(slot.ViewId); } } return list.ToArray(); } internal void ApplyMirror(int[] itemViewIds) { if (!_ready || RunGate.IsHost) { return; } _mirrorViews.Clear(); if (itemViewIds != null) { foreach (int num in itemViewIds) { if (num != 0) { _mirrorViews.Add(num); } } } for (int num2 = _slots.Count - 1; num2 >= 0; num2--) { Slot slot = _slots[num2]; if (!Object.op_Implicit((Object)(object)slot.Item) || !_mirrorViews.Contains(slot.ViewId)) { if (Object.op_Implicit((Object)(object)slot.Item)) { Unmask(slot.Item, thawPhysics: false); } _slots.RemoveAt(num2); } } ResolveMirror(); } private void HostTick(float now) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (PruneMissing()) { _dirty = true; } bool flag = IsDocked(); if (flag) { _dockedCenter = _bay.position; _dockedRotation = _bay.rotation; _hasDockedPose = true; } if (_slots.Count > 0) { if (now >= _nextGrabKick) { _nextGrabKick = now + 0.25f; KickGrabbers(); } if (now >= _nextShield) { _nextShield = now + 0.5f; foreach (Slot slot in _slots) { if (Object.op_Implicit((Object)(object)slot.Item)) { Shield(slot.Item, 1.5f, 1.5f); GameAccess.HoldInCart(((Component)slot.Item).GetComponent<PhysGrabObjectImpactDetector>(), _cart, 1.5f); NoisyLoot.Hush(slot.Item); } } } } if (now >= _nextIntakeScan) { _nextIntakeScan = now + 0.1f; if (flag) { ScanIntake(now); } else { _settleSince.Clear(); } } if (_dirty) { _dirty = false; VaultNet.PublishCart(this, 0); } } private bool IsDocked() { if (!((Behaviour)_cart).isActiveAndEnabled) { return false; } Rigidbody rb = _cartBody.rb; if (Object.op_Implicit((Object)(object)rb) && !rb.detectCollisions) { return false; } if (Object.op_Implicit((Object)(object)_equip) && (_equip.IsEquipped() || GameAccess.InEquipTransition(_equip))) { return false; } return true; } private void ScanIntake(float now) { _seenThisScan.Clear(); List<CartObject> list = GameAccess.CartEntries(_cart.physGrabInCart); if (list != null) { for (int i = 0; i < list.Count; i++) { PhysGrabObject val = list[i]?.physGrabObject; if (!IsIntakeCandidate(val, now)) { continue; } int instanceID = ((Object)val).GetInstanceID(); if (_seenThisScan.Add(instanceID)) { if (!_settleSince.TryGetValue(instanceID, out var value)) { _settleSince[instanceID] = now; } else if (now - value >= 0.25f) { Admit(val); } } } } _settleStale.Clear(); foreach (int key in _settleSince.Keys) { if (!_seenThisScan.Contains(key)) { _settleStale.Add(key); } } foreach (int item in _settleStale) { _settleSince.Remove(item); } } private bool IsIntakeCandidate(PhysGrabObject item, float now) { if (!Object.op_Implicit((Object)(object)item) || (Object)(object)item == (Object)(object)_cartBody || item.dead || !item.spawned || !((Behaviour)item).isActiveAndEnabled) { return false; } if (item.grabbed || item.playerGrabbing.Count > 0) { return false; } Rigidbody rb = item.rb; if (!Object.op_Implicit((Object)(object)rb) || rb.isKinematic) { return false; } if (VaultRegistry.IsHeld(item) || VaultRegistry.IsIntakeLocked(item, now)) { return false; } PhysGrabObjectImpactDetector component = ((Component)item).GetComponent<PhysGrabObjectImpactDetector>(); if (!Object.op_Implicit((Object)(object)component) || !component.inCart || (Object)(object)GameAccess.CartOf(component) != (Object)(object)_cart) { return false; } return IsSellable(item); } private static bool IsSellable(PhysGrabObject item) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 ValuableObject component = ((Component)item).GetComponent<ValuableObject>(); if (Object.op_Implicit((Object)(object)component)) { if (GameAccess.DollarValueReady(component)) { return !GameAccess.IsClaimedByValuableBox(item); } return false; } ItemValuableBox component2 = ((Component)item).GetComponent<ItemValuableBox>(); if (Object.op_Implicit((Object)(object)component2)) { if ((int)component2.currentState != 0) { return (int)component2.currentState == 4; } return true; } CosmeticWorldObject component3 = ((Component)item).GetComponent<CosmeticWorldObject>(); if (Object.op_Implicit((Object)(object)component3)) { return !GameAccess.IsExploding(component3); } return false; } private void Admit(PhysGrabObject item) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_009e: 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) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) StashMask stashMask = ((Component)item).GetComponent<StashMask>(); if (!Object.op_Implicit((Object)(object)stashMask)) { stashMask = ((Component)item).gameObject.AddComponent<StashMask>(); } stashMask.Engage(freezePhysics: true); PhotonView component = ((Component)item).GetComponent<PhotonView>(); Quaternion val = NoisyLoot.RestOffset(item); _slots.Add(new Slot { Item = item, Key = ((Object)item).GetInstanceID(), ViewId = (Object.op_Implicit((Object)(object)component) ? component.ViewID : 0), Rest = val }); VaultRegistry.MarkHeld(item, this); _settleSince.Remove(((Object)item).GetInstanceID()); Quaternion val2 = YawOnly(_bay.rotation) * val; item.Teleport(PivotFor(item, _bay.position, val2), val2); Shield(item, 1.5f, 1.5f); GameAccess.HoldInCart(((Component)item).GetComponent<PhysGrabObjectImpactDetector>(), _cart, 1.5f); ShrinkBridge.Shrink(item); _dirty = true; } private void PinContents() { //IL_0006: 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) //IL_0012: 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) //IL_001c: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) Vector3 position = _bay.position; Quaternion val = YawOnly(_bay.rotation); for (int i = 0; i < _slots.Count; i++) { PhysGrabObject item = _slots[i].Item; if (!Object.op_Implicit((Object)(object)item)) { continue; } Quaternion val2 = val * _slots[i].Rest; Vector3 val3 = PivotFor(item, position, val2); Transform transform = ((Component)item).transform; Vector3 val4 = transform.position - val3; if (!(((Vector3)(ref val4)).sqrMagnitude < 1E-06f) || !(Quaternion.Angle(transform.rotation, val2) < 0.05f)) { transform.SetPositionAndRotation(val3, val2); Rigidbody rb = item.rb; if (Object.op_Implicit((Object)(object)rb)) { rb.position = val3; rb.rotation = val2; } } } } private void KickGrabbers() { foreach (Slot slot in _slots) { PhysGrabObject item = slot.Item; if (!Object.op_Implicit((Object)(object)item) || item.playerGrabbing.Count == 0) { continue; } PhysGrabber[] array = item.playerGrabbing.ToArray(); foreach (PhysGrabber val in array) { if (Object.op_Implicit((Object)(object)val)) { val.OverrideGrabRelease(slot.ViewId, 0.4f); } } } } private bool PruneMissing() { bool result = false; for (int num = _slots.Count - 1; num >= 0; num--) { if (!Object.op_Implicit((Object)(object)_slots[num].Item)) { VaultRegistry.ClearHeld(_slots[num].Key); _slots.RemoveAt(num); result = true; } } return result; } private void SpillAll(string reason) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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) try { PruneMissing(); if (_slots.Count == 0) { return; } ResolveSpillOrigin(out var origin, out var facing); float time = Time.time; int num = 0; foreach (Slot slot in _slots) { VaultRegistry.ClearHeld(slot.Key); PhysGrabObject item = slot.Item; if (Object.op_Implicit((Object)(object)item)) { VaultRegistry.LockIntake(item, time + 2.5f); Unmask(item, thawPhysics: true); ShrinkBridge.Restore(item); Vector3 center = origin + facing * SpillOffset(num); item.Teleport(PivotFor(item, center, facing), facing); Shield(item, 5f, 1f); num++; } } _slots.Clear(); _settleSince.Clear(); VaultNet.PublishCart(this, 0); Plugin.Log.LogInfo((object)$"Cart {ViewId}: spilled {num} stored item(s) ({reason})."); } catch (Exception ex) { Plugin.Log.LogWarning((object)$"Cart {ViewId}: failed to spill stored items ({reason}): {ex.Message}"); } } private void ResolveSpillOrigin(out Vector3 origin, out Quaternion facing) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) //IL_006e: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0051: 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) if (_hasDockedPose) { origin = _dockedCenter; facing = YawOnly(_dockedRotation); return; } TruckSafetySpawnPoint instance = TruckSafetySpawnPoint.instance; if (Object.op_Implicit((Object)(object)instance)) { origin = ((Component)instance).transform.position; facing = YawOnly(((Component)instance).transform.rotation); } else { origin = ((Component)this).transform.position; facing = Quaternion.identity; } } private void MirrorTick(float now) { PruneMissing(); if (_mirrorViews.Count > _slots.Count && now >= _nextMirrorRetry) { _nextMirrorRetry = now + 0.5f; ResolveMirror(); } } private void ResolveMirror() { foreach (int mirrorView in _mirrorViews) { if (HasView(mirrorView)) { continue; } PhotonView val = PhotonView.Find(mirrorView); PhysGrabObject val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<PhysGrabObject>() : null); if (Object.op_Implicit((Object)(object)val2)) { StashMask stashMask = ((Component)val2).GetComponent<StashMask>(); if (!Object.op_Implicit((Object)(object)stashMask)) { stashMask = ((Component)val2).gameObject.AddComponent<StashMask>(); } stashMask.Engage(freezePhysics: false); _slots.Add(new Slot { Item = val2, Key = ((Object)val2).GetInstanceID(), ViewId = mirrorView }); } } } private void ReleaseMirror() { foreach (Slot slot in _slots) { if (Object.op_Implicit((Object)(object)slot.Item)) { Unmask(slot.Item, thawPhysics: false); } } _slots.Clear(); _mirrorViews.Clear(); } private bool HasView(int viewId) { foreach (Slot slot in _slots) { if (slot.ViewId == viewId) { return true; } } return false; } private static void Unmask(PhysGrabObject item, bool thawPhysics) { StashMask component = ((Component)item).GetComponent<StashMask>(); if (Object.op_Implicit((Object)(object)component)) { component.Disengage(thawPhysics); } } private static void Shield(PhysGrabObject item, float indestructibleSeconds, float impactMuteSeconds) { item.OverrideIndestructible(indestructibleSeconds); PhysGrabObjectImpactDetector component = ((Component)item).GetComponent<PhysGrabObjectImpactDetector>(); if (Object.op_Implicit((Object)(object)component)) { component.ImpactDisable(impactMuteSeconds); } } private static Vector3 PivotFor(PhysGrabObject item, Vector3 center, Quaternion rotation) { //IL_0001: 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) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.Scale(item.midPointOffset, ((Component)item).transform.lossyScale); return center - rotation * val; } private static Vector3 SpillOffset(int index) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) int num = index / SpillCellOrder.Length; int num2 = SpillCellOrder[index % SpillCellOrder.Length]; return new Vector3((float)(num2 % 3 - 1) * 0.6f, 0.5f + (float)num * 0.6f, (float)(num2 / 3 - 1) * 0.6f); } private static Quaternion YawOnly(Quaternion rotation) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) return Quaternion.Euler(0f, ((Quaternion)(ref rotation)).eulerAngles.y, 0f); } } internal static class GameAccess { private static FieldRef<PhysGrabInCart, List<CartObject>> _cartEntries; private static FieldRef<PhysGrabObjectImpactDetector, PhysGrabCart> _detectorCart; private static FieldRef<ValuableObject, float> _dollarValue; private static FieldRef<ValuableObject, bool> _dollarValueReady; private static FieldRef<ItemEquippable, bool> _equipping; private static FieldRef<ItemEquippable, bool> _unequipping; private static FieldRef<CosmeticWorldObject, bool> _exploding; private static FieldRef<PhysGrabObjectImpactDetector, float> _inCartTimer; private static FieldInfo _boxClaims; internal static bool Ready { get; private set; } internal static void Resolve() { try { _cartEntries = AccessTools.FieldRefAccess<PhysGrabInCart, List<CartObject>>("inCartObjects"); _detectorCart = AccessTools.FieldRefAccess<PhysGrabObjectImpactDetector, PhysGrabCart>("currentCart"); _dollarValue = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueCurrent"); Ready = _cartEntries != null && _detectorCart != null && _dollarValue != null; } catch (Exception ex) { Ready = false; Plugin.Log.LogError((object)("Required game fields could not be bound: " + ex.Message)); } if (!Ready) { Plugin.Log.LogError((object)"Carts will stay vanilla - the game was probably updated."); return; } _dollarValueReady = Optional<ValuableObject, bool>("dollarValueSet"); _equipping = Optional<ItemEquippable, bool>("isEquipping"); _unequipping = Optional<ItemEquippable, bool>("isUnequipping"); _exploding = Optional<CosmeticWorldObject, bool>("exploding"); _inCartTimer = Optional<PhysGrabObjectImpactDetector, float>("timerInCart"); _boxClaims = AccessTools.Field(typeof(ItemValuableBox), "claimedValuables"); } internal static List<CartObject> CartEntries(PhysGrabInCart zone) { if (!Object.op_Implicit((Object)(object)zone)) { return null; } return _cartEntries.Invoke(zone); } internal static PhysGrabCart CartOf(PhysGrabObjectImpactDetector detector) { if (!Object.op_Implicit((Object)(object)detector)) { return null; } return _detectorCart.Invoke(detector); } internal static int DollarValue(ValuableObject valuable) { if (!Object.op_Implicit((Object)(object)valuable)) { return 0; } return (int)_dollarValue.Invoke(valuable); } internal static bool DollarValueReady(ValuableObject valuable) { if (_dollarValueReady != null) { return _dollarValueReady.Invoke(valuable); } return true; } internal static bool InEquipTransition(ItemEquippable equip) { if (_equipping == null || !_equipping.Invoke(equip)) { if (_unequipping != null) { return _unequipping.Invoke(equip); } return false; } return true; } internal static void HoldInCart(PhysGrabObjectImpactDetector detector, PhysGrabCart cart, float seconds) { if (Object.op_Implicit((Object)(object)detector) && _inCartTimer != null) { _detectorCart.Invoke(detector) = cart; _inCartTimer.Invoke(detector) = seconds; } } internal static bool IsExploding(CosmeticWorldObject cosmetic) { if (_exploding != null) { return _exploding.Invoke(cosmetic); } return false; } internal static bool IsClaimedByValuableBox(PhysGrabObject item) { if (_boxClaims == null) { return false; } try { return _boxClaims.GetValue(null) is HashSet<PhysGrabObject> hashSet && hashSet.Contains(item); } catch (Exception) { return false; } } private static FieldRef<T, F> Optional<T, F>(string field) where T : class { try { return AccessTools.FieldRefAccess<T, F>(field); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Optional field " + typeof(T).Name + "." + field + " not found, skipping that check: " + ex.Message)); return null; } } } internal static class NoisyLoot { internal static Quaternion RestOffset(PhysGrabObject item) { //IL_0047: 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_0027: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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) BabyHeadValuable component = ((Component)item).GetComponent<BabyHeadValuable>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.head)) { return Quaternion.FromToRotation(Quaternion.Inverse(((Component)item).transform.rotation) * component.head.up, Vector3.forward); } return Quaternion.identity; } internal static void Hush(PhysGrabObject item) { PhoneValuable component = ((Component)item).GetComponent<PhoneValuable>(); if (Object.op_Implicit((Object)(object)component)) { component.PickUp(); } } } internal static class PatchInstaller { internal static void InstallAll(Harmony harmony) { if (!GameAccess.Ready) { Plugin.Log.LogError((object)"Game access is not ready, no patches installed."); } else if (!Apply(harmony, "Cart screen total (ValueScreen.UpdateValue)", AccessTools.Method(typeof(ValueScreen), "UpdateValue", (Type[])null, (Type[])null), Method(typeof(CartScreenTotal), "Prefix"))) { Plugin.Log.LogError((object)"Cart screen patch failed, so carts are left vanilla."); } else { Apply(harmony, "Cart vault attach (PhysGrabCart.Start)", AccessTools.Method(typeof(PhysGrabCart), "Start", (Type[])null, (Type[])null), null, Method(typeof(CartSpawnHook), "Postfix")); } } private static bool Apply(Harmony harmony, string label, MethodBase target, HarmonyMethod prefix = null, HarmonyMethod postfix = null) { if (target == null) { Plugin.Log.LogWarning((object)("Target not found, skipping - " + label)); return false; } try { harmony.Patch(target, prefix, postfix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("Installed - " + label)); return true; } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to install - " + label + ": " + ex.Message)); return false; } } private static HarmonyMethod Method(Type type, string name) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null); if (methodInfo == null) { throw new InvalidOperationException("Patch method not found: " + type.Name + "." + name); } return new HarmonyMethod(methodInfo); } } internal static class RunGate { private static int _frame = -1; private static bool _runLevel; private static bool _generated; private static bool _host; private static bool _playing; internal static bool IsRunLevel { get { Refresh(); return _runLevel; } } internal static bool InRunLevel { get { Refresh(); if (_runLevel) { return _generated; } return false; } } internal static bool IsHost { get { Refresh(); return _host; } } internal static bool Playing { get { Refresh(); if (_runLevel && _generated) { return _playing; } return false; } } private static void Refresh() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Invalid comparison between Unknown and I4 int frameCount = Time.frameCount; if (frameCount == _frame) { return; } _frame = frameCount; _runLevel = false; _generated = false; _host = false; _playing = false; try { if (!((Object)(object)RunManager.instance == (Object)null) && !((Object)(object)RunManager.instance.levelCurrent == (Object)null) && !SemiFunc.MenuLevel() && SemiFunc.RunIsLevel()) { _runLevel = true; _generated = (Object)(object)LevelGenerator.Instance != (Object)null && LevelGenerator.Instance.Generated; _host = SemiFunc.IsMasterClientOrSingleplayer(); _playing = (Object)(object)GameDirector.instance != (Object)null && (int)GameDirector.instance.currentState == 2; } } catch (Exception) { _runLevel = false; _generated = false; _host = false; _playing = false; } } } internal static class ShrinkBridge { internal const string ScalerCoreGuid = "Vippy.ScalerCore"; private static readonly bool Present = Chainloader.PluginInfos.ContainsKey("Vippy.ScalerCore"); internal static void Shrink(PhysGrabObject item) { if (!Present) { return; } try { ScalerCoreCalls.Shrink(((Component)item).gameObject); } catch (Exception ex) { Plugin.Log.LogWarning((object)("ScalerCore shrink failed on '" + ((Object)item).name + "': " + ex.Message)); } } internal static void Restore(PhysGrabObject item) { if (!Present) { return; } try { ScalerCoreCalls.Restore(((Component)item).gameObject); } catch (Exception ex) { Plugin.Log.LogWarning((object)("ScalerCore restore failed on '" + ((Object)item).name + "': " + ex.Message)); } } } internal static class ScalerCoreCalls { private const float VaultFactor = 0.01f; [MethodImpl(MethodImplOptions.NoInlining)] internal static void Shrink(GameObject target) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) ScaleController controller = ScaleManager.GetController(target); if (!((Object)(object)controller == (Object)null)) { ScaleOptions val = ScaleOptions.Default; val.Factor = 0.01f; val.Speed = 0.5f; val.RestoreSpeed = 0.2f; val.Duration = 0f; val.AllowedTargets = (ScaleTargets)15; val.SuppressValueDropExpand = true; val.SuppressImpactFlash = true; val.SuppressCameraShake = true; val.IgnoreBonkExpand = true; val.RejectExternalApply = true; if (controller.IsScaled && Mathf.Approximately(controller.CurrentOptions.Factor, 0.01f)) { ScaleManager.ForceUpdateOptions(target, val); } else { ScaleManager.ForceApply(target, val); } } } [MethodImpl(MethodImplOptions.NoInlining)] internal static void Restore(GameObject target) { if (ScaleManager.IsScaled(target)) { ScaleManager.ForceRestore(target); } } } internal sealed class StashMask : MonoBehaviour { private struct Saved<T> where T : Component { public T Part; public bool State; } private const float RescanInterval = 2f; private readonly List<Saved<Collider>> _colliders = new List<Saved<Collider>>(); private readonly List<Saved<Renderer>> _renderers = new List<Saved<Renderer>>(); private readonly List<Saved<Light>> _lights = new List<Saved<Light>>(); private readonly List<Saved<PhysGrabObjectComponentInsideBoxChecker>> _scanners = new List<Saved<PhysGrabObjectComponentInsideBoxChecker>>(); private readonly HashSet<int> _recorded = new HashSet<int>(); private PhysGrabObject _body; private bool _frozen; private bool _wasKinematic; private RigidbodyInterpolation _interpolation; private float _nextRescan; internal bool Engaged { get; private set; } private PhysGrabObject Body { get { if (!Object.op_Implicit((Object)(object)_body)) { _body = ((Component)this).GetComponent<PhysGrabObject>(); } return _body; } } internal void Engage(bool freezePhysics) { if (!Engaged) { Engaged = true; Record(); _nextRescan = Time.time + 2f; } if (freezePhysics && !_frozen) { Freeze(); } Enforce(); } internal void Disengage(bool thawPhysics) { if (!Engaged) { return; } Engaged = false; foreach (Saved<Collider> collider in _colliders) { if (Object.op_Implicit((Object)(object)collider.Part)) { collider.Part.enabled = collider.State; } } foreach (Saved<Renderer> renderer in _renderers) { if (Object.op_Implicit((Object)(object)renderer.Part)) { renderer.Part.forceRenderingOff = renderer.State; } } foreach (Saved<Light> light in _lights) { if (Object.op_Implicit((Object)(object)light.Part)) { ((Behaviour)light.Part).enabled = light.State; } } foreach (Saved<PhysGrabObjectComponentInsideBoxChecker> scanner in _scanners) { if (Object.op_Implicit((Object)(object)scanner.Part)) { ((Behaviour)scanner.Part).enabled = scanner.State; } } _colliders.Clear(); _renderers.Clear(); _lights.Clear(); _scanners.Clear(); _recorded.Clear(); if (_frozen && thawPhysics) { Thaw(); } _frozen = false; } private void LateUpdate() { if (Engaged) { if (Time.time >= _nextRescan) { _nextRescan = Time.time + 2f; Record(); } Enforce(); } } private void Record() { Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (_recorded.Add(((Object)val).GetInstanceID())) { _colliders.Add(new Saved<Collider> { Part = val, State = val.enabled }); } } Renderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren2) { if (_recorded.Add(((Object)val2).GetInstanceID())) { _renderers.Add(new Saved<Renderer> { Part = val2, State = val2.forceRenderingOff }); } } Light[] componentsInChildren3 = ((Component)this).GetComponentsInChildren<Light>(true); foreach (Light val3 in componentsInChildren3) { if (_recorded.Add(((Object)val3).GetInstanceID())) { _lights.Add(new Saved<Light> { Part = val3, State = ((Behaviour)val3).enabled }); } } PhysGrabObjectComponentInsideBoxChecker[] componentsInChildren4 = ((Component)this).GetComponentsInChildren<PhysGrabObjectComponentInsideBoxChecker>(true); foreach (PhysGrabObjectComponentInsideBoxChecker val4 in componentsInChildren4) { if (_recorded.Add(((Object)val4).GetInstanceID())) { _scanners.Add(new Saved<PhysGrabObjectComponentInsideBoxChecker> { Part = val4, State = ((Behaviour)val4).enabled }); } } } private void Enforce() { //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) foreach (Saved<Collider> collider in _colliders) { if (Object.op_Implicit((Object)(object)collider.Part) && collider.Part.enabled) { collider.Part.enabled = false; } } foreach (Saved<Renderer> renderer in _renderers) { if (Object.op_Implicit((Object)(object)renderer.Part) && !renderer.Part.forceRenderingOff) { renderer.Part.forceRenderingOff = true; } } foreach (Saved<Light> light in _lights) { if (Object.op_Implicit((Object)(object)light.Part) && ((Behaviour)light.Part).enabled) { ((Behaviour)light.Part).enabled = false; } } foreach (Saved<PhysGrabObjectComponentInsideBoxChecker> scanner in _scanners) { if (Object.op_Implicit((Object)(object)scanner.Part) && ((Behaviour)scanner.Part).enabled) { ((Behaviour)scanner.Part).enabled = false; } } if (_frozen) { Rigidbody val = (Object.op_Implicit((Object)(object)Body) ? Body.rb : null); if (Object.op_Implicit((Object)(object)val) && !val.isKinematic) { val.velocity = Vector3.zero; val.angularVelocity = Vector3.zero; val.isKinematic = true; } } } private void Freeze() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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) Rigidbody val = (Object.op_Implicit((Object)(object)Body) ? Body.rb : null); if (Object.op_Implicit((Object)(object)val)) { _wasKinematic = val.isKinematic; _interpolation = val.interpolation; if (!val.isKinematic) { val.velocity = Vector3.zero; val.angularVelocity = Vector3.zero; } val.isKinematic = true; val.interpolation = (RigidbodyInterpolation)0; _frozen = true; } } private void Thaw() { //IL_0027: 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) Rigidbody val = (Object.op_Implicit((Object)(object)Body) ? Body.rb : null); if (Object.op_Implicit((Object)(object)val)) { val.interpolation = _interpolation; val.isKinematic = _wasKinematic; if (!val.isKinematic) { val.velocity = Vector3.zero; val.angularVelocity = Vector3.zero; val.WakeUp(); } } } } internal static class VaultNet { private const byte EventCode = 186; private const int Signature = 1346590292; private const byte KindCartState = 1; private const byte KindSnapshotRequest = 2; private const float RequestInterval = 1f; private static readonly Dictionary<int, float> NextAnswerByActor = new Dictionary<int, float>(); private static bool _listening; private static float _nextRequest; internal static void EnsureListening() { if (_listening) { return; } try { PhotonNetwork.NetworkingClient.EventReceived += OnEvent; _listening = true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not subscribe to cart sync events: " + ex.Message)); } } internal static void PublishCart(CartVault vault, int targetActor) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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) try { if (!((Object)(object)vault == (Object)null) && vault.ViewId != 0 && SemiFunc.IsMultiplayer() && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) { object[] array = new object[4] { 1346590292, (byte)1, vault.ViewId, vault.ExportViewIds() }; object obj; if (targetActor <= 0) { obj = (object)new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; } else { RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { targetActor }; obj = val; } RaiseEventOptions val2 = (RaiseEventOptions)obj; PhotonNetwork.RaiseEvent((byte)186, (object)array, val2, SendOptions.SendReliable); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not send cart state: " + ex.Message)); } } internal static void RequestSnapshot() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) try { if (SemiFunc.IsMultiplayer() && PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient) { float unscaledTime = Time.unscaledTime; if (!(unscaledTime < _nextRequest)) { _nextRequest = unscaledTime + 1f; object[] array = new object[4] { 1346590292, (byte)2, 0, new int[0] }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)2 }; PhotonNetwork.RaiseEvent((byte)186, (object)array, val, SendOptions.SendReliable); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not request cart states: " + ex.Message)); } } internal static void Reset() { NextAnswerByActor.Clear(); _nextRequest = 0f; } private static void OnEvent(EventData photonEvent) { if (photonEvent.Code != 186 || !(photonEvent.CustomData is object[] array) || array.Length < 4 || !(array[0] is int num) || num != 1346590292 || !(array[1] is byte b)) { return; } try { switch (b) { case 1: ReceiveCartState(photonEvent.Sender, array); break; case 2: AnswerSnapshot(photonEvent.Sender); break; } } catch (Exception ex) { Plugin.Log.LogWarning((object)$"Bad cart sync event from actor {photonEvent.Sender}: {ex.Message}"); } } private static void ReceiveCartState(int sender, object[] content) { if (PhotonNetwork.IsMasterClient) { return; } Player masterClient = PhotonNetwork.MasterClient; if (masterClient != null && sender == masterClient.ActorNumber && content[2] is int num && num != 0) { int[] itemViewIds = (content[3] as int[]) ?? new int[0]; CartVault cartVault = VaultRegistry.FindByView(num); if ((Object)(object)cartVault != (Object)null) { cartVault.ApplyMirror(itemViewIds); } else { VaultRegistry.StorePendingMirror(num, itemViewIds); } } } private static void AnswerSnapshot(int sender) { if (!PhotonNetwork.IsMasterClient || sender <= 0) { return; } float unscaledTime = Time.unscaledTime; if (NextAnswerByActor.TryGetValue(sender, out var value) && unscaledTime < value) { return; } NextAnswerByActor[sender] = unscaledTime + 1f; foreach (CartVault item in VaultRegistry.All) { if ((Object)(object)item != (Object)null) { PublishCart(item, sender); } } } } internal static class VaultRegistry { private static readonly List<CartVault> Vaults = new List<CartVault>(); private static readonly Dictionary<int, CartVault> ByScreen = new Dictionary<int, CartVault>(); private static readonly Dictionary<int, CartVault> ByView = new Dictionary<int, CartVault>(); private static readonly Dictionary<int, CartVault> Holders = new Dictionary<int, CartVault>(); private static readonly Dictionary<int, float> IntakeLocks = new Dictionary<int, float>(); private static readonly Dictionary<int, int[]> PendingMirrors = new Dictionary<int, int[]>(); internal static IReadOnlyList<CartVault> All => Vaults; internal static void Register(CartVault vault, ValueScreen screen) { if (!Vaults.Contains(vault)) { Vaults.Add(vault); } if (Object.op_Implicit((Object)(object)screen)) { ByScreen[((Object)screen).GetInstanceID()] = vault; } if (vault.ViewId != 0) { ByView[vault.ViewId] = vault; } } internal static void Unregister(CartVault vault) { Vaults.Remove(vault); RemoveValue(ByScreen, vault); RemoveValue(ByView, vault); RemoveValue(Holders, vault); } internal static CartVault FindByScreen(ValueScreen screen) { if (!Object.op_Implicit((Object)(object)screen) || !ByScreen.TryGetValue(((Object)screen).GetInstanceID(), out var value)) { return null; } return value; } internal static CartVault FindByView(int viewId) { if (viewId == 0 || !ByView.TryGetValue(viewId, out var value)) { return null; } return value; } internal static bool IsHeld(PhysGrabObject item) { return Holders.ContainsKey(((Object)item).GetInstanceID()); } internal static void MarkHeld(PhysGrabObject item, CartVault vault) { Holders[((Object)item).GetInstanceID()] = vault; } internal static void ClearHeld(int itemKey) { Holders.Remove(itemKey); } internal static bool IsIntakeLocked(PhysGrabObject item, float now) { int instanceID = ((Object)item).GetInstanceID(); if (!IntakeLocks.TryGetValue(instanceID, out var value)) { return false; } if (now < value) { return true; } IntakeLocks.Remove(instanceID); return false; } internal static void LockIntake(PhysGrabObject item, float until) { IntakeLocks[((Object)item).GetInstanceID()] = until; } internal static void StorePendingMirror(int cartViewId, int[] itemViewIds) { PendingMirrors[cartViewId] = itemViewIds; } internal static int[] TakePendingMirror(int cartViewId) { if (!PendingMirrors.TryGetValue(cartViewId, out var value)) { return null; } PendingMirrors.Remove(cartViewId); return value; } internal static void Reset() { Vaults.Clear(); ByScreen.Clear(); ByView.Clear(); Holders.Clear(); IntakeLocks.Clear(); PendingMirrors.Clear(); VaultNet.Reset(); } private static void RemoveValue(Dictionary<int, CartVault> map, CartVault vault) { List<int> list = null; foreach (KeyValuePair<int, CartVault> item in map) { if (item.Value == vault) { if (list == null) { list = new List<int>(); } list.Add(item.Key); } } if (list == null) { return; } foreach (int item2 in list) { map.Remove(item2); } } } }