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 ShopItemClone v4.0.0
ShopItemClone.dll
Decompiled 5 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("REPOJP")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("zabuMod")] [assembly: AssemblyTitle("zabuMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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; } } } namespace REPOJP.ShopItemClone { [BepInPlugin("REPOJP.ShopItemClone", "Shop Item Clone", "4.0.0")] public sealed class ShopItemClonePlugin : BaseUnityPlugin { public const string PluginGuid = "REPOJP.ShopItemClone"; public const string PluginName = "Shop Item Clone"; public const string PluginVersion = "4.0.0"; internal static ManualLogSource LogSource; internal static ShopItemClonePlugin Instance; internal static ConfigEntry<bool> CloneUpgrades; internal static ConfigEntry<bool> CloneMeleeWeapons; internal static ConfigEntry<bool> CloneGuns; internal static ConfigEntry<bool> CloneCarts; internal static ConfigEntry<bool> ClonePocketCarts; internal static ConfigEntry<bool> CloneDrones; internal static ConfigEntry<bool> CloneOrbs; internal static ConfigEntry<bool> CloneHealthPacks; internal static ConfigEntry<bool> CloneExplosives; internal static ConfigEntry<bool> CloneEnergyCrystals; internal static ConfigEntry<bool> CloneTrackers; internal static ConfigEntry<bool> CloneTools; internal static ConfigEntry<bool> CloneVehicles; internal static ConfigEntry<bool> CloneLaunchers; internal static ConfigEntry<bool> PreventCloneInExtractionPoint; internal static ConfigEntry<int> MaxUpgradesPerShop; internal static ConfigEntry<int> MaxMeleeWeaponsPerShop; internal static ConfigEntry<int> MaxGunsPerShop; internal static ConfigEntry<int> MaxCartsPerShop; internal static ConfigEntry<int> MaxPocketCartsPerShop; internal static ConfigEntry<int> MaxDronesPerShop; internal static ConfigEntry<int> MaxOrbsPerShop; internal static ConfigEntry<int> MaxHealthPacksPerShop; internal static ConfigEntry<int> MaxExplosivesPerShop; internal static ConfigEntry<int> MaxEnergyCrystalsPerShop; internal static ConfigEntry<int> MaxTrackersPerShop; internal static ConfigEntry<int> MaxToolsPerShop; internal static ConfigEntry<int> MaxVehiclesPerShop; internal static ConfigEntry<int> MaxLaunchersPerShop; internal static ConfigEntry<float> MinCloneIntervalSeconds; internal static ConfigEntry<bool> RequireImpactThreshold; internal static ConfigEntry<float> MinimumImpactForce; internal static ConfigEntry<bool> EnableDebugLog; private Harmony harmony; private void Awake() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown try { Instance = this; LogSource = ((BaseUnityPlugin)this).Logger; ((Component)this).gameObject.transform.parent = null; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); BindConfig(); ShopItemCloneRuntime.EnsureCreated(); harmony = new Harmony("REPOJP.ShopItemClone"); harmony.PatchAll(typeof(ShopItemClonePlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Shop Item Clone 4.0.0 loaded"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Failed to initialize Shop Item Clone\n" + ex)); } } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } private void BindConfig() { //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown CloneUpgrades = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Upgrades", true, "Clone item upgrades and player upgrades. アップグレード系アイテムの複製"); CloneMeleeWeapons = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Melee Weapons", true, "Clone melee weapons. 近接武器の複製"); CloneGuns = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Guns", true, "Clone guns. 銃の複製"); CloneCarts = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Carts", true, "Clone carts. カートの複製"); ClonePocketCarts = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Pocket Carts", true, "Clone pocket carts. ポケットカートの複製"); CloneDrones = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Drones", true, "Clone drones. ドローンの複製"); CloneOrbs = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Orbs", true, "Clone orbs. オーブの複製"); CloneHealthPacks = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Health Packs", true, "Clone health packs. ヘルスパックの複製"); CloneExplosives = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Explosives", true, "Clone grenades and mines. グレネードと地雷の複製"); CloneEnergyCrystals = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Energy Crystals", true, "Clone energy crystals. エナジークリスタルの複製"); CloneTrackers = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Trackers", true, "Clone trackers. トラッカー系アイテムの複製"); CloneTools = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Tools", true, "Clone tools added in v0.4.0 and later. v0.4.0以降のツール系アイテムの複製"); CloneVehicles = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Vehicles", true, "Clone vehicles added in v0.4.0 and later. v0.4.0以降の乗り物系アイテムの複製"); CloneLaunchers = ((BaseUnityPlugin)this).Config.Bind<bool>("Category Toggle", "Clone Launchers", true, "Clone launchers and staff-like launcher items. ランチャーや杖系アイテムの複製"); PreventCloneInExtractionPoint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Prevent Clone In Extraction Point", true, "Prevent cloning while the held item is inside the extraction point. 納品所内にある手持ちアイテムの複製を禁止"); MinCloneIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Min Clone Interval Seconds", 0.15f, new ConfigDescription("Minimum seconds between clones from the same source item. 同じ元アイテムから次に複製できるまでの最小秒数", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); RequireImpactThreshold = ((BaseUnityPlugin)this).Config.Bind<bool>("Impact Requirement", "Require Impact Threshold", true, "Require impact force threshold instead of cloning on any ground contact. 地面接触だけでなく一定以上の衝撃を必要にする"); MinimumImpactForce = ((BaseUnityPlugin)this).Config.Bind<float>("Impact Requirement", "Minimum Impact Force", 60f, new ConfigDescription("Minimum PhysGrabObjectImpactDetector impact force required for cloning. 20=Light, 80=Medium, 150=Heavy. 複製に必要な衝撃値 20=軽 80=中 150=強", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>())); MaxUpgradesPerShop = BindMax("Max Upgrades Per Shop", 0, "Max upgrade clones per shop. 0 means unlimited. ショップごとのアップグレード複製上限 0は無制限"); MaxMeleeWeaponsPerShop = BindMax("Max Melee Weapons Per Shop", 0, "Max melee weapon clones per shop. 0 means unlimited. ショップごとの近接武器複製上限 0は無制限"); MaxGunsPerShop = BindMax("Max Guns Per Shop", 0, "Max gun clones per shop. 0 means unlimited. ショップごとの銃複製上限 0は無制限"); MaxCartsPerShop = BindMax("Max Carts Per Shop", 5, "Max cart clones per shop. 0 means unlimited. ショップごとのカート複製上限 0は無制限"); MaxPocketCartsPerShop = BindMax("Max Pocket Carts Per Shop", 5, "Max pocket cart clones per shop. 0 means unlimited. ショップごとのポケットカート複製上限 0は無制限"); MaxDronesPerShop = BindMax("Max Drones Per Shop", 0, "Max drone clones per shop. 0 means unlimited. ショップごとのドローン複製上限 0は無制限"); MaxOrbsPerShop = BindMax("Max Orbs Per Shop", 0, "Max orb clones per shop. 0 means unlimited. ショップごとのオーブ複製上限 0は無制限"); MaxHealthPacksPerShop = BindMax("Max Health Packs Per Shop", 0, "Max health pack clones per shop. 0 means unlimited. ショップごとのヘルスパック複製上限 0は無制限"); MaxExplosivesPerShop = BindMax("Max Explosives Per Shop", 0, "Max explosive clones per shop. 0 means unlimited. ショップごとの爆破物複製上限 0は無制限"); MaxEnergyCrystalsPerShop = BindMax("Max Energy Crystals Per Shop", 0, "Max energy crystal clones per shop. 0 means unlimited. ショップごとのエナジークリスタル複製上限 0は無制限"); MaxTrackersPerShop = BindMax("Max Trackers Per Shop", 0, "Max tracker clones per shop. 0 means unlimited. ショップごとのトラッカー複製上限 0は無制限"); MaxToolsPerShop = BindMax("Max Tools Per Shop", 0, "Max tool clones per shop. 0 means unlimited. ショップごとのツール複製上限 0は無制限"); MaxVehiclesPerShop = BindMax("Max Vehicles Per Shop", 0, "Max vehicle clones per shop. 0 means unlimited. ショップごとの乗り物複製上限 0は無制限"); MaxLaunchersPerShop = BindMax("Max Launchers Per Shop", 0, "Max launcher clones per shop. 0 means unlimited. ショップごとのランチャー複製上限 0は無制限"); EnableDebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Enable Debug Log", false, "Enable detailed clone decision logs. 詳細な複製判定ログを出力"); } private ConfigEntry<int> BindMax(string key, int defaultValue, string description) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<int>("Category Max Per Shop", key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); } internal static void LogDebug(string message) { if (EnableDebugLog != null && EnableDebugLog.Value && LogSource != null) { LogSource.LogInfo((object)message); } } } internal sealed class ShopItemCloneRuntime : MonoBehaviour { private sealed class ContactState { internal PhysGrabObject Source; internal bool Latched; internal float LastValidGroundContactTime; internal float LastCloneTime; } [CompilerGenerated] private sealed class <FinalizeCloneAfterStart>d__52 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public PhysGrabObject source; public ItemAttributes sourceItem; public GameObject cloneObject; public ShopItemCloneRuntime <>4__this; private ItemAttributes <cloneItem>5__1; private PhotonView <clonePhotonView>5__2; private Rigidbody <sourceRb>5__3; private Rigidbody <cloneRb>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FinalizeCloneAfterStart>d__52(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <cloneItem>5__1 = null; <clonePhotonView>5__2 = null; <sourceRb>5__3 = null; <cloneRb>5__4 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = null; <>1__state = 2; return true; case 2: <>1__state = -1; if ((Object)(object)source == (Object)null || (Object)(object)sourceItem == (Object)null || (Object)(object)cloneObject == (Object)null) { return false; } <cloneItem>5__1 = cloneObject.GetComponent<ItemAttributes>(); <clonePhotonView>5__2 = cloneObject.GetComponent<PhotonView>(); <sourceRb>5__3 = source.rb; <cloneRb>5__4 = cloneObject.GetComponent<Rigidbody>(); if ((Object)(object)<cloneItem>5__1 == (Object)null) { return false; } TryApplyInitialMotion(<sourceRb>5__3, <cloneRb>5__4); CopyItemValue(sourceItem, <cloneItem>5__1, <clonePhotonView>5__2); CopyToggleState(source, cloneObject); CopyBatteryState(source, cloneObject, <clonePhotonView>5__2); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <IgnoreCloneCollisionTemporary>d__56 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public GameObject sourceObject; public GameObject cloneObject; public float duration; public ShopItemCloneRuntime <>4__this; private Collider[] <sourceColliders>5__1; private Collider[] <cloneColliders>5__2; private int <i>5__3; private Collider <sourceCollider>5__4; private int <j>5__5; private Collider <cloneCollider>5__6; private int <i>5__7; private Collider <sourceCollider>5__8; private int <j>5__9; private Collider <cloneCollider>5__10; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <IgnoreCloneCollisionTemporary>d__56(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <sourceColliders>5__1 = null; <cloneColliders>5__2 = null; <sourceCollider>5__4 = null; <cloneCollider>5__6 = null; <sourceCollider>5__8 = null; <cloneCollider>5__10 = null; <>1__state = -2; } private bool MoveNext() { //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)sourceObject == (Object)null || (Object)(object)cloneObject == (Object)null) { return false; } <sourceColliders>5__1 = sourceObject.GetComponentsInChildren<Collider>(true); <cloneColliders>5__2 = cloneObject.GetComponentsInChildren<Collider>(true); <i>5__3 = 0; while (<i>5__3 < <sourceColliders>5__1.Length) { <sourceCollider>5__4 = <sourceColliders>5__1[<i>5__3]; if (!((Object)(object)<sourceCollider>5__4 == (Object)null)) { <j>5__5 = 0; while (<j>5__5 < <cloneColliders>5__2.Length) { <cloneCollider>5__6 = <cloneColliders>5__2[<j>5__5]; if (!((Object)(object)<cloneCollider>5__6 == (Object)null)) { Physics.IgnoreCollision(<sourceCollider>5__4, <cloneCollider>5__6, true); <cloneCollider>5__6 = null; } <j>5__5++; } <sourceCollider>5__4 = null; } <i>5__3++; } <>2__current = (object)new WaitForSeconds(duration); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)sourceObject == (Object)null || (Object)(object)cloneObject == (Object)null) { return false; } <i>5__7 = 0; while (<i>5__7 < <sourceColliders>5__1.Length) { <sourceCollider>5__8 = <sourceColliders>5__1[<i>5__7]; if (!((Object)(object)<sourceCollider>5__8 == (Object)null)) { <j>5__9 = 0; while (<j>5__9 < <cloneColliders>5__2.Length) { <cloneCollider>5__10 = <cloneColliders>5__2[<j>5__9]; if (!((Object)(object)<cloneCollider>5__10 == (Object)null)) { Physics.IgnoreCollision(<sourceCollider>5__8, <cloneCollider>5__10, false); <cloneCollider>5__10 = null; } <j>5__9++; } <sourceCollider>5__8 = null; } <i>5__7++; } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const float DefaultCloneHeightOffset = 0.01f; private const float CartCloneHeightOffset = 1f; private const float VehicleCloneHeightOffset = 1f; private const float CloneCollisionIgnoreSeconds = 0.2f; private const float CloneImpactDisableSeconds = 0.2f; private const float RearmNoContactSeconds = 0.08f; private const float GroundNormalMinY = 0.35f; private const string CategoryUpgrades = "Upgrades"; private const string CategoryMeleeWeapons = "MeleeWeapons"; private const string CategoryGuns = "Guns"; private const string CategoryCarts = "Carts"; private const string CategoryPocketCarts = "PocketCarts"; private const string CategoryDrones = "Drones"; private const string CategoryOrbs = "Orbs"; private const string CategoryHealthPacks = "HealthPacks"; private const string CategoryExplosives = "Explosives"; private const string CategoryEnergyCrystals = "EnergyCrystals"; private const string CategoryTrackers = "Trackers"; private const string CategoryTools = "Tools"; private const string CategoryVehicles = "Vehicles"; private const string CategoryLaunchers = "Launchers"; private const string CategoryUnknown = "Unknown"; private static ShopItemCloneRuntime instance; private static readonly FieldInfo ItemValueField = AccessTools.Field(typeof(ItemAttributes), "value"); private static readonly FieldInfo InExtractionPointField = AccessTools.Field(typeof(RoomVolumeCheck), "inExtractionPoint"); private static readonly FieldInfo ImpactForceField = AccessTools.Field(typeof(PhysGrabObjectImpactDetector), "impactForce"); private static readonly MethodInfo BatteryFullPercentChangeMethod = AccessTools.Method(typeof(ItemBattery), "BatteryFullPercentChange", (Type[])null, (Type[])null); private readonly Dictionary<int, ContactState> contactStates = new Dictionary<int, ContactState>(); private readonly Dictionary<string, int> categoryCloneCounts = new Dictionary<string, int>(); private bool wasShopMainPhase; internal static ShopItemCloneRuntime Instance => instance; internal static void EnsureCreated() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)instance != (Object)null)) { GameObject val = new GameObject("ShopItemCloneRuntime"); val.transform.parent = null; ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); instance = val.AddComponent<ShopItemCloneRuntime>(); } } private void Update() { try { bool flag = IsShopMainPhase(); if (flag && !wasShopMainPhase) { ResetShopCounters(); } else if (!flag && wasShopMainPhase) { ResetShopCounters(); contactStates.Clear(); } wasShopMainPhase = flag; if (contactStates.Count == 0) { return; } float unscaledTime = Time.unscaledTime; List<int> removeKeys = null; foreach (KeyValuePair<int, ContactState> contactState in contactStates) { ContactState value = contactState.Value; PhysGrabObject source = value.Source; if ((Object)(object)source == (Object)null) { AddRemoveKey(ref removeKeys, contactState.Key); continue; } bool flag2 = IsActuallyHeld(source); bool flag3 = IsShopMainPhase(); if (!flag2 || !flag3) { AddRemoveKey(ref removeKeys, contactState.Key); } else if (unscaledTime - value.LastValidGroundContactTime > 0.08f) { value.Latched = false; } } if (removeKeys != null) { for (int i = 0; i < removeKeys.Count; i++) { contactStates.Remove(removeKeys[i]); } } } catch (Exception ex) { if (ShopItemClonePlugin.LogSource != null) { ShopItemClonePlugin.LogSource.LogError((object)("Failure: Runtime update failed\n" + ex)); } } } private static void AddRemoveKey(ref List<int> removeKeys, int key) { if (removeKeys == null) { removeKeys = new List<int>(); } removeKeys.Add(key); } internal void OnImpactStay(PhysGrabObjectImpactDetector detector, Collision collision) { try { if ((Object)(object)detector == (Object)null || collision == null || !IsHostAuthority() || !IsShopMainPhase()) { return; } PhysGrabObject component = ((Component)detector).GetComponent<PhysGrabObject>(); if ((Object)(object)component == (Object)null) { return; } ItemAttributes component2 = ((Component)component).GetComponent<ItemAttributes>(); if ((Object)(object)component2 == (Object)null || (Object)(object)component2.item == (Object)null || (Object)(object)((Component)component).GetComponent<ValuableObject>() != (Object)null) { return; } string categoryKey = GetCategoryKey(component2); if (!IsCategoryEnabled(categoryKey) || !IsActuallyHeld(component) || (ShopItemClonePlugin.PreventCloneInExtractionPoint != null && ShopItemClonePlugin.PreventCloneInExtractionPoint.Value && IsInsideExtractionPoint(component)) || !IsGroundLikeEnvironmentCollision(collision)) { return; } int instanceID = ((Object)component).GetInstanceID(); if (!contactStates.TryGetValue(instanceID, out var value)) { value = new ContactState(); value.Source = component; value.LastCloneTime = -999f; contactStates[instanceID] = value; } float num = (value.LastValidGroundContactTime = Time.unscaledTime); if (value.Latched) { return; } float num2 = Mathf.Clamp(ShopItemClonePlugin.MinCloneIntervalSeconds.Value, 0f, 5f); if (num - value.LastCloneTime < num2) { return; } float impactForce = GetImpactForce(detector, collision); if (ShopItemClonePlugin.RequireImpactThreshold != null && ShopItemClonePlugin.RequireImpactThreshold.Value) { float num3 = Mathf.Clamp(ShopItemClonePlugin.MinimumImpactForce.Value, 0f, 200f); if (impactForce < num3) { ShopItemClonePlugin.LogDebug("Impact skipped category=" + categoryKey + " force=" + impactForce.ToString("0.00") + " required=" + num3.ToString("0.00")); return; } } if (!CanCloneCategoryThisShop(categoryKey)) { ShopItemClonePlugin.LogDebug("Category max skipped category=" + categoryKey); return; } value.Latched = true; value.LastCloneTime = num; CloneHeldShopItem(component, component2, categoryKey); } catch (Exception ex) { if (ShopItemClonePlugin.LogSource != null) { ShopItemClonePlugin.LogSource.LogError((object)("Failure: Impact handling failed\n" + ex)); } } } private static bool IsHostAuthority() { try { if (!GameManager.Multiplayer()) { return true; } } catch { if (!PhotonNetwork.InRoom) { return true; } } return PhotonNetwork.IsMasterClient; } private static bool IsShopMainPhase() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 try { if (!SemiFunc.RunIsShop()) { return false; } if ((Object)(object)GameDirector.instance == (Object)null) { return false; } return (int)GameDirector.instance.currentState == 2; } catch { return false; } } private static string GetCategoryKey(ItemAttributes itemAttributes) { if ((Object)(object)itemAttributes == (Object)null || (Object)(object)itemAttributes.item == (Object)null) { return "Unknown"; } string empty = string.Empty; try { empty = ((object)(itemType)(ref itemAttributes.item.itemType)).ToString(); } catch { empty = string.Empty; } if (empty == "item_upgrade" || empty == "player_upgrade") { return "Upgrades"; } switch (empty) { case "melee": return "MeleeWeapons"; case "gun": return "Guns"; case "cart": return "Carts"; case "pocket_cart": return "PocketCarts"; case "drone": return "Drones"; case "orb": return "Orbs"; case "healthPack": return "HealthPacks"; default: if (!(empty == "mine")) { return empty switch { "power_crystal" => "EnergyCrystals", "tracker" => "Trackers", "tool" => "Tools", "vehicle" => "Vehicles", "launcher" => "Launchers", _ => "Unknown", }; } goto case "grenade"; case "grenade": return "Explosives"; } } private static bool IsCategoryEnabled(string category) { return category switch { "Upgrades" => ShopItemClonePlugin.CloneUpgrades != null && ShopItemClonePlugin.CloneUpgrades.Value, "MeleeWeapons" => ShopItemClonePlugin.CloneMeleeWeapons != null && ShopItemClonePlugin.CloneMeleeWeapons.Value, "Guns" => ShopItemClonePlugin.CloneGuns != null && ShopItemClonePlugin.CloneGuns.Value, "Carts" => ShopItemClonePlugin.CloneCarts != null && ShopItemClonePlugin.CloneCarts.Value, "PocketCarts" => ShopItemClonePlugin.ClonePocketCarts != null && ShopItemClonePlugin.ClonePocketCarts.Value, "Drones" => ShopItemClonePlugin.CloneDrones != null && ShopItemClonePlugin.CloneDrones.Value, "Orbs" => ShopItemClonePlugin.CloneOrbs != null && ShopItemClonePlugin.CloneOrbs.Value, "HealthPacks" => ShopItemClonePlugin.CloneHealthPacks != null && ShopItemClonePlugin.CloneHealthPacks.Value, "Explosives" => ShopItemClonePlugin.CloneExplosives != null && ShopItemClonePlugin.CloneExplosives.Value, "EnergyCrystals" => ShopItemClonePlugin.CloneEnergyCrystals != null && ShopItemClonePlugin.CloneEnergyCrystals.Value, "Trackers" => ShopItemClonePlugin.CloneTrackers != null && ShopItemClonePlugin.CloneTrackers.Value, "Tools" => ShopItemClonePlugin.CloneTools != null && ShopItemClonePlugin.CloneTools.Value, "Vehicles" => ShopItemClonePlugin.CloneVehicles != null && ShopItemClonePlugin.CloneVehicles.Value, "Launchers" => ShopItemClonePlugin.CloneLaunchers != null && ShopItemClonePlugin.CloneLaunchers.Value, _ => false, }; } private bool CanCloneCategoryThisShop(string category) { int categoryMax = GetCategoryMax(category); if (categoryMax <= 0) { return true; } if (!categoryCloneCounts.TryGetValue(category, out var value)) { value = 0; } return value < categoryMax; } private void RegisterCategoryClone(string category) { if (!categoryCloneCounts.TryGetValue(category, out var value)) { value = 0; } categoryCloneCounts[category] = value + 1; } private static int GetCategoryMax(string category) { return category switch { "Upgrades" => ShopItemClonePlugin.MaxUpgradesPerShop.Value, "MeleeWeapons" => ShopItemClonePlugin.MaxMeleeWeaponsPerShop.Value, "Guns" => ShopItemClonePlugin.MaxGunsPerShop.Value, "Carts" => ShopItemClonePlugin.MaxCartsPerShop.Value, "PocketCarts" => ShopItemClonePlugin.MaxPocketCartsPerShop.Value, "Drones" => ShopItemClonePlugin.MaxDronesPerShop.Value, "Orbs" => ShopItemClonePlugin.MaxOrbsPerShop.Value, "HealthPacks" => ShopItemClonePlugin.MaxHealthPacksPerShop.Value, "Explosives" => ShopItemClonePlugin.MaxExplosivesPerShop.Value, "EnergyCrystals" => ShopItemClonePlugin.MaxEnergyCrystalsPerShop.Value, "Trackers" => ShopItemClonePlugin.MaxTrackersPerShop.Value, "Tools" => ShopItemClonePlugin.MaxToolsPerShop.Value, "Vehicles" => ShopItemClonePlugin.MaxVehiclesPerShop.Value, "Launchers" => ShopItemClonePlugin.MaxLaunchersPerShop.Value, _ => 0, }; } private static bool IsActuallyHeld(PhysGrabObject source) { if ((Object)(object)source == (Object)null) { return false; } if (!source.grabbed) { return false; } List<PhysGrabber> playerGrabbing = source.playerGrabbing; if (playerGrabbing == null || playerGrabbing.Count == 0) { return false; } for (int i = 0; i < playerGrabbing.Count; i++) { PhysGrabber val = playerGrabbing[i]; if (!((Object)(object)val == (Object)null) && val.grabbed && !((Object)(object)val.grabbedPhysGrabObject != (Object)(object)source)) { return true; } } return false; } private static bool IsInsideExtractionPoint(PhysGrabObject source) { if ((Object)(object)source == (Object)null) { return false; } RoomVolumeCheck val = ((Component)source).GetComponent<RoomVolumeCheck>(); if ((Object)(object)val == (Object)null) { val = ((Component)source).GetComponentInChildren<RoomVolumeCheck>(); } if ((Object)(object)val == (Object)null) { val = ((Component)source).GetComponentInParent<RoomVolumeCheck>(); } if ((Object)(object)val == (Object)null) { return false; } try { val.CheckSet(); if (InExtractionPointField != null) { object value = InExtractionPointField.GetValue(val); if (value is bool) { return (bool)value; } } } catch { } return false; } private static bool IsGroundLikeEnvironmentCollision(Collision collision) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if (collision == null) { return false; } Transform transform = collision.transform; if ((Object)(object)transform == (Object)null) { return false; } MaterialSurface val = ((Component)transform).GetComponent<MaterialSurface>(); if ((Object)(object)val == (Object)null) { val = ((Component)transform).GetComponentInParent<MaterialSurface>(); } if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)((Component)transform).GetComponentInParent<PhysGrabObject>() != (Object)null) { return false; } if (((Component)transform).CompareTag("Player") || (Object)(object)((Component)transform).GetComponentInParent<PlayerAvatar>() != (Object)null) { return false; } if ((Object)(object)((Component)transform).GetComponentInParent<EnemyRigidbody>() != (Object)null) { return false; } if ((Object)(object)((Component)transform).GetComponentInParent<PhysGrabCart>() != (Object)null) { return false; } float num = -1f; ContactPoint[] contacts = collision.contacts; for (int i = 0; i < contacts.Length; i++) { if (((ContactPoint)(ref contacts[i])).normal.y > num) { num = ((ContactPoint)(ref contacts[i])).normal.y; } } return num >= 0.35f; } private static float GetImpactForce(PhysGrabObjectImpactDetector detector, Collision collision) { //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) float num = 0f; try { if (ImpactForceField != null && (Object)(object)detector != (Object)null) { object value = ImpactForceField.GetValue(detector); if (value is float) { num = (float)value; } } } catch { num = 0f; } if (num > 0.01f) { return num; } try { Rigidbody val = (((Object)(object)detector != (Object)null) ? ((Component)detector).GetComponent<Rigidbody>() : null); float num2 = (((Object)(object)val != (Object)null) ? Mathf.Max(val.mass, 1f) : 1f); Vector3 relativeVelocity = collision.relativeVelocity; num = ((Vector3)(ref relativeVelocity)).magnitude * num2 * 10f; } catch { num = 0f; } return num; } private static bool IsCartLikeCategory(string category) { return category == "Carts" || category == "PocketCarts" || category == "Vehicles"; } private Vector3 GetCloneSpawnPosition(PhysGrabObject source, ItemAttributes sourceItem, string category) { //IL_004d: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) float num = 0.01f; if (category == "Carts" || category == "PocketCarts") { num = 1f; } else if (category == "Vehicles") { num = 1f; } return ((Component)source).transform.position + Vector3.up * num; } private void ResetShopCounters() { categoryCloneCounts.Clear(); } private void CloneHeldShopItem(PhysGrabObject source, ItemAttributes sourceItem, string category) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || (Object)(object)sourceItem == (Object)null || (Object)(object)sourceItem.item == (Object)null || !CanCloneCategoryThisShop(category)) { return; } string text = null; if (sourceItem.item.prefab != null) { text = sourceItem.item.prefab.ResourcePath; } if (string.IsNullOrEmpty(text)) { if (ShopItemClonePlugin.LogSource != null) { ShopItemClonePlugin.LogSource.LogWarning((object)("Skipped clone because resource path was missing: " + ((Object)source).name)); } return; } Vector3 cloneSpawnPosition = GetCloneSpawnPosition(source, sourceItem, category); Quaternion rotation = ((Component)source).transform.rotation; GameObject val = null; if (GameManager.Multiplayer()) { val = PhotonNetwork.InstantiateRoomObject(text, cloneSpawnPosition, rotation, (byte)0, (object[])null); } else { GameObject prefab = sourceItem.item.prefab.Prefab; if ((Object)(object)prefab != (Object)null) { val = Object.Instantiate<GameObject>(prefab, cloneSpawnPosition, rotation); } } if (!((Object)(object)val == (Object)null)) { RegisterCategoryClone(category); Rigidbody rb = source.rb; Rigidbody component = val.GetComponent<Rigidbody>(); TryApplyInitialMotion(rb, component); PhysGrabObjectImpactDetector component2 = val.GetComponent<PhysGrabObjectImpactDetector>(); if ((Object)(object)component2 != (Object)null) { component2.ImpactDisable(0.2f); } ((MonoBehaviour)this).StartCoroutine(FinalizeCloneAfterStart(source, sourceItem, val)); ((MonoBehaviour)this).StartCoroutine(IgnoreCloneCollisionTemporary(((Component)source).gameObject, val, 0.2f)); ShopItemClonePlugin.LogDebug("Cloned item=" + ((Object)source).name + " category=" + category); } } private static void TryApplyInitialMotion(Rigidbody sourceRb, Rigidbody cloneRb) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourceRb == (Object)null || (Object)(object)cloneRb == (Object)null || cloneRb.isKinematic) { return; } try { cloneRb.velocity = sourceRb.velocity; cloneRb.angularVelocity = sourceRb.angularVelocity; } catch { } } [IteratorStateMachine(typeof(<FinalizeCloneAfterStart>d__52))] private IEnumerator FinalizeCloneAfterStart(PhysGrabObject source, ItemAttributes sourceItem, GameObject cloneObject) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FinalizeCloneAfterStart>d__52(0) { <>4__this = this, source = source, sourceItem = sourceItem, cloneObject = cloneObject }; } private static void CopyItemValue(ItemAttributes sourceItem, ItemAttributes cloneItem, PhotonView clonePhotonView) { if (ItemValueField == null || (Object)(object)sourceItem == (Object)null || (Object)(object)cloneItem == (Object)null) { return; } try { object value = ItemValueField.GetValue(sourceItem); if (value is int) { int num = (int)value; if (GameManager.Multiplayer() && (Object)(object)clonePhotonView != (Object)null) { clonePhotonView.RPC("GetValueRPC", (RpcTarget)0, new object[1] { num }); } else { cloneItem.GetValueRPC(num); } } } catch { } } private static void CopyToggleState(PhysGrabObject source, GameObject cloneObject) { if ((Object)(object)source == (Object)null || (Object)(object)cloneObject == (Object)null) { return; } try { ItemToggle component = ((Component)source).GetComponent<ItemToggle>(); ItemToggle component2 = cloneObject.GetComponent<ItemToggle>(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && component2.toggleState != component.toggleState) { component2.ToggleItem(component.toggleState, -1); } } catch { } } private static void CopyBatteryState(PhysGrabObject source, GameObject cloneObject, PhotonView clonePhotonView) { if ((Object)(object)source == (Object)null || (Object)(object)cloneObject == (Object)null) { return; } try { ItemBattery component = ((Component)source).GetComponent<ItemBattery>(); ItemBattery component2 = cloneObject.GetComponent<ItemBattery>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && component2.batteryBars > 0) { int num = Mathf.Clamp(Mathf.RoundToInt(component.batteryLife / (100f / (float)component2.batteryBars)), 0, component2.batteryBars); if (GameManager.Multiplayer() && (Object)(object)clonePhotonView != (Object)null) { clonePhotonView.RPC("BatteryFullPercentChangeRPC", (RpcTarget)0, new object[2] { num, false }); } else if (BatteryFullPercentChangeMethod != null) { BatteryFullPercentChangeMethod.Invoke(component2, new object[2] { num, false }); } } } catch { } } [IteratorStateMachine(typeof(<IgnoreCloneCollisionTemporary>d__56))] private IEnumerator IgnoreCloneCollisionTemporary(GameObject sourceObject, GameObject cloneObject, float duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <IgnoreCloneCollisionTemporary>d__56(0) { <>4__this = this, sourceObject = sourceObject, cloneObject = cloneObject, duration = duration }; } } [HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "OnCollisionStay")] internal static class PhysGrabObjectImpactDetectorPatch { private static void Postfix(PhysGrabObjectImpactDetector __instance, Collision collision) { ShopItemCloneRuntime instance = ShopItemCloneRuntime.Instance; if (!((Object)(object)instance == (Object)null)) { instance.OnImpactStay(__instance, collision); } } } }