using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using BetterArmory; using BetterArmory.Effects; using BetterArmory.Interactive; using BetterArmory.Ui; using Dawn; using GameNetcodeStuff; using HarmonyLib; using LethalCompanyInputUtils.Api; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Utilities; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.SceneManagement; using UnityEngine.UI; using Y4NGZInteractions.InteractionAnimationApi; using Y4NGZUpgrades.HUD; using Y4NGZUpgrades.Interactive.Feedback; using Y4NGZUpgrades.Weapons; using Y4NGZUpgrades.Weapons.Patches; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("DunGen")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.ASPP")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.UnityNav")] [assembly: IgnoresAccessChecksTo("EasyTextEffects")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.XR.CoreUtils")] [assembly: IgnoresAccessChecksTo("Unity.XR.Management")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.ConformanceAutomation")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MetaQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MockRuntime")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.OculusQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.RuntimeDebugger")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SpatialTracking")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("UnityEngine.XR.LegacyInputHelpers")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BetterArmory")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Better Armory weapon plugin split out of Y4NGZUpgrades")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+dfef71c89c7844cd9ab349fbd0fbf0af3289f0ac")] [assembly: AssemblyProduct("BetterArmory")] [assembly: AssemblyTitle("BetterArmory")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Y4NGZUpgrades.Weapons { internal sealed class AmmoPickupConfig { public string Id; public string DisplayName; public WeaponAmmoType AmmoType; public string FilePrefix; public float TargetWorldSize; public int ScrapMinValue; public int ScrapMaxValue; internal int DefaultRoundsGranted; internal int DefaultScrapRarity = 18; internal Func ReadRoundsGranted; internal Func ReadScrapRarity; internal string ShopDescription; internal int RoundsGranted { get { try { return Math.Max(0, (ReadRoundsGranted != null) ? ReadRoundsGranted() : DefaultRoundsGranted); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Could not read rounds config for " + DisplayName + ": " + ex.Message)); } return Math.Max(0, DefaultRoundsGranted); } } } internal int ScrapRarity { get { try { return Math.Max(0, (ReadScrapRarity != null) ? ReadScrapRarity() : DefaultScrapRarity); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Could not read scrap rarity for " + DisplayName + ": " + ex.Message)); } return Math.Max(0, DefaultScrapRarity); } } } } internal static class AmmoPickupCatalog { internal const string ShotgunShellsBoxId = "shotgun_shells_box"; internal const string PistolRoundsBoxId = "pistol_rounds_box"; internal const string HeavyRoundsBoxId = "heavy_rounds_box"; internal const string FuelTankId = "fuel_tank"; internal const string GrenadeId = "grenade"; internal static readonly AmmoPickupConfig ShotgunShellsBox = new AmmoPickupConfig { Id = "shotgun_shells_box", DisplayName = "Shotgun Shells", AmmoType = WeaponAmmoType.ShotgunShells, FilePrefix = "shotgun_shells", TargetWorldSize = 0.28f, ScrapMinValue = 8, ScrapMaxValue = 16, DefaultRoundsGranted = 4, DefaultScrapRarity = 18, ReadRoundsGranted = () => ArmoryContentConfig.RoundsPerBox(WeaponAmmoType.ShotgunShells, 4), ReadScrapRarity = () => ArmoryContentConfig.AmmoInteriorWeight(WeaponAmmoType.ShotgunShells, 18), ShopDescription = "Buckshot in a company-issue carton. Feeds the shell reserve every shotgun draws from." }; internal static readonly AmmoPickupConfig PistolRoundsBox = new AmmoPickupConfig { Id = "pistol_rounds_box", DisplayName = "Small Caliber Rounds", AmmoType = WeaponAmmoType.SmallCaliberRounds, FilePrefix = "pistol_rounds", TargetWorldSize = 0.22f, ScrapMinValue = 8, ScrapMaxValue = 16, DefaultRoundsGranted = 6, DefaultScrapRarity = 18, ReadRoundsGranted = () => ArmoryContentConfig.RoundsPerBox(WeaponAmmoType.SmallCaliberRounds, 6), ReadScrapRarity = () => ArmoryContentConfig.AmmoInteriorWeight(WeaponAmmoType.SmallCaliberRounds, 18), ShopDescription = "Mixed small-calibre cartridges. Serves the revolver and the pistol from one reserve." }; internal static readonly AmmoPickupConfig HeavyRoundsBox = new AmmoPickupConfig { Id = "heavy_rounds_box", DisplayName = "Heavy Caliber Rounds", AmmoType = WeaponAmmoType.HeavyCaliberRounds, FilePrefix = "heavy_rounds", TargetWorldSize = 0.26f, ScrapMinValue = 8, ScrapMaxValue = 16, DefaultRoundsGranted = 10, DefaultScrapRarity = 18, ReadRoundsGranted = () => ArmoryContentConfig.RoundsPerBox(WeaponAmmoType.HeavyCaliberRounds, 10), ReadScrapRarity = () => ArmoryContentConfig.AmmoInteriorWeight(WeaponAmmoType.HeavyCaliberRounds, 18), ShopDescription = "Belted rifle brass. The only thing the assault rifle and the bolt-action will eat." }; internal static readonly AmmoPickupConfig FuelTank = new AmmoPickupConfig { Id = "fuel_tank", DisplayName = "Fuel Tank", AmmoType = WeaponAmmoType.Fuel, FilePrefix = "fuel_tank", TargetWorldSize = 0.55f, ScrapMinValue = 8, ScrapMaxValue = 16, DefaultRoundsGranted = 100, DefaultScrapRarity = 18, ReadRoundsGranted = () => ArmoryContentConfig.RoundsPerBox(WeaponAmmoType.Fuel, 100), ReadScrapRarity = () => ArmoryContentConfig.AmmoInteriorWeight(WeaponAmmoType.Fuel, 18), ShopDescription = "Pressurised accelerant. Tops the flame thrower's tank back up out in the field." }; internal static readonly AmmoPickupConfig Grenade = new AmmoPickupConfig { Id = "grenade", DisplayName = "Grenade", AmmoType = WeaponAmmoType.Grenades, FilePrefix = "grenade", TargetWorldSize = 0.2f, ScrapMinValue = 18, ScrapMaxValue = 32, DefaultRoundsGranted = 1, DefaultScrapRarity = 12, ReadRoundsGranted = () => ArmoryContentConfig.RoundsPerBox(WeaponAmmoType.Grenades, 1), ReadScrapRarity = () => ArmoryContentConfig.AmmoInteriorWeight(WeaponAmmoType.Grenades, 12), ShopDescription = "One fragmentation grenade. Throw it by hand, or load it into the launcher." }; internal static IEnumerable All() { yield return ShotgunShellsBox; yield return PistolRoundsBox; yield return HeavyRoundsBox; yield return FuelTank; } internal static AmmoPickupConfig ById(string id) { foreach (AmmoPickupConfig item in All()) { if (string.Equals(item.Id, id, StringComparison.Ordinal)) { return item; } } return ShotgunShellsBox; } } internal sealed class AmmoPickupDevSpawnHost : MonoBehaviour { internal static bool Enabled = true; internal static Key SpawnKey = (Key)70; private int _lastSpawnFrame = -1; internal static void Ensure() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) try { GameObject host = ArmoryPersistentRunner.Host; if (!((Object)(object)host == (Object)null) && !((Object)(object)host.GetComponent() != (Object)null)) { host.AddComponent(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZAmmo] Dev spawn host attached (enabled={Enabled}, key={SpawnKey})."); } } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZAmmo] Could not attach the dev spawn host: " + ex.Message)); } } } private void Update() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) try { Keyboard current = Keyboard.current; if (Enabled && current != null && ((ButtonControl)current[SpawnKey]).wasPressedThisFrame && _lastSpawnFrame != Time.frameCount) { _lastSpawnFrame = Time.frameCount; AmmoPickupRegistry.DebugSpawnAllAtLocalPlayer(); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Dev spawn input failed safely: " + ex.Message)); } } } } internal sealed class AmmoPickupItem : MonoBehaviour { public string ConfigId = "shotgun_shells_box"; [NonSerialized] internal bool ConsumptionStarted; internal AmmoPickupConfig Config { get { try { return AmmoPickupCatalog.ById(ConfigId); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Could not resolve pickup config '" + ConfigId + "': " + ex.Message)); } return AmmoPickupCatalog.ShotgunShellsBox; } } } } internal static class AmmoPickupRegistry { private readonly struct VisualBuildResult { internal readonly MeshRenderer Renderer; internal readonly Bounds LocalBounds; internal VisualBuildResult(MeshRenderer renderer, Bounds localBounds) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Renderer = renderer; LocalBounds = localBounds; } } private const string PickupSoundFileName = "ammo_pickup.mp3"; private const int PropsLayer = 6; private const int ScanNodeFallbackLayer = 22; private const float PickupRootGroundOffset = 0.12f; private const float VisualFloorClearance = 0.015f; private const float MinimumPickupWidth = 0.52f; private const float MinimumPickupHeight = 0.24f; private const float MinimumPickupDepth = 0.38f; private static readonly Dictionary Prefabs = new Dictionary(); private static readonly Dictionary Items = new Dictionary(); private static readonly List PrefabHolders = new List(); private static bool _registered; private static bool _pickupSoundLoadAttempted; private static bool _missingPickupSoundWarned; private static AudioClip _pickupSound; private static AudioClip _fallbackGrabSound; private static AudioClip _fallbackDropSound; private static Sprite _simpleIcon; internal static int RegisteredCount => Prefabs.Count; internal static GameObject PrefabFor(string configId) { try { GameObject value; return Prefabs.TryGetValue(configId ?? string.Empty, out value) ? value : null; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Prefab lookup failed for '" + configId + "': " + ex.Message)); } return null; } } internal static Item ItemFor(string configId) { try { Item value; return Items.TryGetValue(configId ?? string.Empty, out value) ? value : null; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Item lookup failed for '" + configId + "': " + ex.Message)); } return null; } } internal static bool TryRegisterAll() { try { RefreshFallbackSounds(); if (_registered) { ApplySoundsToRegisteredItems(); TryBeginPickupSoundLoad(); return true; } bool flag = true; foreach (AmmoPickupConfig item in AmmoPickupCatalog.All()) { if ((Object)(object)PrefabFor(item.Id) != (Object)null && (Object)(object)ItemFor(item.Id) != (Object)null) { continue; } try { BuildAndRegister(item); } catch (Exception arg) { flag = false; ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZAmmo] Registration failed for {item.DisplayName}; other gameplay will continue: {arg}"); } } } foreach (AmmoPickupConfig item2 in AmmoPickupCatalog.All()) { flag &= (Object)(object)PrefabFor(item2.Id) != (Object)null && (Object)(object)ItemFor(item2.Id) != (Object)null; } bool num = flag && !_registered; _registered = flag; if (num) { if (Prefabs.Count > 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[Y4NGZAmmo] Registered {Prefabs.Count} ammo pickups."); } } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"[Y4NGZAmmo] Registered 0 ammo pickups: the ammo pickup catalog yielded no entries. No ammunition will spawn or appear in the shop."); } } } ApplySoundsToRegisteredItems(); TryBeginPickupSoundLoad(); return flag; } catch (Exception arg2) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)$"[Y4NGZAmmo] Ammo pickup registration failed safely: {arg2}"); } return false; } } private static void BuildAndRegister(AmmoPickupConfig config) { GameObject holder = null; GameObject val = null; Item val2 = null; try { val = BuildItemPrefab(config, out holder); val2 = BuildItemProperties(config, val); PhysicsProp component = val.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The generated prefab has no PhysicsProp component."); } ((GrabbableObject)component).itemProperties = val2; val2.spawnPrefab = val; DawnLibCompat.FixMixerGroups(val); DawnLibCompat.RegisterNetworkPrefab(val); WeaponAmmoType family = config.AmmoType; DawnLibCompat.RegisterItem(config.Id, val2, () => ArmoryContentConfig.IsAmmoPurchasable(family), () => ArmoryContentConfig.AmmoShopPrice(family), config.ShopDescription, () => config.ScrapRarity); Prefabs[config.Id] = val; Items[config.Id] = val2; if ((Object)(object)holder != (Object)null) { PrefabHolders.Add(holder); } NetworkObject component2 = val.GetComponent(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZAmmo] Registered {config.DisplayName} (hash={component2?.GlobalObjectIdHash ?? 0}, " + $"rounds={config.RoundsGranted}, scrapRarity={config.ScrapRarity}).")); } } catch { if ((Object)(object)holder != (Object)null) { Object.DestroyImmediate((Object)(object)holder); } else if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } if ((Object)(object)val2 != (Object)null) { Object.DestroyImmediate((Object)(object)val2); } throw; } } private static GameObject BuildItemPrefab(AmmoPickupConfig config, out GameObject holder) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) holder = new GameObject("Y4NGZ_" + config.Id + "_InactiveHolder"); ((Object)holder).hideFlags = (HideFlags)61; holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)holder); GameObject val = new GameObject("Y4NGZ_" + config.Id + "_Prefab"); val.transform.SetParent(holder.transform, false); ((Object)val).hideFlags = (HideFlags)0; val.layer = 6; SetTagSafe(val, "PhysicsProp"); NetworkObject obj = val.AddComponent(); obj.SynchronizeTransform = true; obj.SceneMigrationSynchronization = true; obj.SpawnWithObservers = true; obj.DontDestroyWithOwner = true; obj.AutoObjectParentSync = true; AssignStableNetworkHash(obj, config.Id); Rigidbody val2 = val.AddComponent(); val2.isKinematic = true; val2.useGravity = false; val2.mass = 0.8f; val2.drag = 0.15f; val2.angularDrag = 4f; AudioSource obj2 = val.AddComponent(); obj2.playOnAwake = false; obj2.spatialBlend = 1f; obj2.dopplerLevel = 0f; obj2.rolloffMode = (AudioRolloffMode)0; obj2.minDistance = 1f; obj2.maxDistance = 16f; PhysicsProp val3 = val.AddComponent(); ((GrabbableObject)val3).grabbable = true; ((GrabbableObject)val3).grabbableToEnemies = false; ((GrabbableObject)val3).deactivated = false; ((GrabbableObject)val3).isHeld = false; ((GrabbableObject)val3).isPocketed = false; ((GrabbableObject)val3).isInFactory = false; ((GrabbableObject)val3).scrapValue = (config.ScrapMinValue + config.ScrapMaxValue) / 2; ((GrabbableObject)val3).rotateObject = false; ((GrabbableObject)val3).propBody = val2; ((GrabbableObject)val3).originalScale = Vector3.one; ((GrabbableObject)val3).customGrabTooltip = "Collect ammunition"; VisualBuildResult visualBuildResult = BuildVisual(val, config); BoxCollider val4 = val.AddComponent(); ((Collider)val4).isTrigger = false; Bounds localBounds = visualBuildResult.LocalBounds; val4.center = ((Bounds)(ref localBounds)).center; localBounds = visualBuildResult.LocalBounds; float num = Mathf.Max(0.52f, ((Bounds)(ref localBounds)).size.x + 0.05f); localBounds = visualBuildResult.LocalBounds; float num2 = Mathf.Max(0.24f, ((Bounds)(ref localBounds)).size.y + 0.04f); localBounds = visualBuildResult.LocalBounds; val4.size = new Vector3(num, num2, Mathf.Max(0.38f, ((Bounds)(ref localBounds)).size.z + 0.05f)); Vector3 center = val4.center; center.y = Mathf.Max(center.y, val4.size.y * 0.5f + 0.015f - 0.12f); val4.center = center; ((Collider)val4).enabled = true; ((Component)val4).gameObject.layer = 6; SetTagSafe(((Component)val4).gameObject, "PhysicsProp"); ((GrabbableObject)val3).propColliders = (Collider[])(object)new Collider[1] { (Collider)val4 }; ((GrabbableObject)val3).mainObjectRenderer = visualBuildResult.Renderer; BuildScanNode(val, val4, config); val.AddComponent().ConfigId = config.Id; return val; } private static VisualBuildResult BuildVisual(GameObject root, AmmoPickupConfig config) { //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) try { if (config.Id == "grenade" && TryBuildBundledGrenadeVisual(root, config, out var result)) { return result; } string text = WeaponAssetLoader.AssetDirectory(); Mesh val = WeaponAssetLoader.LoadMesh(string.IsNullOrWhiteSpace(text) ? null : Path.Combine(text, config.FilePrefix + ".mesh"), config.DisplayName); Material val2 = WeaponAssetLoader.BuildMaterial(text, config.FilePrefix, config.DisplayName); GameObject val3; MeshRenderer val4; if (!((Object)(object)val == (Object)null)) { Bounds bounds = val.bounds; if (!(WeaponAssetLoader.LongestAxis(((Bounds)(ref bounds)).size) <= 1E-05f)) { val3 = new GameObject("Y4NGZ_" + config.Id + "_Visual"); val3.transform.SetParent(root.transform, false); val3.AddComponent().sharedMesh = val; val4 = val3.AddComponent(); goto IL_017c; } } val3 = GameObject.CreatePrimitive((PrimitiveType)3); val3.SetActive(false); ((Object)val3).name = "Y4NGZ_" + config.Id + "_PlaceholderVisual"; val3.transform.SetParent(root.transform, false); Collider component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } MeshFilter component2 = val3.GetComponent(); val = ((component2 != null) ? component2.sharedMesh : null); val4 = val3.GetComponent(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] " + config.DisplayName + " is using a primitive-cube placeholder visual.")); } val3.SetActive(true); goto IL_017c; IL_017c: val3.layer = root.layer; if ((Object)(object)val4 != (Object)null && (Object)(object)val2 != (Object)null) { ((Renderer)val4).sharedMaterial = val2; } Bounds val5 = (Bounds)(((Object)(object)val != (Object)null) ? val.bounds : new Bounds(Vector3.zero, Vector3.one)); float num = Mathf.Max(1E-05f, WeaponAssetLoader.LongestAxis(((Bounds)(ref val5)).size)); float num2 = Mathf.Max(0.01f, config.TargetWorldSize) / num; val3.transform.localRotation = Quaternion.identity; val3.transform.localScale = Vector3.one * num2; val3.transform.localPosition = new Vector3((0f - ((Bounds)(ref val5)).center.x) * num2, (0f - ((Bounds)(ref val5)).min.y) * num2 + 0.015f - 0.12f, (0f - ((Bounds)(ref val5)).center.z) * num2); Vector3 val6 = default(Vector3); ((Vector3)(ref val6))..ctor(Mathf.Abs(((Bounds)(ref val5)).size.x * num2), Mathf.Abs(((Bounds)(ref val5)).size.y * num2), Mathf.Abs(((Bounds)(ref val5)).size.z * num2)); Bounds localBounds = default(Bounds); ((Bounds)(ref localBounds))..ctor(new Vector3(0f, val6.y * 0.5f + 0.015f - 0.12f, 0f), val6); return new VisualBuildResult(val4, localBounds); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZAmmo] Visual build failed for " + config.DisplayName + "; using a minimal pickup box: " + ex.Message)); } try { GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); obj.SetActive(false); ((Object)obj).name = "Y4NGZ_" + config.Id + "_EmergencyPlaceholderVisual"; obj.transform.SetParent(root.transform, false); Collider component3 = obj.GetComponent(); if ((Object)(object)component3 != (Object)null) { Object.DestroyImmediate((Object)(object)component3); } obj.layer = root.layer; obj.transform.localPosition = Vector3.up * (config.TargetWorldSize * 0.5f + 0.015f - 0.12f); obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = Vector3.one * config.TargetWorldSize; obj.SetActive(true); Bounds localBounds2 = default(Bounds); ((Bounds)(ref localBounds2))..ctor(new Vector3(0f, config.TargetWorldSize * 0.5f + 0.015f - 0.12f, 0f), Vector3.one * config.TargetWorldSize); return new VisualBuildResult(obj.GetComponent(), localBounds2); } catch (Exception ex2) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZAmmo] Emergency placeholder also failed: " + ex2.Message)); } Bounds localBounds3 = default(Bounds); ((Bounds)(ref localBounds3))..ctor(new Vector3(0f, config.TargetWorldSize * 0.5f + 0.015f - 0.12f, 0f), Vector3.one * config.TargetWorldSize); return new VisualBuildResult(null, localBounds3); } } } private static bool TryBuildBundledGrenadeVisual(GameObject root, AmmoPickupConfig config, out VisualBuildResult result) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) result = default(VisualBuildResult); GameObject val = GrenadeContentAssets.CreateVisual(root.transform); if ((Object)(object)val == (Object)null) { return false; } ((Object)val).name = "Y4NGZ_" + config.Id + "_Visual"; Renderer[] componentsInChildren = val.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { Object.DestroyImmediate((Object)(object)val); return false; } Bounds bounds = componentsInChildren[0].bounds; for (int i = 1; i < componentsInChildren.Length; i++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[i].bounds); } float num = Mathf.Max(1E-05f, WeaponAssetLoader.LongestAxis(((Bounds)(ref bounds)).size)); Transform transform = val.transform; transform.localScale *= Mathf.Max(0.01f, config.TargetWorldSize) / num; bounds = componentsInChildren[0].bounds; for (int j = 1; j < componentsInChildren.Length; j++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[j].bounds); } Vector3 val2 = root.transform.InverseTransformPoint(((Bounds)(ref bounds)).center); Vector3 val3 = root.transform.InverseTransformPoint(new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).center.z)); Transform transform2 = val.transform; transform2.localPosition += new Vector3(0f - val2.x, -0.105f - val3.y, 0f - val2.z); bounds = componentsInChildren[0].bounds; for (int k = 1; k < componentsInChildren.Length; k++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[k].bounds); } Vector3 val4 = root.transform.InverseTransformPoint(((Bounds)(ref bounds)).center); Vector3 lossyScale = root.transform.lossyScale; Vector3 val5 = default(Vector3); ((Vector3)(ref val5))..ctor(((Bounds)(ref bounds)).size.x / Mathf.Max(1E-05f, Mathf.Abs(lossyScale.x)), ((Bounds)(ref bounds)).size.y / Mathf.Max(1E-05f, Mathf.Abs(lossyScale.y)), ((Bounds)(ref bounds)).size.z / Mathf.Max(1E-05f, Mathf.Abs(lossyScale.z))); Renderer obj = componentsInChildren[0]; result = new VisualBuildResult((MeshRenderer)(object)((obj is MeshRenderer) ? obj : null), new Bounds(val4, val5)); return true; } private static void BuildScanNode(GameObject root, BoxCollider pickupCollider, AmmoPickupConfig config) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0075: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("ScanNode"); val.transform.SetParent(root.transform, false); val.layer = ResolveLayer("ScanNode", 22); val.transform.localPosition = pickupCollider.center + Vector3.up * 0.08f; BoxCollider obj = val.AddComponent(); ((Collider)obj).isTrigger = true; obj.size = pickupCollider.size + Vector3.one * 0.08f; ScanNodeProperties obj2 = val.AddComponent(); obj2.headerText = config.DisplayName; obj2.subText = "Ammunition"; obj2.maxRange = 24; obj2.minRange = 1; obj2.requiresLineOfSight = false; obj2.nodeType = 0; obj2.creatureScanID = -1; obj2.scrapValue = (config.ScrapMinValue + config.ScrapMaxValue) / 2; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Scan node setup failed for " + config.DisplayName + ": " + ex.Message)); } } } private static Item BuildItemProperties(AmmoPickupConfig config, GameObject prefab) { //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) try { Item obj = ScriptableObject.CreateInstance(); ((Object)obj).name = "Y4NGZ_" + config.Id + "_Item"; obj.itemName = config.DisplayName; obj.spawnPositionTypes = new List(); obj.twoHanded = false; obj.twoHandedAnimation = false; obj.canBeGrabbedBeforeGameStart = true; obj.disallowUtilitySlot = true; obj.weight = 1f; obj.itemSpawnsOnGround = true; obj.isConductiveMetal = true; obj.isScrap = true; obj.creditsWorth = (config.ScrapMinValue + config.ScrapMaxValue) / 2; obj.minValue = config.ScrapMinValue; obj.maxValue = config.ScrapMaxValue; obj.spawnPrefab = prefab; obj.requiresBattery = false; obj.itemIcon = WeaponAssetLoader.LoadIconSprite(config.Id) ?? GetSimpleIcon(); obj.grabAnimationTime = 0.25f; obj.grabSFX = (((Object)(object)_pickupSound != (Object)null) ? _pickupSound : _fallbackGrabSound); obj.dropSFX = _fallbackDropSound; obj.syncGrabFunction = true; obj.syncUseFunction = false; obj.syncDiscardFunction = true; obj.syncInteractLRFunction = false; obj.saveItemVariable = false; obj.toolTips = Array.Empty(); obj.verticalOffset = 0.12f; obj.floorYOffset = 0; obj.allowDroppingAheadOfPlayer = true; obj.restingRotation = Vector3.zero; obj.rotationOffset = Vector3.zero; obj.positionOffset = Vector3.zero; obj.meshOffset = false; obj.canBeInspected = true; ((Object)obj).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)obj); return obj; } catch (Exception innerException) { throw new InvalidOperationException("Could not build Item data for " + config.DisplayName + ".", innerException); } } private static void RefreshFallbackSounds() { try { if ((Object)(object)_fallbackGrabSound != (Object)null && (Object)(object)_fallbackDropSound != (Object)null) { return; } Item[] array = Resources.FindObjectsOfTypeAll(); foreach (Item val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.spawnPrefab == (Object)null) && !((Object)(object)val.spawnPrefab.GetComponent() != (Object)null)) { if ((Object)(object)_fallbackGrabSound == (Object)null && (Object)(object)val.grabSFX != (Object)null) { _fallbackGrabSound = val.grabSFX; } if ((Object)(object)_fallbackDropSound == (Object)null && (Object)(object)val.dropSFX != (Object)null) { _fallbackDropSound = val.dropSFX; } if ((Object)(object)_fallbackGrabSound != (Object)null && (Object)(object)_fallbackDropSound != (Object)null) { break; } } } AudioClip[] array2 = StartOfRound.Instance?.playerGrabSFX; if ((Object)(object)_fallbackGrabSound == (Object)null && array2 != null && array2.Length != 0) { _fallbackGrabSound = array2[0]; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Could not resolve vanilla pickup sounds: " + ex.Message)); } } } private static void ApplySoundsToRegisteredItems() { try { foreach (Item value in Items.Values) { if (!((Object)(object)value == (Object)null)) { if ((Object)(object)_pickupSound != (Object)null) { value.grabSFX = _pickupSound; } else if ((Object)(object)value.grabSFX == (Object)null) { value.grabSFX = _fallbackGrabSound; } if ((Object)(object)value.dropSFX == (Object)null) { value.dropSFX = _fallbackDropSound; } } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Could not apply pickup sounds: " + ex.Message)); } } } private static void TryBeginPickupSoundLoad() { try { if (_pickupSoundLoadAttempted || (Object)(object)_pickupSound != (Object)null) { return; } string text = WeaponAssetLoader.AssetDirectory(); string text2 = (string.IsNullOrWhiteSpace(text) ? null : Path.Combine(text, "ammo_pickup.mp3")); if (string.IsNullOrWhiteSpace(text2) || !File.Exists(text2)) { _pickupSoundLoadAttempted = true; if (!_missingPickupSoundWarned) { _missingPickupSoundWarned = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Y4NGZAmmo] ammo_pickup.mp3 is missing; ammo pickups will keep a vanilla/default grab sound."); } } return; } _pickupSoundLoadAttempted = true; if (ArmoryPersistentRunner.Run(LoadPickupSound(text2)) == null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Y4NGZAmmo] Could not start the pickup sound load; keeping defaults."); } } } catch (Exception ex) { _pickupSoundLoadAttempted = true; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZAmmo] Pickup sound load could not start; keeping defaults: " + ex.Message)); } } } private static IEnumerator LoadPickupSound(string path) { UnityWebRequest request = null; UnityWebRequestAsyncOperation val; try { request = UnityWebRequestMultimedia.GetAudioClip(new Uri(path).AbsoluteUri, (AudioType)13); val = request.SendWebRequest(); } catch (Exception ex) { UnityWebRequest obj = request; if (obj != null) { obj.Dispose(); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Pickup sound request failed to start; keeping defaults: " + ex.Message)); } yield break; } yield return val; try { if ((int)request.result != 1) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZAmmo] Pickup sound failed to load; keeping defaults: " + request.error)); } yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"[Y4NGZAmmo] Pickup sound decoded as null; keeping defaults."); } yield break; } ((Object)content).name = "Y4NGZ_AmmoPickup"; _pickupSound = content; ApplySoundsToRegisteredItems(); ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)"[Y4NGZAmmo] Loaded shared ammo pickup grab sound."); } } catch (Exception ex2) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogWarning((object)("[Y4NGZAmmo] Pickup sound processing failed; keeping defaults: " + ex2.Message)); } } finally { UnityWebRequest obj2 = request; if (obj2 != null) { obj2.Dispose(); } } } private static Sprite GetSimpleIcon() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0069: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_00a8: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_simpleIcon != (Object)null) { return _simpleIcon; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { name = "Y4NGZ_AmmoPickupIconTexture", hideFlags = (HideFlags)61 }; Color val2 = default(Color); ((Color)(ref val2))..ctor(0.86f, 0.53f, 0.16f, 1f); val.SetPixels((Color[])(object)new Color[4] { val2, val2, val2, val2 }); val.Apply(false, true); _simpleIcon = Sprite.Create(val, new Rect(0f, 0f, 2f, 2f), new Vector2(0.5f, 0.5f), 100f); ((Object)_simpleIcon).name = "Y4NGZ_AmmoPickupIcon"; ((Object)_simpleIcon).hideFlags = (HideFlags)61; return _simpleIcon; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Could not create the simple ammo icon: " + ex.Message)); } return null; } } private static void AssignStableNetworkHash(NetworkObject networkObject, string id) { if ((Object)(object)networkObject == (Object)null) { return; } try { uint num; using (MD5 mD = MD5.Create()) { num = BitConverter.ToUInt32(mD.ComputeHash(Encoding.UTF8.GetBytes("com.y4ngz.betterarmory.AmmoPickup." + id)), 0); } FieldInfo? obj = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (obj == null) { throw new MissingFieldException(typeof(NetworkObject).FullName, "GlobalObjectIdHash"); } obj.SetValue(networkObject, num); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Failed to assign the stable network hash for " + id + ": " + ex.Message)); } } } private static int ResolveLayer(string name, int fallback) { try { int num = LayerMask.NameToLayer(name); return (num >= 0) ? num : fallback; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Layer '" + name + "' lookup failed: " + ex.Message)); } return fallback; } } private static void SetTagSafe(GameObject target, string tag) { try { if ((Object)(object)target != (Object)null) { target.tag = tag; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZAmmo] Tag '" + tag + "' was not available for " + ((target != null) ? ((Object)target).name : null) + ": " + ex.Message)); } } } internal static void DebugSpawnAllAtLocalPlayer() { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0105: 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_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) try { if (!TryRegisterAll()) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Y4NGZAmmo] Dev spawn skipped because ammo pickup registration is incomplete."); } return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Y4NGZAmmo] Dev spawn requires being the host."); } return; } PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"[Y4NGZAmmo] Dev spawn skipped because the local player is unavailable."); } return; } int num = 0; foreach (AmmoPickupConfig item in AmmoPickupCatalog.All()) { try { GameObject val2 = PrefabFor(item.Id); if (!((Object)(object)val2 == (Object)null)) { float num2 = ((float)num - 1.5f) * 0.42f; Vector3 val3 = ((Component)val).transform.position + ((Component)val).transform.forward * 1.35f + ((Component)val).transform.right * num2 + Vector3.up * 0.55f; GameObject val4 = Object.Instantiate(val2, val3, Quaternion.identity); val4.SetActive(true); NetworkObject component = val4.GetComponent(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val4); throw new InvalidOperationException("Spawned prefab has no NetworkObject."); } component.Spawn(false); ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[Y4NGZAmmo] Dev-spawned {item.DisplayName} at {val3}."); } } } catch (Exception ex) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogWarning((object)("[Y4NGZAmmo] Dev spawn failed for " + item.DisplayName + ": " + ex.Message)); } } finally { num++; } } } catch (Exception arg) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogWarning((object)$"[Y4NGZAmmo] Dev spawn failed safely: {arg}"); } } } } [Serializable] internal class AmmoReserveData { public int shotgunShells; public int pistolRounds; public int bolts; public int fuel; public int grenades; public bool grantedStartingReserve; public int smallCaliberRounds; public int heavyRounds; public int Get(WeaponAmmoType t) { return t switch { WeaponAmmoType.ShotgunShells => shotgunShells, WeaponAmmoType.Fuel => fuel, WeaponAmmoType.Grenades => grenades, WeaponAmmoType.SmallCaliberRounds => smallCaliberRounds, WeaponAmmoType.HeavyCaliberRounds => heavyRounds, _ => 0, }; } public void Set(WeaponAmmoType t, int v) { v = Mathf.Max(0, v); int num = AmmoReserve.MaximumFor(t); if (num != int.MaxValue) { v = Mathf.Min(num, v); } switch (t) { case WeaponAmmoType.ShotgunShells: shotgunShells = v; break; case WeaponAmmoType.Fuel: fuel = v; break; case WeaponAmmoType.Grenades: grenades = v; break; case WeaponAmmoType.SmallCaliberRounds: smallCaliberRounds = v; break; case WeaponAmmoType.HeavyCaliberRounds: heavyRounds = v; break; } } } internal static class AmmoReserve { internal const int MaxGrenades = 2; private static AmmoReserveData _data; private static string _key; private static readonly HashSet _devGranted = new HashSet(); private static string SaveDir => Path.Combine(Paths.ConfigPath, "Y4NGZAmmoReserve"); internal static AmmoReserveData Local => Load(); internal static int Get(WeaponAmmoType t) { return Load().Get(t); } internal static int MaximumFor(WeaponAmmoType t) { return ArmoryContentConfig.MaxReserve(t); } internal static void Add(WeaponAmmoType t, int amount) { TryAdd(t, amount, out var _); } internal static bool TryAdd(WeaponAmmoType t, int amount, out int added) { added = 0; if (amount <= 0) { return false; } AmmoReserveData ammoReserveData = Load(); int num = ammoReserveData.Get(t); int num2 = MaximumFor(t); added = ((num2 == int.MaxValue) ? amount : Mathf.Min(amount, Mathf.Max(0, num2 - num))); if (added <= 0) { return false; } ammoReserveData.Set(t, num + added); Save(); return true; } internal static bool TryConsume(WeaponAmmoType t, int amount) { if (amount <= 0) { return true; } AmmoReserveData ammoReserveData = Load(); if (ammoReserveData.Get(t) < amount) { return false; } ammoReserveData.Set(t, ammoReserveData.Get(t) - amount); Save(); return true; } internal static void Set(WeaponAmmoType t, int value) { Load().Set(t, value); Save(); } internal static void Reload() { _data = null; _key = null; _devGranted.Clear(); } internal static bool TryDevGrantOnce(WeaponAmmoType t, int amount) { if (amount <= 0 || _devGranted.Contains(t) || Get(t) > 0) { return false; } _devGranted.Add(t); Set(t, amount); return true; } internal static void ResetCurrentSave() { if (!ArmorySaveBridge.TryGetCurrentExistingOrSlotKey(out var key)) { Reload(); } else { DeleteForKey(key); } } internal static bool DeleteForKey(string key) { bool result = false; try { string path = GetPath(key); if (File.Exists(path)) { File.Delete(path); result = true; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] ammo reserve reset failed: " + ex.Message)); } } if (string.Equals(_key, key, StringComparison.OrdinalIgnoreCase)) { Reload(); } return result; } private static AmmoReserveData Load() { if (!ArmorySaveBridge.TryGetCurrentKey(out var key)) { if (_data == null || _key != null) { _data = new AmmoReserveData(); _key = null; } return _data; } if (_data != null && _key == key) { return _data; } _key = key; string path = GetPath(key); if (File.Exists(path)) { try { _data = JsonUtility.FromJson(File.ReadAllText(path)) ?? new AmmoReserveData(); } catch { _data = new AmmoReserveData(); } } else { _data = new AmmoReserveData(); } _data.Set(WeaponAmmoType.Grenades, _data.Get(WeaponAmmoType.Grenades)); if (MigrateRetiredFamilies(_data) | GrantStartingReserveOnce(_data)) { Save(); } return _data; } private static bool MigrateRetiredFamilies(AmmoReserveData d) { bool result = false; if (d.pistolRounds > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZWeapons] Ammo migration (#148): folding {d.pistolRounds} pistol round(s) " + "into the small-caliber reserve; the revolver now shares that family.")); } d.smallCaliberRounds += d.pistolRounds; result = true; } if (d.pistolRounds != 0) { d.pistolRounds = 0; result = true; } if (d.bolts != 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)($"[Y4NGZWeapons] Ammo migration (#150): dropping {d.bolts} crossbow bolt(s); " + "the crossbow was removed and no weapon fires them.")); } d.bolts = 0; result = true; } return result; } private static bool GrantStartingReserveOnce(AmmoReserveData d) { if (d == null || d.grantedStartingReserve) { return false; } d.grantedStartingReserve = true; List list = new List(); foreach (AmmoPickupConfig item in AmmoPickupCatalog.All()) { if (item != null) { int num = ArmoryContentConfig.StartingReserve(item.AmmoType); if (num > 0) { d.Set(item.AmmoType, Math.Max(d.Get(item.AmmoType), num)); list.Add($"{d.Get(item.AmmoType)} {ArmoryContentConfig.FamilyName(item.AmmoType)}"); } } } if (list.Count > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons] Starting ammo reserve granted for this save: " + string.Join(", ", list.ToArray()) + ".")); } } return true; } private static void Save() { if (_data == null || string.IsNullOrWhiteSpace(_key)) { return; } try { if (!Directory.Exists(SaveDir)) { Directory.CreateDirectory(SaveDir); } File.WriteAllText(GetPath(_key), JsonUtility.ToJson((object)_data, true)); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] ammo reserve save failed: " + ex.Message)); } } } private static string GetPath(string key) { return Path.Combine(SaveDir, Sanitize(key) + ".json"); } private static string Sanitize(string raw) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); char[] array = raw.ToCharArray(); for (int i = 0; i < array.Length; i++) { if (Array.IndexOf(invalidFileNameChars, array[i]) >= 0) { array[i] = '_'; } } return new string(array); } } public static class ArmoryAmmoReserveApi { public const int ProtocolVersion = 1; private static readonly (WeaponAmmoType Type, string Label)[] Families = new(WeaponAmmoType, string)[4] { (WeaponAmmoType.ShotgunShells, "SHOTGUN SHELLS"), (WeaponAmmoType.Fuel, "FLAMETHROWER PROPELLANT"), (WeaponAmmoType.SmallCaliberRounds, "SMALL CALIBER ROUNDS"), (WeaponAmmoType.HeavyCaliberRounds, "HEAVY CALIBER ROUNDS") }; private static readonly string[] NoIds = new string[0]; public static string[] GetAmmoFamilyIds() { try { List list = new List(Families.Length); for (int i = 0; i < Families.Length; i++) { list.Add(Families[i].Type.ToString()); } return list.ToArray(); } catch (Exception ex) { Warn("family enumeration", ex); return NoIds; } } public static string GetAmmoFamilyLabel(string familyId) { if (!TryResolve(familyId, out var index)) { return familyId; } return Families[index].Label; } public static int GetAmmoFamilyReserve(string familyId) { if (!TryResolve(familyId, out var index)) { return 0; } try { return AmmoReserve.Get(Families[index].Type); } catch (Exception ex) { Warn("reserve read", ex); return 0; } } public static int GetAmmoFamilyCapacity(string familyId) { if (!TryResolve(familyId, out var index)) { return 0; } try { return AmmoReserve.MaximumFor(Families[index].Type); } catch (Exception ex) { Warn("capacity read", ex); return 0; } } private static bool TryResolve(string familyId, out int index) { index = -1; if (string.IsNullOrWhiteSpace(familyId)) { return false; } for (int i = 0; i < Families.Length; i++) { if (string.Equals(Families[i].Type.ToString(), familyId, StringComparison.Ordinal)) { index = i; return true; } } return false; } private static void Warn(string what, Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[ArmoryAmmoReserveApi] " + what + " failed safely: " + ex.Message)); } } } internal sealed class WeaponContentSettings { internal ConfigEntry Enabled; internal ConfigEntry PurchasableInShop; internal ConfigEntry ShopPrice; internal ConfigEntry SpawnsInInteriors; internal ConfigEntry InteriorSpawnRarity; internal ConfigEntry ScrapValue; internal ConfigEntry EnemyDamageNear; internal ConfigEntry EnemyDamageFar; internal ConfigEntry PlayerDamageNear; internal ConfigEntry PlayerDamageFar; internal ConfigEntry MagazineSize; internal ConfigEntry FireCadenceMultiplier; internal ConfigEntry SpreadMultiplier; internal ConfigEntry Weight; internal ConfigEntry TwoHanded; internal ConfigEntry TwoHandedAnimation; internal ConfigEntry FlameEnemyDamagePerTick; internal ConfigEntry FlameDamageTickSeconds; } internal sealed class AmmoFamilySettings { internal ConfigEntry PurchasableInShop; internal ConfigEntry ShopPrice; internal ConfigEntry RoundsPerBox; internal ConfigEntry SpawnsInInteriors; internal ConfigEntry InteriorSpawnRarity; internal ConfigEntry MaxReservePerPlayer; internal ConfigEntry StartingReserve; internal ConfigEntry VanillaShotgunSharesReserve; } internal static class ArmoryContentConfig { internal const string ShopSection = "Shop"; internal const int DefaultWeaponInteriorRarity = 8; private static readonly Dictionary Weapons = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary AmmoFamilies = new Dictionary(); private static bool _applied; internal static ConfigEntry ShopPriceMultiplier { get; private set; } internal static bool VanillaShotgunSharesShellReserve { get { AmmoFamilySettings ammoFamilySettings = ForFamily(WeaponAmmoType.ShotgunShells); if (ammoFamilySettings?.VanillaShotgunSharesReserve != null) { return ammoFamilySettings.VanillaShotgunSharesReserve.Value; } return true; } } internal static string FamilyName(WeaponAmmoType type) { return type switch { WeaponAmmoType.ShotgunShells => "Shotgun Shells", WeaponAmmoType.SmallCaliberRounds => "Small Caliber Rounds", WeaponAmmoType.HeavyCaliberRounds => "Heavy Caliber Rounds", WeaponAmmoType.Fuel => "Fuel", WeaponAmmoType.Grenades => "Grenades", _ => type.ToString(), }; } private static int DefaultShopPrice(WeaponAmmoType type) { return type switch { WeaponAmmoType.ShotgunShells => 20, WeaponAmmoType.SmallCaliberRounds => 20, WeaponAmmoType.HeavyCaliberRounds => 30, WeaponAmmoType.Fuel => 25, WeaponAmmoType.Grenades => 40, _ => 20, }; } private static int DefaultMaxReserve(WeaponAmmoType type) { if (type != WeaponAmmoType.Grenades) { return 0; } return 2; } internal static string WeaponSection(WeaponConfig config) { return "Weapon: " + config.DisplayName; } internal static string AmmoSection(WeaponAmmoType type) { return "Ammo: " + FamilyName(type); } internal static void Bind(ConfigFile config) { if (config == null) { return; } ShopPriceMultiplier = config.Bind("Shop", "Shop Price Multiplier", 1f, "Multiplier applied to every Y4NGZ weapon and ammunition shop price before it is shown in the terminal. 1.0 leaves each 'Shop Price' exactly as configured. Prices are re-read on each terminal redraw, so this takes effect without a restart. Terminal purchases are host-authoritative, but the printed price comes from the reading player's config - keep this identical across a lobby."); Weapons.Clear(); foreach (WeaponConfig item in WeaponCatalog.AllRegistered()) { BindWeapon(config, item); } AmmoFamilies.Clear(); foreach (AmmoPickupConfig item2 in AmmoPickupCatalog.All()) { BindAmmoFamily(config, item2); } } private static void BindWeapon(ConfigFile config, WeaponConfig weapon) { if (weapon != null && !Weapons.ContainsKey(weapon.Id)) { string text = WeaponSection(weapon); WeaponContentSettings weaponContentSettings = new WeaponContentSettings { Enabled = config.Bind(text, "Enabled", true, "Register this weapon at all. When false it is never built, never registered as an item, never appears in the shop or in interiors, and is dropped from the LUCKY-8 prize pool. Existing saves holding one will find the item missing, so prefer the shop and interior toggles below for balance changes. Registration is per machine: every player in a lobby must agree."), PurchasableInShop = config.Bind(text, "Purchasable In Shop", true, "List this weapon in the terminal store. ON by default: a buyable armoury is what this mod is for. Turn it off to keep this weapon out of the store without disabling it. Purchases are host-authoritative, but the printed listing comes from the reading player's config."), ShopPrice = config.Bind(text, "Shop Price", weapon.CreditsWorth, "Terminal store price in credits, before 'Shop / Shop Price Multiplier'. Re-read on each terminal redraw."), SpawnsInInteriors = config.Bind(text, "Spawns In Interiors", false, "Let this weapon spawn as interior loot. Off by default: weapons have never spawned in interiors and turning one on is a real balance change."), InteriorSpawnRarity = config.Bind(text, "Interior Spawn Rarity", 8, "Spawn weight in every moon's scrap pool, used only while 'Spawns In Interiors' is on. Higher is more common; compare against the ammunition families' 18 and vanilla scrap, which runs from about 5 to 100. Zero also removes the weapon from the pool. Weights are recomputed every round, so this needs no restart."), ScrapValue = config.Bind(text, "Scrap Value", weapon.CreditsWorth, "Credits this weapon is worth when sold as scrap. Applied when the item is built, so it takes a restart, and it is read on the host when a spawned instance rolls its value."), Weight = config.Bind(text, "Weight", weapon.Weight, "Carried weight in Lethal Company's units, where 1.0 is weightless and each 0.01 above it is one pound in the HUD. Applied when the item is built, so it takes a restart."), TwoHanded = config.Bind(text, "Two Handed", weapon.TwoHanded, "Whether carrying this weapon occupies both hands, which blocks the sprint, ladder and second-item interactions a one-handed item allows. Applied when the item is built, so it takes a restart. Evaluated per machine: every player in a lobby must use the same value."), TwoHandedAnimation = config.Bind(text, "Two Handed Animation", weapon.TwoHandedAnimation, "Whether the player's third-person carry pose uses the two-handed hold. Applied when the item is built, so it takes a restart, and every player in a lobby must use the same value. CAUTION: this is a pose, not a rule - setting it against what the weapon's authored hold was built for makes the model sit wrong in other players' hands even though it looks correct in your own.") }; if (weapon.Native) { weaponContentSettings.EnemyDamageNear = config.Bind(text, "Enemy Damage Near", weapon.EnemyDamageClose, "Damage dealt to CREATURES at point-blank range, falling off linearly to 'Enemy Damage Far' at the weapon's maximum range. This is Lethal Company's own enemy damage scale, NOT player health: most creatures have between 1 and 10 hit points (a Bracken has 5, a Hoarding Bug 3, a Thumper 6) and a shovel hits for 1, so 1 to 3 is the normal range for a weapon here and small changes are large balance changes. On a weapon that fires a pattern this is PER PELLET - the Heavy Shotgun's ten pellets each apply this value at their own distance. Zero means the weapon does not damage creatures at all. HOST-AUTHORITATIVE: enemy damage is resolved on the server, so the host's value is the one that lands."); weaponContentSettings.EnemyDamageFar = config.Bind(text, "Enemy Damage Far", weapon.EnemyDamageFar, "Damage dealt to CREATURES at maximum range, on the same 1-to-10 enemy scale as 'Enemy Damage Near' and per pellet in the same way. HOST-AUTHORITATIVE."); weaponContentSettings.PlayerDamageNear = config.Bind(text, "Player Damage Near", weapon.PlayerDamageClose, "Friendly-fire damage dealt to PLAYERS at point-blank range, falling off linearly to 'Player Damage Far' at the weapon's maximum range. This is player health, where a player has 100 - so it is a completely different scale from the 'Enemy Damage' pair above and must not be tuned against it. Applied once per shot rather than per pellet. Resolved on the victim's own machine."); weaponContentSettings.PlayerDamageFar = config.Bind(text, "Player Damage Far", weapon.PlayerDamageFar, "Friendly-fire damage dealt to PLAYERS at maximum range, out of 100 player health. Same scale as 'Player Damage Near'."); weaponContentSettings.MagazineSize = config.Bind(text, "Magazine Size", weapon.MagazineSize, "Rounds the weapon holds when full. Read locally by every player's reload, HUD and save/load path, so this MUST MATCH across a lobby - a mismatch makes two players disagree about when the gun is empty."); weaponContentSettings.FireCadenceMultiplier = config.Bind(text, "Fire Cadence Multiplier", 1f, "Multiplier on the weapon's rate of fire. 2.0 fires twice as fast, 0.5 half as fast. Applied to the authored rounds-per-minute (or, on a weapon that has none, to its shot cooldown). Evaluated locally: keep it identical across a lobby."); weaponContentSettings.SpreadMultiplier = config.Bind(text, "Spread Multiplier", 1f, "Multiplier on the weapon's base spread cone, before the movement, stance, shot and recoil bloom terms. Below 1 tightens the pattern. The crosshair is sized from the same number, so it follows automatically. Pellets are resolved on the shooter's machine."); } else if (weapon.Id == "grenade_launcher") { weaponContentSettings.MagazineSize = config.Bind(text, "Magazine Size", weapon.MagazineSize, "Grenades the launcher holds when full. Read locally by the reload path, so this MUST MATCH across a lobby."); } if (weapon.Id == "flame_thrower") { weaponContentSettings.FlameEnemyDamagePerTick = config.Bind(text, "Enemy Damage Per Tick", 1, "Direct damage dealt to CREATURES caught in the stream on each damage tick. On Lethal Company's enemy scale, where most creatures have between 1 and 10 hit points and a shovel hits for 1. This is on TOP of the burning effect the stream applies, which ticks for 1 on its own - so the shipped 1 per second here is about 2 health per second in total. HOST-AUTHORITATIVE: the stream is resolved on the server."); weaponContentSettings.FlameDamageTickSeconds = config.Bind(text, "Damage Tick Interval Seconds", 1f, "Seconds between damage ticks while a creature is held in the stream. Lower is faster and therefore more damage per second; 1.0 is the shipped value. Clamped to between 0.1 and 10. HOST-AUTHORITATIVE, same as 'Enemy Damage Per Tick'."); } Weapons[weapon.Id] = weaponContentSettings; } } private static void BindAmmoFamily(ConfigFile config, AmmoPickupConfig pickup) { if (pickup != null && !AmmoFamilies.ContainsKey(pickup.AmmoType)) { string text = AmmoSection(pickup.AmmoType); AmmoFamilySettings ammoFamilySettings = new AmmoFamilySettings { PurchasableInShop = config.Bind(text, "Purchasable In Shop", true, "List " + pickup.DisplayName + " in the terminal store. ON by default: buyable weapons are only usable alongside buyable ammunition. Interior spawning stays on as well, so ammunition is both found and bought."), ShopPrice = config.Bind(text, "Shop Price", DefaultShopPrice(pickup.AmmoType), "Terminal store price in credits for one " + pickup.DisplayName + " pickup, before 'Shop / Shop Price Multiplier'. One purchase delivers one pickup, which grants 'Rounds Per Box' rounds when collected."), RoundsPerBox = config.Bind(text, "Rounds Per Box", pickup.DefaultRoundsGranted, "Reserve rounds granted when one " + pickup.DisplayName + " pickup is collected. Each player consumes their own pickup locally."), SpawnsInInteriors = config.Bind(text, "Spawns In Interiors", true, "Let " + pickup.DisplayName + " spawn as interior loot. On by default - this is how ammunition has always been distributed."), InteriorSpawnRarity = config.Bind(text, "Interior Spawn Rarity", pickup.DefaultScrapRarity, "Spawn weight in every moon's scrap pool, used only while 'Spawns In Interiors' is on. Higher is more common. Zero also removes the pickup from the pool. Weights are recomputed every round, so this needs no restart."), MaxReservePerPlayer = config.Bind(text, "Max Reserve Per Player", DefaultMaxReserve(pickup.AmmoType), "Hard cap on how much of this family one player may carry in reserve. 0 means unlimited. Enforced on pickup, on purchase delivery and on the reserve file itself, so lowering it clamps an over-full reserve on the next save. The reserve is per player and per save, so this is a local rule, not a host one."), StartingReserve = config.Bind(text, "Starting Reserve", 0, "Reserve rounds of this family granted ONCE per save file, the first time that save's reserve is loaded. Raising it later does not re-grant; a save that has already been granted is marked as such in its reserve file. Clamped by 'Max Reserve Per Player'.") }; if (pickup.AmmoType == WeaponAmmoType.ShotgunShells) { ammoFamilySettings.VanillaShotgunSharesReserve = config.Bind(text, "Vanilla Shotgun Shares Shell Reserve", true, "Let Lethal Company's own shotgun reload from this reserve once it has run out of hotbar ammo. Hotbar shells always take priority; this is only the fallback. Turn it off to keep the shell reserve exclusively for Y4NGZ weapons."); } AmmoFamilies[pickup.AmmoType] = ammoFamilySettings; } } internal static void ApplyToCatalogs() { if (_applied) { return; } _applied = true; foreach (WeaponConfig item in WeaponCatalog.AllRegistered()) { if (item == null || !Weapons.TryGetValue(item.Id, out var value)) { continue; } try { if (value.ScrapValue != null) { item.CreditsWorth = Mathf.Max(0, value.ScrapValue.Value); } if (value.EnemyDamageNear != null) { item.EnemyDamageClose = Mathf.Max(0, value.EnemyDamageNear.Value); } if (value.EnemyDamageFar != null) { item.EnemyDamageFar = Mathf.Max(0, value.EnemyDamageFar.Value); } if (value.PlayerDamageNear != null) { item.PlayerDamageClose = Mathf.Max(0, value.PlayerDamageNear.Value); } if (value.PlayerDamageFar != null) { item.PlayerDamageFar = Mathf.Max(0, value.PlayerDamageFar.Value); } if (value.FlameEnemyDamagePerTick != null) { FlamethrowerStreamDriver.DirectDamage = Mathf.Max(0, value.FlameEnemyDamagePerTick.Value); } if (value.FlameDamageTickSeconds != null) { FlamethrowerStreamDriver.DamageInterval = Mathf.Clamp(value.FlameDamageTickSeconds.Value, 0.1f, 10f); } if (value.MagazineSize != null) { item.MagazineSize = Mathf.Max(1, value.MagazineSize.Value); } if (value.Weight != null) { item.Weight = Mathf.Max(1f, value.Weight.Value); } if (value.TwoHanded != null) { item.TwoHanded = value.TwoHanded.Value; } if (value.TwoHandedAnimation != null) { item.TwoHandedAnimation = value.TwoHandedAnimation.Value; } if (value.SpreadMultiplier != null) { item.SpreadDegrees = Mathf.Max(0f, item.SpreadDegrees * Mathf.Max(0f, value.SpreadMultiplier.Value)); } if (value.FireCadenceMultiplier != null) { float num = Mathf.Max(0.01f, value.FireCadenceMultiplier.Value); if (item.RoundsPerMinute > 0f) { item.RoundsPerMinute *= num; } else if (item.FireCooldownSeconds > 0f) { item.FireCooldownSeconds /= num; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZArmoryConfig] Could not apply config to " + item.DisplayName + "; its authored values stand: " + ex.Message)); } } } } private static WeaponContentSettings ForWeapon(string weaponId) { if (weaponId == null || !Weapons.TryGetValue(weaponId, out var value)) { return null; } return value; } private static AmmoFamilySettings ForFamily(WeaponAmmoType type) { if (!AmmoFamilies.TryGetValue(type, out var value)) { return null; } return value; } internal static bool IsWeaponEnabled(string weaponId) { WeaponContentSettings weaponContentSettings = ForWeapon(weaponId); if (weaponContentSettings?.Enabled != null) { return weaponContentSettings.Enabled.Value; } return true; } internal static bool IsWeaponPurchasable(string weaponId) { WeaponContentSettings weaponContentSettings = ForWeapon(weaponId); if (weaponContentSettings?.PurchasableInShop != null) { return weaponContentSettings.PurchasableInShop.Value; } return false; } internal static int WeaponShopPrice(string weaponId, int fallback) { WeaponContentSettings weaponContentSettings = ForWeapon(weaponId); return ScalePrice((weaponContentSettings?.ShopPrice != null) ? weaponContentSettings.ShopPrice.Value : fallback); } internal static int WeaponInteriorWeight(string weaponId) { WeaponContentSettings weaponContentSettings = ForWeapon(weaponId); if (weaponContentSettings?.SpawnsInInteriors == null || !weaponContentSettings.SpawnsInInteriors.Value) { return 0; } if (weaponContentSettings.InteriorSpawnRarity == null) { return 0; } return Math.Max(0, weaponContentSettings.InteriorSpawnRarity.Value); } internal static bool IsAmmoPurchasable(WeaponAmmoType type) { AmmoFamilySettings ammoFamilySettings = ForFamily(type); if (ammoFamilySettings?.PurchasableInShop != null) { return ammoFamilySettings.PurchasableInShop.Value; } return false; } internal static int AmmoShopPrice(WeaponAmmoType type) { AmmoFamilySettings ammoFamilySettings = ForFamily(type); return ScalePrice((ammoFamilySettings?.ShopPrice != null) ? ammoFamilySettings.ShopPrice.Value : DefaultShopPrice(type)); } internal static int AmmoInteriorWeight(WeaponAmmoType type, int fallbackRarity) { AmmoFamilySettings ammoFamilySettings = ForFamily(type); if (ammoFamilySettings == null) { return Math.Max(0, fallbackRarity); } if (ammoFamilySettings.SpawnsInInteriors != null && !ammoFamilySettings.SpawnsInInteriors.Value) { return 0; } if (ammoFamilySettings.InteriorSpawnRarity == null) { return Math.Max(0, fallbackRarity); } return Math.Max(0, ammoFamilySettings.InteriorSpawnRarity.Value); } internal static int RoundsPerBox(WeaponAmmoType type, int fallback) { AmmoFamilySettings ammoFamilySettings = ForFamily(type); if (ammoFamilySettings?.RoundsPerBox == null) { return Math.Max(0, fallback); } return Math.Max(0, ammoFamilySettings.RoundsPerBox.Value); } internal static int MaxReserve(WeaponAmmoType type) { AmmoFamilySettings ammoFamilySettings = ForFamily(type); int num = ((ammoFamilySettings?.MaxReservePerPlayer != null) ? ammoFamilySettings.MaxReservePerPlayer.Value : DefaultMaxReserve(type)); if (num > 0) { return num; } return int.MaxValue; } internal static int StartingReserve(WeaponAmmoType type) { AmmoFamilySettings ammoFamilySettings = ForFamily(type); if (ammoFamilySettings?.StartingReserve == null) { return 0; } return Math.Max(0, ammoFamilySettings.StartingReserve.Value); } private static int ScalePrice(int raw) { float num = ((ShopPriceMultiplier != null) ? ShopPriceMultiplier.Value : 1f); return Math.Max(0, Mathf.RoundToInt((float)Math.Max(0, raw) * Mathf.Max(0f, num))); } } public static class ArmoryPresentationApi { public const int ProtocolVersion = 1; public static void StopPresentationForHeldItemStow(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return; } try { WeaponFirstPersonAnimation.StopForHeldItemStow(player); WeaponThirdPersonAnimation.StopForHeldItemStow(player); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[ArmoryPresentationApi] stow presentation stop failed safely: " + ex.Message)); } } } } public static class ArmoryPrizeApi { public const int ProtocolVersion = 1; private static readonly string[] NoIds = new string[0]; public static string[] GetWeaponPrizeIds() { try { WeaponRuntimeRegistry.TryRegisterAll(); List list = new List(); foreach (WeaponConfig item in WeaponCatalog.AllRegistered()) { if (item != null && !((Object)(object)WeaponRuntimeRegistry.ItemFor(item.Id) == (Object)null) && !((Object)(object)WeaponRuntimeRegistry.PrefabFor(item.Id) == (Object)null)) { list.Add(item.Id); } } return list.ToArray(); } catch (Exception ex) { Warn("weapon prize enumeration", ex); return NoIds; } } public static string GetWeaponDisplayName(string weaponId) { try { WeaponConfig weaponConfig = WeaponCatalog.ById(weaponId); return (weaponConfig != null && !string.IsNullOrWhiteSpace(weaponConfig.DisplayName)) ? weaponConfig.DisplayName : weaponId; } catch (Exception ex) { Warn("weapon display name", ex); return weaponId; } } public static GameObject GetWeaponPrizePrefab(string weaponId) { try { WeaponRuntimeRegistry.TryRegisterAll(); return WeaponRuntimeRegistry.PrefabFor(weaponId); } catch (Exception ex) { Warn("weapon prize prefab", ex); return null; } } public static Item GetWeaponItem(string weaponId) { try { WeaponRuntimeRegistry.TryRegisterAll(); return WeaponRuntimeRegistry.ItemFor(weaponId); } catch (Exception ex) { Warn("weapon item", ex); return null; } } public static void InitializeWeaponPrize(GameObject instance, string weaponId) { if ((Object)(object)instance == (Object)null) { return; } try { WeaponConfig weaponConfig = WeaponCatalog.ById(weaponId); if (weaponConfig != null) { ShotgunItem component = instance.GetComponent(); if ((Object)(object)component != (Object)null) { component.shellsLoaded = weaponConfig.MagazineSize; } Y4NGZWeaponBase component2 = instance.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.Magazine = weaponConfig.MagazineSize; } } } catch (Exception ex) { Warn("weapon prize initialisation", ex); } } public static string[] GetWeaponFingerprintTokens() { try { List list = new List(); foreach (WeaponConfig item in WeaponCatalog.AllRegistered()) { if (item != null) { list.Add(item.Id); list.Add(((Object)(object)WeaponRuntimeRegistry.ItemFor(item.Id) != (Object)null) ? "item" : "no-item"); list.Add(((Object)(object)WeaponRuntimeRegistry.PrefabFor(item.Id) != (Object)null) ? "prefab" : "no-prefab"); } } return list.ToArray(); } catch (Exception ex) { Warn("weapon fingerprint", ex); return NoIds; } } public static string[] GetAmmoPrizeIds() { try { AmmoPickupRegistry.TryRegisterAll(); List list = new List(); foreach (AmmoPickupConfig item in AmmoPickupCatalog.All()) { if (item != null && !((Object)(object)AmmoPickupRegistry.ItemFor(item.Id) == (Object)null) && !((Object)(object)AmmoPickupRegistry.PrefabFor(item.Id) == (Object)null)) { list.Add(item.Id); } } return list.ToArray(); } catch (Exception ex) { Warn("ammo prize enumeration", ex); return NoIds; } } public static string GetAmmoDisplayName(string pickupId) { try { AmmoPickupConfig ammoPickupConfig = AmmoPickupCatalog.ById(pickupId); return (ammoPickupConfig != null && !string.IsNullOrWhiteSpace(ammoPickupConfig.DisplayName)) ? ammoPickupConfig.DisplayName : pickupId; } catch (Exception ex) { Warn("ammo display name", ex); return pickupId; } } public static GameObject GetAmmoPrizePrefab(string pickupId) { try { AmmoPickupRegistry.TryRegisterAll(); return AmmoPickupRegistry.PrefabFor(pickupId); } catch (Exception ex) { Warn("ammo prize prefab", ex); return null; } } public static Item GetAmmoItem(string pickupId) { try { AmmoPickupRegistry.TryRegisterAll(); return AmmoPickupRegistry.ItemFor(pickupId); } catch (Exception ex) { Warn("ammo item", ex); return null; } } private static void Warn(string what, Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[ArmoryPrizeApi] " + what + " failed safely: " + ex.Message)); } } } internal static class BulletHoleDecalModel { internal const float StackedMinOffset = 0.002f; internal const float StackedMaxOffset = 0.02f; internal const float StackedStepDistance = 0.001f; internal const int StackedSlotCount = 19; internal static float OffsetForStackSlot(int slot) { int num = slot % 19; if (num < 0) { num += 19; } float num2 = 0.002f + (float)num * 0.001f; if (!(num2 <= 0.02f)) { return 0.02f; } return num2; } internal static float OpacityForRemaining(float remainingSeconds, float fadeSeconds) { if (remainingSeconds <= 0f) { return 0f; } if (fadeSeconds <= 0f || remainingSeconds >= fadeSeconds) { return 1f; } return remainingSeconds / fadeSeconds; } } internal static class DawnLibCompat { private sealed class FuncWeighted : IWeighted { private readonly Func _weight; internal FuncWeighted(Func weight) { _weight = weight; } public int GetWeight() { try { return Math.Max(0, (_weight != null) ? _weight() : 0); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Spawn weight read failed; treating as 0: " + ex.Message)); } return 0; } } } private sealed class ConfigGatedPurchasePredicate : ITerminalPurchasePredicate { private readonly Func _enabled; internal ConfigGatedPurchasePredicate(Func enabled) { _enabled = enabled; } public TerminalPurchaseResult CanPurchase() { try { if (_enabled == null || _enabled()) { return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Success(); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Shop predicate read failed; hiding the entry: " + ex.Message)); } } return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Hidden(); } } internal const string ItemNamespace = "y4ngz_upgrades"; [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void RegisterNetworkPrefab(GameObject prefab) { DawnLib.RegisterNetworkPrefab(prefab); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void FixMixerGroups(GameObject prefab) { DawnLib.FixMixerGroups(prefab); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void RegisterItem(string itemKey, Item item, Func shopEnabled = null, Func shopPrice = null, string shopDescription = null, Func interiorWeight = null) { if ((Object)(object)item == (Object)null || string.IsNullOrWhiteSpace(itemKey)) { return; } DawnLib.DefineItem(NamespacedKey.From("y4ngz_upgrades", itemKey), item, (Action)delegate(ItemInfoBuilder builder) { if (shopPrice != null) { string itemName = item.itemName; builder.DefineShop((Action)delegate(ShopBuilder shop) { shop.OverrideCost((IProvider)(object)new FuncProvider(shopPrice)); shop.SetPurchasePredicate((ITerminalPurchasePredicate)(object)new ConfigGatedPurchasePredicate(shopEnabled)); TerminalNode val = BuildInfoNode(itemName, shopDescription); if ((Object)(object)val != (Object)null) { shop.OverrideInfoNode(val); } }); } if (interiorWeight != null) { builder.DefineScrap((Action)delegate(ScrapBuilder scrap) { scrap.SetWeights((Action>)delegate(WeightTableBuilder w) { w.SetGlobalWeight((IWeighted)(object)new FuncWeighted(interiorWeight)); }); }); } }); } private static TerminalNode BuildInfoNode(string itemName, string description) { if (string.IsNullOrWhiteSpace(description)) { return null; } try { TerminalNode obj = ScriptableObject.CreateInstance(); ((Object)obj).name = "Y4NGZ_" + (itemName ?? "item") + "_InfoNode"; obj.displayText = description.TrimEnd() + "\n\n"; obj.clearPreviousText = true; obj.maxCharactersToType = 35; ((Object)obj).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)obj); return obj; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Could not build the store info node for '" + itemName + "'; DawnLib's placeholder text stands: " + ex.Message)); } return null; } } } internal static class FlamethrowerContentAssets { internal const string BundleFileName = "y4ngz-interactions-flamethrower-iktargets.animationbundle"; internal const string BundleInternalName = "y4ngz-interactions-flamethrower-iktargets.animationbundle"; internal const string PropPrefabName = "Y4NGZ_FPSFlamethrowerProp"; internal const string MuzzleName = "Y4NGZ_FlamethrowerMuzzle"; private static AssetBundle _bundle; private static GameObject _propPrefab; private static Material _runtimeWeaponMaterial; private static GameObject _vanillaStreamPrefab; private static AudioClip _vanillaLoopClip; private static float _nextVanillaAssetSearchTime; private static bool _missingParticleLogged; private static bool _missingAudioLogged; internal static GameObject LoadPropPrefab() { if ((Object)(object)_propPrefab != (Object)null) { return _propPrefab; } AssetBundle orLoadBundle = GetOrLoadBundle(); if ((Object)(object)orLoadBundle == (Object)null) { return null; } _propPrefab = orLoadBundle.LoadAsset("Y4NGZ_FPSFlamethrowerProp"); if ((Object)(object)_propPrefab == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[Flamethrower] consumer prop missing from y4ngz-interactions-flamethrower-iktargets.animationbundle."); } } return _propPrefab; } internal static Material LoadRuntimeWeaponMaterial() { //IL_0088: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_runtimeWeaponMaterial != (Object)null) { return _runtimeWeaponMaterial; } GameObject val = LoadPropPrefab(); Renderer val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren(true) : null); Material material = (((Object)(object)val2 != (Object)null) ? val2.sharedMaterial : null); Shader val3 = Shader.Find("HDRP/Lit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); if ((Object)(object)val3 == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[Flamethrower] no supported runtime shader was found for the weapon model."); } return null; } _runtimeWeaponMaterial = new Material(val3) { name = "Y4NGZ_Flamethrower_RuntimeMaterial", hideFlags = (HideFlags)61 }; Texture texture = GetTexture(material, "_BaseColorMap", "_MainTex"); Texture texture2 = GetTexture(material, "_NormalMap", "_BumpMap"); Texture texture3 = GetTexture(material, "_MaskMap", "_MetallicGlossMap"); SetTexture(_runtimeWeaponMaterial, texture, "_BaseColorMap", "_MainTex"); SetTexture(_runtimeWeaponMaterial, texture2, "_NormalMap", "_BumpMap"); SetTexture(_runtimeWeaponMaterial, texture3, "_MaskMap", "_MetallicGlossMap"); if ((Object)(object)texture2 != (Object)null) { _runtimeWeaponMaterial.EnableKeyword("_NORMALMAP"); } if (_runtimeWeaponMaterial.HasProperty("_BaseColor")) { _runtimeWeaponMaterial.SetColor("_BaseColor", Color.white); } if (_runtimeWeaponMaterial.HasProperty("_Color")) { _runtimeWeaponMaterial.SetColor("_Color", Color.white); } if (_runtimeWeaponMaterial.HasProperty("_Metallic")) { _runtimeWeaponMaterial.SetFloat("_Metallic", 0.2f); } if (_runtimeWeaponMaterial.HasProperty("_Smoothness")) { _runtimeWeaponMaterial.SetFloat("_Smoothness", 0.35f); } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Flamethrower] built runtime weapon material with shader '" + ((Object)val3).name + "' (baseColor=" + ((Object)(object)texture != (Object)null) + ", normal=" + ((Object)(object)texture2 != (Object)null) + ", mask=" + ((Object)(object)texture3 != (Object)null) + ").")); } return _runtimeWeaponMaterial; } internal static void ApplyRuntimeWeaponMaterial(GameObject prop) { Material val = LoadRuntimeWeaponMaterial(); if (!((Object)(object)prop == (Object)null) && !((Object)(object)val == (Object)null)) { Renderer[] componentsInChildren = prop.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].sharedMaterial = val; } } } private static Texture GetTexture(Material material, params string[] names) { if ((Object)(object)material == (Object)null) { return null; } foreach (string text in names) { if (material.HasProperty(text)) { Texture texture = material.GetTexture(text); if ((Object)(object)texture != (Object)null) { return texture; } } } return null; } private static void SetTexture(Material material, Texture texture, params string[] names) { if ((Object)(object)material == (Object)null || (Object)(object)texture == (Object)null) { return; } foreach (string text in names) { if (material.HasProperty(text)) { material.SetTexture(text, texture); } } } internal static GameObject CreateStreamObject(Transform muzzle) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)muzzle == (Object)null) { return null; } ResolveVanillaAssets(); GameObject val; if ((Object)(object)_vanillaStreamPrefab != (Object)null) { val = Object.Instantiate(_vanillaStreamPrefab, muzzle, false); ((Object)val).name = "Y4NGZ_RadMechBlueFlamethrowerParticle"; } else { val = CreateBlueFallback(muzzle); } val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.SetActive(false); return val; } internal static AudioClip LoadLoopClip() { ResolveVanillaAssets(); return _vanillaLoopClip; } private static AssetBundle GetOrLoadBundle() { if ((Object)(object)_bundle != (Object)null) { return _bundle; } foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if ((Object)(object)allLoadedAssetBundle != (Object)null && string.Equals(((Object)allLoadedAssetBundle).name, "y4ngz-interactions-flamethrower-iktargets.animationbundle", StringComparison.OrdinalIgnoreCase)) { _bundle = allLoadedAssetBundle; return _bundle; } } string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = (string.IsNullOrEmpty(directoryName) ? null : Path.Combine(directoryName, "y4ngz-interactions-flamethrower-iktargets.animationbundle")); if (string.IsNullOrEmpty(text) || !File.Exists(text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Flamethrower] consumer bundle missing: " + text)); } return null; } _bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)_bundle == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("[Flamethrower] failed to load consumer bundle: " + text)); } } return _bundle; } private static void ResolveVanillaAssets() { if (((Object)(object)_vanillaStreamPrefab != (Object)null && (Object)(object)_vanillaLoopClip != (Object)null) || Time.unscaledTime < _nextVanillaAssetSearchTime) { return; } _nextVanillaAssetSearchTime = Time.unscaledTime + 2f; if ((Object)(object)_vanillaStreamPrefab == (Object)null) { ParticleSystem val = null; ParticleSystem[] array = Resources.FindObjectsOfTypeAll(); foreach (ParticleSystem val2 in array) { if (!((Object)(object)val2 == (Object)null) && string.Equals(((Object)val2).name, "FlamethrowerParticle", StringComparison.OrdinalIgnoreCase)) { val = val2; if (((Component)val2).GetComponentsInChildren(true).Length > 1) { break; } } } if ((Object)(object)val != (Object)null) { _vanillaStreamPrefab = ((Component)val).gameObject; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Flamethrower] resolved vanilla RadMech FlamethrowerParticle hierarchy (children=" + ((Component)val).GetComponentsInChildren(true).Length + ").")); } } else if (!_missingParticleLogged) { _missingParticleLogged = true; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Flamethrower] vanilla RadMech FlamethrowerParticle is not loaded yet; using a blue fallback and retrying."); } } } if (!((Object)(object)_vanillaLoopClip == (Object)null)) { return; } _vanillaLoopClip = ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((AudioClip clip) => (Object)(object)clip != (Object)null && (string.Equals(((Object)clip).name, "Flamethrower", StringComparison.OrdinalIgnoreCase) || ((Object)clip).name.IndexOf("Flamethrower", StringComparison.OrdinalIgnoreCase) >= 0))); if ((Object)(object)_vanillaLoopClip == (Object)null && !_missingAudioLogged) { _missingAudioLogged = true; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"[Flamethrower] vanilla Flamethrower.ogg is not loaded yet; retrying."); } } } private static GameObject CreateBlueFallback(Transform muzzle) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00ad: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Y4NGZ_BlueFlameFallback"); val.transform.SetParent(muzzle, false); ParticleSystem obj = val.AddComponent(); MainModule main = obj.main; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.18f, 0.35f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(8f, 14f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.12f, 0.28f); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(0.18f, 0.55f, 1f, 0.9f), new Color(0.62f, 0.9f, 1f, 0.55f)); EmissionModule emission = obj.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(110f); ShapeModule shape = obj.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).angle = 5f; ((ShapeModule)(ref shape)).radius = 0.05f; ParticleSystemRenderer component = ((Component)obj).GetComponent(); Shader val2 = Shader.Find("Particles/Standard Unlit") ?? Shader.Find("Legacy Shaders/Particles/Additive"); if ((Object)(object)val2 != (Object)null) { Material val3 = new Material(val2) { name = "Y4NGZ_BlueFlameMaterial_Fallback", hideFlags = (HideFlags)61 }; if (val3.HasProperty("_Color")) { val3.SetColor("_Color", new Color(0.2f, 0.6f, 1f, 0.75f)); } ((Renderer)component).sharedMaterial = val3; } return val; } } internal static class FlamethrowerGroundFire { internal const float DefaultRadius = 1.6f; internal const float DefaultDurationSeconds = 5f; internal const float DefaultDwellSeconds = 1f; internal const int DefaultMaxPatches = 6; private const float SearchRetrySeconds = 2f; private const int MinPatches = 1; private const int MaxPatches = 24; private static readonly List Patches = new List(); private static GameObject _template; private static float _nextSearchTime; private static bool _missingLogged; internal static FlamethrowerGroundFirePatch Spawn(Vector3 position, float radius, float duration, PlayerControllerB sourcePlayer) { //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_005b: 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_0067: 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) if (Plugin.GroundFireEnabled != null && !Plugin.GroundFireEnabled.Value) { return null; } Transform val = ResolveContainer(); if ((Object)(object)val == (Object)null) { return null; } ResolveAssets(); if ((Object)(object)_template == (Object)null) { return null; } Prune(); EnforceCap(); GameObject val2 = new GameObject("Y4NGZ_FlamethrowerGroundFire"); val2.transform.SetParent(val, false); val2.transform.position = position; val2.transform.rotation = Quaternion.identity; FlamethrowerGroundFirePatch flamethrowerGroundFirePatch = val2.AddComponent(); Patches.Add(flamethrowerGroundFirePatch); flamethrowerGroundFirePatch.Initialize(_template, radius, duration, sourcePlayer); return flamethrowerGroundFirePatch; } internal static bool HasPatchNear(Vector3 position, float radius) { //IL_002c: 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_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) Prune(); for (int i = 0; i < Patches.Count; i++) { FlamethrowerGroundFirePatch flamethrowerGroundFirePatch = Patches[i]; if (!((Object)(object)flamethrowerGroundFirePatch == (Object)null)) { float num = Mathf.Max(radius, flamethrowerGroundFirePatch.Radius); Vector3 val = flamethrowerGroundFirePatch.Position - position; if (((Vector3)(ref val)).sqrMagnitude <= num * num) { return true; } } } return false; } internal static void Forget(FlamethrowerGroundFirePatch patch) { if (!((Object)(object)patch == (Object)null)) { Patches.Remove(patch); } } internal static float ResolveRadius() { if (Plugin.GroundFireRadius == null) { return 1.6f; } return Mathf.Clamp(Plugin.GroundFireRadius.Value, 0.3f, 6f); } internal static float ResolveDuration() { if (Plugin.GroundFireDurationSeconds == null) { return 5f; } return Mathf.Clamp(Plugin.GroundFireDurationSeconds.Value, 0.5f, 30f); } private static void EnforceCap() { int num = ((Plugin.GroundFireMaxPatches != null) ? Mathf.Clamp(Plugin.GroundFireMaxPatches.Value, 1, 24) : 6); while (Patches.Count >= num) { FlamethrowerGroundFirePatch flamethrowerGroundFirePatch = Patches[0]; if ((Object)(object)flamethrowerGroundFirePatch == (Object)null) { Patches.RemoveAt(0); continue; } flamethrowerGroundFirePatch.Extinguish(); if (Patches.Count > 0 && (Object)(object)Patches[0] == (Object)(object)flamethrowerGroundFirePatch) { Patches.RemoveAt(0); } } } private static void Prune() { for (int num = Patches.Count - 1; num >= 0; num--) { if ((Object)(object)Patches[num] == (Object)null) { Patches.RemoveAt(num); } } } private static Transform ResolveContainer() { RoundManager instance = RoundManager.Instance; GameObject val = (((Object)(object)instance != (Object)null) ? instance.mapPropsContainer : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.transform; } private static void ResolveAssets() { if ((Object)(object)_template != (Object)null || Time.unscaledTime < _nextSearchTime) { return; } _nextSearchTime = Time.unscaledTime + 2f; GameObject val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.explosionPrefab : null); if ((Object)(object)val == (Object)null) { WarnMissingOnce("StartOfRound has no explosionPrefab yet"); return; } Transform val2 = FindDescendant(val.transform, "LingeringFire"); if ((Object)(object)val2 == (Object)null) { WarnMissingOnce("the vanilla explosion prefab carries no LingeringFire child"); return; } _template = ((Component)val2).gameObject; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[GroundFire] resolved the vanilla LingeringFire subtree (particles=" + _template.GetComponentsInChildren(true).Length + ", lights=" + _template.GetComponentsInChildren(true).Length + ").")); } } private static Transform FindDescendant(Transform root, string name) { Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root && ((Object)val).name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) { return val; } } return null; } private static void WarnMissingOnce(string reason) { if (!_missingLogged) { _missingLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GroundFire] " + reason + "; lingering fire stays off and the search retries.")); } } } } internal sealed class FlamethrowerGroundFirePatch : MonoBehaviour { private struct RigLight { internal Light Light; internal float BaseRange; internal float BaseIntensity; } private const float AuthoredRadius = 2.5f; private const float BurnTickInterval = 1f; private const float FadeSeconds = 1f; private const float VerticalReach = 2.5f; private const float BurnDurationSeconds = 3f; private const int BurnDamagePerTick = 1; private const float BurnTickIntervalSeconds = 1f; private const float MinScale = 0.15f; private const float MaxScale = 2f; private GameObject _visual; private RigLight[] _lights; private float _radius; private float _endTime; private float _nextBurnTime; private int _sourcePlayerId = -1; private bool _extinguishing; private float _fadeEndTime; internal Vector3 Position => ((Component)this).transform.position; internal float Radius => _radius; internal void Initialize(GameObject template, float radius, float duration, PlayerControllerB sourcePlayer) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00d5: Unknown result type (might be due to invalid IL or missing references) _radius = Mathf.Max(0.2f, radius); _endTime = Time.time + Mathf.Max(0.5f, duration); _nextBurnTime = Time.time + 0.25f; _sourcePlayerId = (((Object)(object)sourcePlayer != (Object)null) ? ((int)sourcePlayer.playerClientId) : (-1)); _visual = VanillaCloneStaging.CloneInactive(template, ((Component)this).transform, "Y4NGZ_LingeringFire"); if ((Object)(object)_visual == (Object)null) { return; } float num = Mathf.Clamp(_radius / 2.5f, 0.15f, 2f); _visual.transform.localScale = Vector3.one * num; ParticleSystem[] componentsInChildren = _visual.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!((Object)(object)componentsInChildren[i] == (Object)null)) { MainModule main = componentsInChildren[i].main; ((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0; } } CacheLights(num); _visual.SetActive(true); } internal void Extinguish() { if (_extinguishing) { return; } _extinguishing = true; _fadeEndTime = Time.time + 1f; if ((Object)(object)_visual != (Object)null) { ParticleSystem[] componentsInChildren = _visual.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { componentsInChildren[i].Stop(true, (ParticleSystemStopBehavior)1); } } } ReleaseLights(); FlamethrowerGroundFire.Forget(this); Object.Destroy((Object)(object)((Component)this).gameObject, 1f); } private void CacheLights(float scale) { //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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_0075: Unknown result type (might be due to invalid IL or missing references) List list = new List(_visual.GetComponentsInChildren(true)); if (list.Count == 0) { GameObject val = new GameObject("Y4NGZ_GroundFire_Light"); val.transform.SetParent(_visual.transform, false); val.transform.localPosition = Vector3.up * 0.4f; Light val2 = val.AddComponent(); val2.type = (LightType)2; val2.color = new Color(1f, 0.42f, 0.12f); val2.range = Mathf.Max(3f, _radius * 4f); val2.intensity = 4.5f; val2.bounceIntensity = 0.28f; list.Add(val2); } _lights = new RigLight[list.Count]; for (int i = 0; i < list.Count; i++) { Light val3 = list[i]; if (!((Object)(object)val3 == (Object)null)) { val3.shadows = (LightShadows)0; val3.range = Mathf.Max(3f, val3.range * scale); _lights[i].Light = val3; _lights[i].BaseRange = val3.range; _lights[i].BaseIntensity = val3.intensity; UpgradesBridge.RegisterFireLight(val3); } } } private void Update() { UpgradesBridge.TickFireLightBudget(); if (_extinguishing) { AdvanceFade(); } else if (Time.time >= _endTime) { Extinguish(); } else if (IsServer() && Time.time >= _nextBurnTime) { _nextBurnTime = Time.time + 1f; BurnEnemiesInside(); } } private void BurnEnemiesInside() { //IL_002c: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00a8: Unknown result type (might be due to invalid IL or missing references) List list = (((Object)(object)RoundManager.Instance != (Object)null) ? RoundManager.Instance.SpawnedEnemies : null); if (list == null) { return; } PlayerControllerB sourcePlayer = ResolveSourcePlayer(); Vector3 position = ((Component)this).transform.position; float num = _radius * _radius; for (int i = 0; i < list.Count; i++) { EnemyAI val = list[i]; if (!((Object)(object)val == (Object)null) && !val.isEnemyDead) { Vector3 position2 = ((Component)val).transform.position; float num2 = position2.x - position.x; float num3 = position2.z - position.z; if (!(num2 * num2 + num3 * num3 > num) && !(Mathf.Abs(position2.y - position.y) > 2.5f)) { EnemyStatusEffects.ApplyBurning(val, sourcePlayer, 3f, 1, 1f); } } } } private PlayerControllerB ResolveSourcePlayer() { if (_sourcePlayerId < 0 || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return null; } if (_sourcePlayerId >= StartOfRound.Instance.allPlayerScripts.Length) { return null; } return StartOfRound.Instance.allPlayerScripts[_sourcePlayerId]; } private void AdvanceFade() { float num = Mathf.Clamp01((_fadeEndTime - Time.time) / 1f); if (_lights == null) { return; } for (int i = 0; i < _lights.Length; i++) { Light light = _lights[i].Light; if (!((Object)(object)light == (Object)null)) { light.range = _lights[i].BaseRange * num; light.intensity = _lights[i].BaseIntensity * num; if (num <= 0f) { ((Behaviour)light).enabled = false; } } } } private void ReleaseLights() { if (_lights != null) { for (int i = 0; i < _lights.Length; i++) { UpgradesBridge.UnregisterFireLight(_lights[i].Light); } } } private void OnDestroy() { ReleaseLights(); FlamethrowerGroundFire.Forget(this); } private static bool IsServer() { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } } internal static class FlamethrowerScorchDecals { private struct Mark { internal GameObject Instance; internal Vector3 Position; internal Vector3 Normal; } internal const int DefaultMaxMarks = 32; internal const float DefaultMinSpacing = 1.2f; private const float SearchRetrySeconds = 2f; private const float SurfaceOffset = 0.012f; private const float SameSurfaceNormalDot = 0.6f; private const int MinMarks = 4; private const int MaxMarks = 128; private static readonly Func HasBlastMark = (RadMechAI mech) => (Object)(object)mech.blastMarkPrefab != (Object)null; private static readonly int SupportDecalsId = Shader.PropertyToID("_SupportDecals"); private const string DisableDecalsKeyword = "_DISABLE_DECALS"; private static readonly List Marks = new List(); private static readonly HashSet ReceptiveMaterials = new HashSet(); private static GameObject _markPrefab; private static Vector3 _markSurfaceAxis = Vector3.up; private static bool _markIsProjector; private static float _nextSearchTime; private static bool _missingLogged; private static Transform _container; private static int _recycleIndex; internal static void Spawn(Vector3 point, Vector3 normal, Renderer surface) { //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_0055: 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_005f: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_008c: 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) if ((Plugin.ScorchMarksEnabled != null && !Plugin.ScorchMarksEnabled.Value) || ((Vector3)(ref normal)).sqrMagnitude < 0.0001f) { return; } Transform val = ResolveContainer(); if ((Object)(object)val == (Object)null) { return; } ResolveAssets(); if ((Object)(object)_markPrefab == (Object)null) { return; } SyncPool(val); normal = ((Vector3)(ref normal)).normalized; if (!HasMarkNear(point, normal)) { Quaternion val2 = ResolveRotation(normal); Vector3 val3 = point + normal * 0.012f; int num = ResolveMaxMarks(); if (Marks.Count >= num) { RecycleOldest(val3, val2, normal, num); } else { GameObject instance = Object.Instantiate(_markPrefab, val3, val2, val); Marks.Add(new Mark { Instance = instance, Position = val3, Normal = normal }); } if (_markIsProjector) { EnsureSurfaceReceivesDecals(surface); } } } internal static void Clear() { Marks.Clear(); _recycleIndex = 0; _container = null; } private static void RecycleOldest(Vector3 position, Quaternion rotation, Vector3 normal, int cap) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0055: 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_0091: 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) for (int i = 0; i < Marks.Count; i++) { _recycleIndex = (_recycleIndex + 1) % Marks.Count; Mark value = Marks[_recycleIndex]; if (!((Object)(object)value.Instance == (Object)null)) { value.Instance.transform.SetPositionAndRotation(position, rotation); value.Position = position; value.Normal = normal; Marks[_recycleIndex] = value; return; } } Marks.Clear(); _recycleIndex = 0; if (cap > 0) { Spawn(position, normal, null); } } private static bool HasMarkNear(Vector3 point, Vector3 normal) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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) float num = ((Plugin.ScorchMarkSpacing != null) ? Mathf.Max(0.05f, Plugin.ScorchMarkSpacing.Value) : 1.2f); float num2 = num * num; for (int i = 0; i < Marks.Count; i++) { Mark mark = Marks[i]; if (!((Object)(object)mark.Instance == (Object)null)) { Vector3 val = mark.Position - point; if (!(((Vector3)(ref val)).sqrMagnitude > num2) && Vector3.Dot(mark.Normal, normal) >= 0.6f) { return true; } } } return false; } private static Quaternion ResolveRotation(Vector3 normal) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_001d: 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) float num = Random.Range(0f, 360f); if (_markIsProjector) { return Quaternion.LookRotation(-normal) * Quaternion.Euler(0f, 0f, num); } return Quaternion.FromToRotation(_markSurfaceAxis, normal) * Quaternion.AngleAxis(num, normal); } private static int ResolveMaxMarks() { return Mathf.Clamp((Plugin.ScorchMarkPoolSize != null) ? Plugin.ScorchMarkPoolSize.Value : 32, 4, 128); } private static Transform ResolveContainer() { RoundManager instance = RoundManager.Instance; GameObject val = (((Object)(object)instance != (Object)null) ? instance.mapPropsContainer : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.transform; } private static void SyncPool(Transform container) { if ((Object)(object)_container != (Object)(object)container) { Marks.Clear(); _recycleIndex = 0; _container = container; return; } for (int num = Marks.Count - 1; num >= 0; num--) { if ((Object)(object)Marks[num].Instance == (Object)null) { Marks.RemoveAt(num); } } if (_recycleIndex >= Marks.Count) { _recycleIndex = 0; } } private unsafe static void ResolveAssets() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_markPrefab != (Object)null || Time.unscaledTime < _nextSearchTime) { return; } _nextSearchTime = Time.unscaledTime + 2f; RadMechAI val = VanillaEnemyPrefabs.Find(HasBlastMark); if ((Object)(object)val == (Object)null) { if (!_missingLogged) { _missingLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Scorch] no RadMech prefab is loaded yet; scorch marks stay off and the search retries."); } } return; } _markPrefab = val.blastMarkPrefab; _markIsProjector = (Object)(object)_markPrefab.GetComponentInChildren(true) != (Object)null; _markSurfaceAxis = ResolveSurfaceAxis(_markPrefab); ManualLogSource log2 = Plugin.Log; if (log2 != null) { string[] obj = new string[5] { "[Scorch] resolved the vanilla BlastMark (projector=", _markIsProjector.ToString(), ", surfaceAxis=", null, null }; Vector3 markSurfaceAxis = _markSurfaceAxis; obj[3] = ((object)(*(Vector3*)(&markSurfaceAxis))/*cast due to .constrained prefix*/).ToString(); obj[4] = ")."; log2.LogInfo((object)string.Concat(obj)); } } private static Vector3 ResolveSurfaceAxis(GameObject prefab) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) //IL_003a: 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_0024: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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: 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_005b: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_00af: Unknown result type (might be due to invalid IL or missing references) MeshFilter componentInChildren = prefab.GetComponentInChildren(true); Mesh val = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.sharedMesh : null); if ((Object)(object)val == (Object)null) { return Vector3.up; } Bounds bounds = val.bounds; Vector3 size = ((Bounds)(ref bounds)).size; Vector3 val2 = ((size.y <= size.x && size.y <= size.z) ? Vector3.up : ((!(size.z <= size.x) || !(size.z <= size.y)) ? Vector3.right : Vector3.forward)); Vector3 val3 = prefab.transform.InverseTransformDirection(((Component)componentInChildren).transform.TransformDirection(val2)); if (!(((Vector3)(ref val3)).sqrMagnitude > 0.0001f)) { return Vector3.up; } return ((Vector3)(ref val3)).normalized; } private static void EnsureSurfaceReceivesDecals(Renderer surface) { if ((Object)(object)surface == (Object)null || (Plugin.ScorchMarkForceReceiveDecals != null && !Plugin.ScorchMarkForceReceiveDecals.Value)) { return; } Material[] sharedMaterials = surface.sharedMaterials; if (sharedMaterials == null) { return; } foreach (Material val in sharedMaterials) { if (!((Object)(object)val == (Object)null) && ReceptiveMaterials.Add(((Object)val).GetInstanceID())) { if (val.HasProperty(SupportDecalsId)) { val.SetFloat(SupportDecalsId, 1f); } val.DisableKeyword("_DISABLE_DECALS"); if (val.renderQueue >= 2000 && val.renderQueue < 2225) { val.renderQueue = 2225; } else if (val.renderQueue >= 2450 && val.renderQueue < 2475) { val.renderQueue = 2475; } } } } } internal sealed class FlamethrowerStreamDriver : MonoBehaviour { private struct StreamParticle { internal ParticleSystem System; internal float BaseRate; internal float BaseSize; } [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnUseMessage; public static HandleNamedMessageDelegate <1>__OnAimMessage; public static HandleNamedMessageDelegate <2>__OnReloadMessage; public static HandleNamedMessageDelegate <3>__OnStateMessage; public static HandleNamedMessageDelegate <4>__OnGroundFireMessage; public static Action <5>__OnClientDisconnect; } internal const float MaxRange = 8f; internal const float MuzzleRadius = 0.2f; internal const float EndRadius = 0.9f; internal const float FuelPerSecond = 10f; internal const float DefaultDamageInterval = 1f; internal const int DefaultDirectDamage = 1; internal static float DamageInterval = 1f; internal static int DirectDamage = 1; internal const float AimSendInterval = 0.1f; internal const float AimTimeout = 0.25f; internal const float ReloadDuration = 4.2f; internal const int TankCapacity = 100; private const int DirectHitId = -9410; private const float StreamAttackSeconds = 0.25f; private const float StreamReleaseSeconds = 0.6f; private const float StreamMinSizeScale = 0.6f; private const float StreamTailCapSeconds = 2f; private const float StreamLightRange = 10f; private const float StreamLightIntensity = 4.5f; private const float MinimumVisibleLightIntensity = 4.5f; private const float ScorchSampleInterval = 0.1f; private const float ScorchDwellSeconds = 0.6f; private const float GroundFireSampleInterval = 0.1f; private const float GroundFireMinNormalY = 0.5f; private const string MsgUse = "Y4NGZ_Flamethrower_Use"; private const string MsgAim = "Y4NGZ_Flamethrower_Aim"; private const string MsgReload = "Y4NGZ_Flamethrower_Reload"; private const string MsgState = "Y4NGZ_Flamethrower_State"; private const string MsgGroundFire = "Y4NGZ_Flamethrower_GroundFire"; private static readonly List Instances = new List(); private static NetworkManager _registeredManager; private ShotgunItem _shotgun; private Y4NGZWeaponItem _weapon; private bool _localTriggerHeld; private bool _localReloading; private float _nextAimSendTime; private bool _serverInitialized; private bool _serverFiring; private bool _serverReloading; private ulong _serverFiringClientId = ulong.MaxValue; private ulong _serverReloadClientId = ulong.MaxValue; private float _serverFuelExact; private float _serverLastAimTime; private float _serverLastAimMessageTime; private float _serverLastUseMessageTime; private float _serverReloadEndTime; private int _serverReloadRequested; private float _nextDamageTime; private float _nextStateTime; private Vector3 _serverOrigin; private Vector3 _serverDirection = Vector3.forward; private bool _replicatedFiring; private bool _replicatedReloading; private GameObject _streamObject; private Transform _streamMuzzle; private AudioSource _streamAudio; private float _nextEffectResolveTime; private StreamParticle[] _streamParticles; private Light _streamLight; private bool _streamEmitting; private float _streamIntensity; private float _streamTarget; private float _streamTailSeconds; private float _streamTailTimer; private float _streamAudioVolume = 1f; private float _nextScorchSampleTime; private float _lastScorchSampleTime; private Vector3 _scorchDwellPoint; private Vector3 _scorchDwellNormal; private Renderer _scorchDwellSurface; private float _scorchDwellSeconds; private bool _scorchDwellValid; private float _nextGroundFireSampleTime; private float _lastGroundFireSampleTime; private Vector3 _groundFireDwellPoint; private float _groundFireDwellSeconds; private bool _groundFireDwellValid; private static readonly HashSet SeenEnemies = new HashSet(); internal bool IsReloading { get { if (!_localReloading && !_serverReloading) { return _replicatedReloading; } return true; } } private void Awake() { _shotgun = ((Component)this).GetComponent(); _weapon = ((Component)this).GetComponent(); if (!Instances.Contains(this)) { Instances.Add(this); } RegisterNetworkHandlers(); SuppressVanillaGunPresentation(); } private void OnDestroy() { Instances.Remove(this); } private void OnDisable() { if (_localTriggerHeld) { SetLocalUse(firing: false); } if (IsServer()) { bool serverReloading = _serverReloading; _serverReloading = false; _serverReloadRequested = 0; _serverReloadClientId = ulong.MaxValue; ServerStopStream(broadcast: true); if (serverReloading && !_serverFiring) { BroadcastState(force: true, 0); } } StopEffects(); } private void Update() { //IL_005d: 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) RegisterNetworkHandlers(); SuppressVanillaGunPresentation(); if (IsLocalHolder()) { if (_localTriggerHeld && !IsEquippedAndAlive()) { SetLocalUse(firing: false); } else if (_localTriggerHeld && Time.unscaledTime >= _nextAimSendTime) { _nextAimSendTime = Time.unscaledTime + 0.1f; ResolveAim(out var origin, out var direction); SendAim(origin, direction); } } if (IsServer()) { ServerTick(); } if (_replicatedFiring) { EnsureEffects(); } AdvanceStreamEnvelope(); AdvanceScorchDwell(); } private void AdvanceScorchDwell() { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) if (!_replicatedFiring) { _scorchDwellValid = false; _scorchDwellSeconds = 0f; _lastScorchSampleTime = 0f; return; } if (Time.time < _nextScorchSampleTime) { return; } float num = ((_lastScorchSampleTime > 0f) ? Mathf.Min(Time.time - _lastScorchSampleTime, 0.5f) : 0.1f); _lastScorchSampleTime = Time.time; _nextScorchSampleTime = Time.time + 0.1f; if (!TryTraceStream(out var hit)) { _scorchDwellValid = false; _scorchDwellSeconds = 0f; return; } float num2 = ((Plugin.ScorchMarkSpacing != null) ? Mathf.Max(0.05f, Plugin.ScorchMarkSpacing.Value) : 1.2f); if (_scorchDwellValid) { Vector3 val = ((RaycastHit)(ref hit)).point - _scorchDwellPoint; if (((Vector3)(ref val)).sqrMagnitude <= num2 * num2) { _scorchDwellSeconds += num; goto IL_010e; } } _scorchDwellPoint = ((RaycastHit)(ref hit)).point; _scorchDwellValid = true; _scorchDwellSeconds = num; goto IL_010e; IL_010e: _scorchDwellNormal = ((RaycastHit)(ref hit)).normal; _scorchDwellSurface = ResolveHitRenderer(hit); float num3 = ((Plugin.ScorchMarkDwellSeconds != null) ? Mathf.Max(0.05f, Plugin.ScorchMarkDwellSeconds.Value) : 0.6f); if (!(_scorchDwellSeconds < num3)) { FlamethrowerScorchDecals.Spawn(_scorchDwellPoint, _scorchDwellNormal, _scorchDwellSurface); _scorchDwellSeconds = 0f; _scorchDwellPoint = ((RaycastHit)(ref hit)).point; } } private bool TryTraceStream(out RaycastHit hit) { //IL_0001: 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_0043: Unknown result type (might be due to invalid IL or missing references) hit = default(RaycastHit); if (((Vector3)(ref _serverDirection)).sqrMagnitude < 0.0001f) { return false; } int num = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-5)); return Physics.Raycast(_serverOrigin, ((Vector3)(ref _serverDirection)).normalized, ref hit, 8f, num, (QueryTriggerInteraction)1); } private static Renderer ResolveHitRenderer(RaycastHit hit) { Collider collider = ((RaycastHit)(ref hit)).collider; if ((Object)(object)collider == (Object)null) { return null; } Renderer component = ((Component)collider).GetComponent(); if (!((Object)(object)component != (Object)null)) { return ((Component)collider).GetComponentInParent(); } return component; } internal void SetLocalUse(bool firing) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!IsLocalHolder()) { return; } firing = firing && !_localReloading && IsEquippedAndAlive() && _shotgun.shellsLoaded > 0; if (_localTriggerHeld != firing) { _localTriggerHeld = firing; CrosshairSignals.SetContinuousStream(firing); ((GrabbableObject)_shotgun).isBeingUsed = firing; ResolveAim(out var origin, out var direction); SendUse(firing, origin, direction); WeaponFirstPersonAnimation.SetContinuousFiring(_weapon, ((GrabbableObject)_shotgun).playerHeldBy, firing); if (!firing) { ApplyReplicatedState(firing: false, _replicatedReloading, _shotgun.shellsLoaded, 0); } } } internal bool TryBeginReload() { if (!IsLocalHolder() || !IsEquippedAndAlive() || _localReloading) { return false; } int num = 100 - Mathf.Clamp(_shotgun.shellsLoaded, 0, 100); int num2 = AmmoReserve.Get(WeaponAmmoType.Fuel); if (num <= 0 || num2 <= 0) { return false; } SetLocalUse(firing: false); _localReloading = true; _shotgun.isReloading = true; WeaponFirstPersonAnimation.OnWeaponReloadStarted(_weapon, ((GrabbableObject)_shotgun).playerHeldBy); TriggerWorldPropReload(); SendReload(Mathf.Min(num, num2)); return true; } internal void ForceLocalStop() { SetLocalUse(firing: false); _localReloading = false; if ((Object)(object)_shotgun != (Object)null) { _shotgun.isReloading = false; } ApplyReplicatedState(firing: false, reloading: false, ((Object)(object)_shotgun != (Object)null) ? _shotgun.shellsLoaded : 0, 0); } internal static void RegisterNetworkHandlers() { //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_004c: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00c2: 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) //IL_00cd: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.CustomMessagingManager == null || (Object)(object)singleton == (Object)(object)_registeredManager) { return; } try { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__OnUseMessage; if (obj == null) { HandleNamedMessageDelegate val = OnUseMessage; <>O.<0>__OnUseMessage = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("Y4NGZ_Flamethrower_Use", (HandleNamedMessageDelegate)obj); CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager; object obj2 = <>O.<1>__OnAimMessage; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnAimMessage; <>O.<1>__OnAimMessage = val2; obj2 = (object)val2; } customMessagingManager2.RegisterNamedMessageHandler("Y4NGZ_Flamethrower_Aim", (HandleNamedMessageDelegate)obj2); CustomMessagingManager customMessagingManager3 = singleton.CustomMessagingManager; object obj3 = <>O.<2>__OnReloadMessage; if (obj3 == null) { HandleNamedMessageDelegate val3 = OnReloadMessage; <>O.<2>__OnReloadMessage = val3; obj3 = (object)val3; } customMessagingManager3.RegisterNamedMessageHandler("Y4NGZ_Flamethrower_Reload", (HandleNamedMessageDelegate)obj3); CustomMessagingManager customMessagingManager4 = singleton.CustomMessagingManager; object obj4 = <>O.<3>__OnStateMessage; if (obj4 == null) { HandleNamedMessageDelegate val4 = OnStateMessage; <>O.<3>__OnStateMessage = val4; obj4 = (object)val4; } customMessagingManager4.RegisterNamedMessageHandler("Y4NGZ_Flamethrower_State", (HandleNamedMessageDelegate)obj4); CustomMessagingManager customMessagingManager5 = singleton.CustomMessagingManager; object obj5 = <>O.<4>__OnGroundFireMessage; if (obj5 == null) { HandleNamedMessageDelegate val5 = OnGroundFireMessage; <>O.<4>__OnGroundFireMessage = val5; obj5 = (object)val5; } customMessagingManager5.RegisterNamedMessageHandler("Y4NGZ_Flamethrower_GroundFire", (HandleNamedMessageDelegate)obj5); singleton.OnClientDisconnectCallback += OnClientDisconnect; _registeredManager = singleton; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[Flamethrower] registered stream network handlers."); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Flamethrower] network handler registration failed: " + ex.Message)); } } } private void ServerTick() { if (!_serverInitialized) { _serverFuelExact = Mathf.Clamp(_shotgun.shellsLoaded, 0, 100); _serverInitialized = true; _nextStateTime = Time.unscaledTime; } if (_serverFiring) { if (!SenderOwnsHeldWeapon(_serverFiringClientId) || Time.unscaledTime - _serverLastAimTime > 0.25f) { ServerStopStream(broadcast: true); } else { _serverFuelExact = Mathf.Max(0f, _serverFuelExact - 10f * Time.deltaTime); _shotgun.shellsLoaded = Mathf.Clamp(Mathf.CeilToInt(_serverFuelExact), 0, 100); if (_serverFuelExact <= 0f) { _shotgun.shellsLoaded = 0; ServerStopStream(broadcast: true); } else { if (Time.time >= _nextDamageTime) { _nextDamageTime = Time.time + DamageInterval; DamageExposedEnemies(); } AdvanceGroundFireDwell(); } } } if (_serverReloading) { if (!SenderOwnsHeldWeapon(_serverReloadClientId)) { _serverReloading = false; _serverReloadRequested = 0; _serverReloadClientId = ulong.MaxValue; BroadcastState(force: true, 0); } else if (Time.unscaledTime >= _serverReloadEndTime) { int num = Mathf.Clamp(Mathf.CeilToInt(_serverFuelExact), 0, 100); int num2 = Mathf.Min(100 - num, _serverReloadRequested); _serverFuelExact = num + num2; _shotgun.shellsLoaded = num + num2; _serverReloading = false; _serverReloadRequested = 0; _serverReloadClientId = ulong.MaxValue; BroadcastState(force: true, num2); } } float num3 = ((_serverFiring || _serverReloading) ? 0.1f : 1f); if (Time.unscaledTime >= _nextStateTime) { _nextStateTime = Time.unscaledTime + num3; BroadcastState(force: false, 0); } } private void ServerSetUse(ulong senderClientId, bool firing, Vector3 origin, Vector3 direction) { //IL_0050: 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_005c: 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_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) EnsureServerInitialized(); if (!SenderOwnsHeldWeapon(senderClientId)) { return; } if (!firing) { ServerStopStream(broadcast: true); } else { if (Time.unscaledTime - _serverLastUseMessageTime < 0.05f) { return; } _serverLastUseMessageTime = Time.unscaledTime; if (_serverReloading || _serverFuelExact <= 0f || !ValidateAim(origin, direction)) { return; } _serverOrigin = origin; _serverDirection = ((Vector3)(ref direction)).normalized; _serverLastAimTime = Time.unscaledTime; _serverLastAimMessageTime = Time.unscaledTime; if (!_serverFiring) { _serverFiring = true; _serverFiringClientId = senderClientId; if (_nextDamageTime <= 0f) { _nextDamageTime = Time.time; } BroadcastState(force: true, 0); } } } private void ServerSetAim(ulong senderClientId, Vector3 origin, Vector3 direction) { //IL_0026: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (_serverFiring && SenderOwnsHeldWeapon(senderClientId) && !(Time.unscaledTime - _serverLastAimMessageTime < 0.05f) && ValidateAim(origin, direction)) { _serverLastAimMessageTime = Time.unscaledTime; _serverLastAimTime = Time.unscaledTime; _serverOrigin = origin; _serverDirection = ((Vector3)(ref direction)).normalized; } } private void ServerBeginReload(ulong senderClientId, int requested) { EnsureServerInitialized(); if (SenderOwnsHeldWeapon(senderClientId) && !_serverReloading && requested > 0) { int num = Mathf.Clamp(Mathf.CeilToInt(_serverFuelExact), 0, 100); if (num < 100) { ServerStopStream(broadcast: false); _serverReloading = true; _serverReloadClientId = senderClientId; _serverReloadRequested = Mathf.Clamp(requested, 1, 100 - num); _serverReloadEndTime = Time.unscaledTime + 4.2f; BroadcastState(force: true, 0); } } } private void ServerStopStream(bool broadcast) { if (_serverFiring) { _serverFiring = false; _serverFiringClientId = ulong.MaxValue; ResetGroundFireDwell(); if (broadcast) { BroadcastState(force: true, 0); } } } private void AdvanceGroundFireDwell() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) if ((Plugin.GroundFireEnabled != null && !Plugin.GroundFireEnabled.Value) || Time.time < _nextGroundFireSampleTime) { return; } float num = ((_lastGroundFireSampleTime > 0f) ? Mathf.Min(Time.time - _lastGroundFireSampleTime, 0.5f) : 0.1f); _lastGroundFireSampleTime = Time.time; _nextGroundFireSampleTime = Time.time + 0.1f; if (!TryTraceStream(out var hit) || ((RaycastHit)(ref hit)).normal.y < 0.5f) { ResetGroundFireDwell(); return; } float num2 = FlamethrowerGroundFire.ResolveRadius(); if (_groundFireDwellValid) { Vector3 val = ((RaycastHit)(ref hit)).point - _groundFireDwellPoint; if (((Vector3)(ref val)).sqrMagnitude <= num2 * num2) { _groundFireDwellSeconds += num; goto IL_00e6; } } _groundFireDwellPoint = ((RaycastHit)(ref hit)).point; _groundFireDwellValid = true; _groundFireDwellSeconds = num; goto IL_00e6; IL_00e6: float num3 = ((Plugin.GroundFireDwellSeconds != null) ? Mathf.Max(0.1f, Plugin.GroundFireDwellSeconds.Value) : 1f); if (!(_groundFireDwellSeconds < num3)) { _groundFireDwellSeconds = 0f; if (!FlamethrowerGroundFire.HasPatchNear(_groundFireDwellPoint, num2)) { float duration = FlamethrowerGroundFire.ResolveDuration(); FlamethrowerGroundFire.Spawn(_groundFireDwellPoint, num2, duration, ((GrabbableObject)_shotgun).playerHeldBy); BroadcastGroundFire(_groundFireDwellPoint, num2, duration); } } } private void ResetGroundFireDwell() { _groundFireDwellValid = false; _groundFireDwellSeconds = 0f; _lastGroundFireSampleTime = 0f; } private void EnsureServerInitialized() { if (!_serverInitialized) { _serverFuelExact = Mathf.Clamp(((Object)(object)_shotgun != (Object)null) ? _shotgun.shellsLoaded : 0, 0, 100); _serverInitialized = true; _nextStateTime = Time.unscaledTime; } } private void DamageExposedEnemies() { PlayerControllerB playerHeldBy = ((GrabbableObject)_shotgun).playerHeldBy; if ((Object)(object)playerHeldBy == (Object)null) { return; } SeenEnemies.Clear(); List list = (((Object)(object)RoundManager.Instance != (Object)null) ? RoundManager.Instance.SpawnedEnemies : null); if (list != null) { for (int i = 0; i < list.Count; i++) { DamageEnemyIfExposed(list[i], playerHeldBy); } return; } EnemyAI[] array = Object.FindObjectsOfType(); foreach (EnemyAI enemy in array) { DamageEnemyIfExposed(enemy, playerHeldBy); } } private void DamageEnemyIfExposed(EnemyAI enemy, PlayerControllerB sourcePlayer) { //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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemy == (Object)null || enemy.isEnemyDead || !SeenEnemies.Add(enemy)) { return; } Vector3 val = ResolveEnemyPoint(enemy); Vector3 val2 = val - _serverOrigin; float num = Vector3.Dot(val2, _serverDirection); if (!(num < 0f) && !(num > 8f)) { float num2 = Mathf.Lerp(0.2f, 0.9f, num / 8f); Vector3 val3 = val2 - _serverDirection * num; if (!(((Vector3)(ref val3)).sqrMagnitude > num2 * num2) && !IsWorldOccluded(_serverOrigin, val, enemy)) { enemy.HitEnemy(DirectDamage, sourcePlayer, false, -9410); int num3 = (((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null) ? ((int)GameNetworkManager.Instance.localPlayerController.playerClientId) : (-1)); enemy.HitEnemyClientRpc(DirectDamage, num3, false, -9410); EnemyStatusEffects.ApplyBurning(enemy, sourcePlayer, 3f, 1, 1f); } } } private static Vector3 ResolveEnemyPoint(EnemyAI enemy) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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) if (enemy.overlapColliders != null) { Collider[] overlapColliders = enemy.overlapColliders; foreach (Collider val in overlapColliders) { if ((Object)(object)val != (Object)null && val.enabled) { Bounds bounds = val.bounds; return ((Bounds)(ref bounds)).center; } } } return ((Component)enemy).transform.position + Vector3.up * 0.8f; } private static bool IsWorldOccluded(Vector3 origin, Vector3 point, EnemyAI target) { //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_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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) //IL_0037: 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) Vector3 val = point - origin; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.05f) { return false; } int num = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-5)); RaycastHit val2 = default(RaycastHit); if (!Physics.Raycast(origin, val / magnitude, ref val2, magnitude - 0.05f, num, (QueryTriggerInteraction)1)) { return false; } if (!((Object)(object)target == (Object)null)) { if ((Object)(object)((RaycastHit)(ref val2)).transform != (Object)(object)((Component)target).transform) { return !((RaycastHit)(ref val2)).transform.IsChildOf(((Component)target).transform); } return false; } return true; } private bool ValidateAim(Vector3 origin, Vector3 direction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!Finite(origin) || !Finite(direction) || ((Vector3)(ref direction)).sqrMagnitude < 0.64f || ((Vector3)(ref direction)).sqrMagnitude > 1.44f) { return false; } Transform val = (((Object)(object)_shotgun.shotgunRayPoint != (Object)null) ? _shotgun.shotgunRayPoint : ((Component)_shotgun).transform); return Vector3.Distance(origin, val.position) <= 2.5f; } private bool SenderOwnsHeldWeapon(ulong senderClientId) { if (ServerHolderValid()) { return ((GrabbableObject)_shotgun).playerHeldBy.playerClientId == senderClientId; } return false; } private bool ServerHolderValid() { PlayerControllerB val = (((Object)(object)_shotgun != (Object)null) ? ((GrabbableObject)_shotgun).playerHeldBy : null); if ((Object)(object)val != (Object)null && !val.isPlayerDead && ((GrabbableObject)_shotgun).isHeld && !((GrabbableObject)_shotgun).isPocketed) { return (Object)(object)val.currentlyHeldObjectServer == (Object)(object)_shotgun; } return false; } private bool IsEquippedAndAlive() { PlayerControllerB val = (((Object)(object)_shotgun != (Object)null) ? ((GrabbableObject)_shotgun).playerHeldBy : null); if ((Object)(object)val != (Object)null && !val.isPlayerDead && ((GrabbableObject)_shotgun).isHeld && !((GrabbableObject)_shotgun).isPocketed) { return (Object)(object)val.currentlyHeldObjectServer == (Object)(object)_shotgun; } return false; } private bool IsLocalHolder() { PlayerControllerB val = (((Object)(object)_shotgun != (Object)null) ? ((GrabbableObject)_shotgun).playerHeldBy : null); PlayerControllerB val2 = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { return (Object)(object)val == (Object)(object)val2; } return false; } private void ResolveAim(out Vector3 origin, out Vector3 direction) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_009c: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = (((Object)(object)_shotgun != (Object)null) ? ((GrabbableObject)_shotgun).playerHeldBy : null); Camera val2 = (((Object)(object)val != (Object)null) ? val.gameplayCamera : null); Transform val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).transform : (((Object)(object)_shotgun != (Object)null && (Object)(object)_shotgun.shotgunRayPoint != (Object)null) ? _shotgun.shotgunRayPoint : ((Component)this).transform)); Transform val4 = ResolveEffectMuzzle(); origin = (((Object)(object)val4 != (Object)null) ? val4.position : val3.position); Vector3 forward = val3.forward; direction = ((Vector3)(ref forward)).normalized; } private unsafe void SendUse(bool firing, Vector3 origin, Vector3 direction) { //IL_0040: 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_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_007d: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null || (Object)(object)_shotgun == (Object)null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(64, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)_shotgun).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref firing, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref origin); ((FastBufferWriter)(ref val)).WriteValueSafe(ref direction); singleton.CustomMessagingManager.SendNamedMessage("Y4NGZ_Flamethrower_Use", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe void SendAim(Vector3 origin, Vector3 direction) { //IL_0040: 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_006b: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null || (Object)(object)_shotgun == (Object)null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(64, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)_shotgun).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref origin); ((FastBufferWriter)(ref val)).WriteValueSafe(ref direction); singleton.CustomMessagingManager.SendNamedMessage("Y4NGZ_Flamethrower_Aim", 0uL, val, (NetworkDelivery)1); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe void SendReload(int requested) { //IL_0040: 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_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_006b: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null || (Object)(object)_shotgun == (Object)null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(24, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)_shotgun).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref requested, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("Y4NGZ_Flamethrower_Reload", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe void BroadcastState(bool force, int reloadAdded) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!IsServer() || ((singleton != null) ? singleton.CustomMessagingManager : null) == null || (Object)(object)_shotgun == (Object)null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(80, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)_shotgun).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); int num = Mathf.Clamp(_shotgun.shellsLoaded, 0, 100); ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref _serverFiring, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref _serverReloading, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref reloadAdded, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref _serverOrigin); ((FastBufferWriter)(ref val)).WriteValueSafe(ref _serverDirection); singleton.CustomMessagingManager.SendNamedMessageToAll("Y4NGZ_Flamethrower_State", val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe void BroadcastGroundFire(Vector3 position, float radius, float duration) { //IL_0036: 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_0048: 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_005f: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!IsServer() || ((singleton != null) ? singleton.CustomMessagingManager : null) == null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(40, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref position); ((FastBufferWriter)(ref val)).WriteValueSafe(ref radius, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref duration, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessageToAll("Y4NGZ_Flamethrower_GroundFire", val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void OnGroundFireMessage(ulong senderClientId, FastBufferReader reader) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_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) if (!((Object)(object)NetworkManager.Singleton == (Object)null) && senderClientId == 0L) { Vector3 position = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref position); float radius = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref radius, default(ForPrimitives)); float duration = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref duration, default(ForPrimitives)); if (!IsServer()) { FlamethrowerGroundFire.Spawn(position, radius, duration, null); } } } private static void OnUseMessage(ulong senderClientId, FastBufferReader reader) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) if (IsServer()) { ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); bool firing = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref firing, default(ForPrimitives)); Vector3 origin = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref origin); Vector3 direction = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref direction); Find(networkObjectId)?.ServerSetUse(senderClientId, firing, origin, direction); } } private static void OnAimMessage(ulong senderClientId, FastBufferReader reader) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0039: Unknown result type (might be due to invalid IL or missing references) if (IsServer()) { ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); Vector3 origin = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref origin); Vector3 direction = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref direction); Find(networkObjectId)?.ServerSetAim(senderClientId, origin, direction); } } private static void OnReloadMessage(ulong senderClientId, FastBufferReader reader) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0026: Unknown result type (might be due to invalid IL or missing references) if (IsServer()) { ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); int requested = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref requested, default(ForPrimitives)); Find(networkObjectId)?.ServerBeginReload(senderClientId, requested); } } private static void OnStateMessage(ulong senderClientId, FastBufferReader reader) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00a0: 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) if (!((Object)(object)NetworkManager.Singleton == (Object)null) && senderClientId == 0L) { ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); int fuel = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref fuel, default(ForPrimitives)); bool firing = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref firing, default(ForPrimitives)); bool reloading = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe(ref reloading, default(ForPrimitives)); int reloadAdded = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref reloadAdded, default(ForPrimitives)); Vector3 serverOrigin = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref serverOrigin); Vector3 serverDirection = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref serverDirection); FlamethrowerStreamDriver flamethrowerStreamDriver = Find(networkObjectId); if (!((Object)(object)flamethrowerStreamDriver == (Object)null)) { flamethrowerStreamDriver._serverOrigin = serverOrigin; flamethrowerStreamDriver._serverDirection = serverDirection; flamethrowerStreamDriver.ApplyReplicatedState(firing, reloading, fuel, reloadAdded); } } } private void ApplyReplicatedState(bool firing, bool reloading, int fuel, int reloadAdded) { bool flag = reloading && !_replicatedReloading; _replicatedFiring = firing && fuel > 0; _replicatedReloading = reloading; _shotgun.shellsLoaded = Mathf.Clamp(fuel, 0, 100); _shotgun.isReloading = reloading; if (IsLocalHolder()) { WeaponFirstPersonAnimation.SetContinuousFiring(_weapon, ((GrabbableObject)_shotgun).playerHeldBy, _replicatedFiring); if (!reloading) { _localReloading = false; } if (reloadAdded > 0 && !AmmoReserve.TryConsume(WeaponAmmoType.Fuel, reloadAdded)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Flamethrower] completed reload exceeded the owner's Fuel reserve snapshot."); } } } Animator val = ResolveWorldAnimator(); if ((Object)(object)val != (Object)null) { val.SetBool("Y4NGZ_FlamethrowerProp_Firing", _replicatedFiring); if (flag) { val.SetTrigger("Y4NGZ_FlamethrowerProp_Reload"); } } if (_replicatedFiring) { EnsureEffects(); } else { ReleaseEffects(); } } private void TriggerWorldPropReload() { Animator val = ResolveWorldAnimator(); if ((Object)(object)val != (Object)null) { val.SetTrigger("Y4NGZ_FlamethrowerProp_Reload"); } } private Animator ResolveWorldAnimator() { Transform val = ((Component)this).transform.Find("Y4NGZ_FlamethrowerVisual"); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent(); } private void EnsureEffects() { if ((Object)(object)_streamObject == (Object)null || Time.unscaledTime >= _nextEffectResolveTime) { _nextEffectResolveTime = Time.unscaledTime + 0.25f; Transform val = ResolveEffectMuzzle(); if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)_streamObject == (Object)null || (Object)(object)_streamMuzzle != (Object)(object)val) { if ((Object)(object)_streamObject != (Object)null) { Object.Destroy((Object)(object)_streamObject); } _streamMuzzle = val; _streamLight = null; _streamEmitting = false; _streamObject = FlamethrowerContentAssets.CreateStreamObject(val); CacheStreamParticles(); CreateStreamLight(); } } if ((Object)(object)_streamObject == (Object)null) { return; } _streamTarget = 1f; _streamTailTimer = 0f; if ((Object)(object)_streamObject != (Object)null && !_streamEmitting) { if (!_streamObject.activeSelf) { _streamObject.SetActive(false); _streamObject.SetActive(true); } for (int i = 0; i < _streamParticles.Length; i++) { ParticleSystem system = _streamParticles[i].System; if ((Object)(object)system != (Object)null) { system.Play(true); } } _streamEmitting = true; } if ((Object)(object)_streamAudio == (Object)null) { _streamAudio = ((Component)this).gameObject.AddComponent(); _streamAudio.loop = true; _streamAudio.playOnAwake = false; _streamAudio.spatialBlend = 1f; _streamAudio.minDistance = 1f; _streamAudio.maxDistance = 25f; _streamAudio.rolloffMode = (AudioRolloffMode)1; _streamAudio.clip = FlamethrowerContentAssets.LoadLoopClip(); _streamAudioVolume = _streamAudio.volume; _streamAudio.volume = 0f; } if ((Object)(object)_streamAudio.clip != (Object)null && !_streamAudio.isPlaying) { _streamAudio.Play(); } } private void CacheStreamParticles() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) _streamTailSeconds = 0f; if ((Object)(object)_streamObject == (Object)null) { _streamParticles = Array.Empty(); return; } ParticleSystem[] componentsInChildren = _streamObject.GetComponentsInChildren(true); _streamParticles = new StreamParticle[componentsInChildren.Length]; for (int i = 0; i < componentsInChildren.Length; i++) { ParticleSystem val = componentsInChildren[i]; StreamParticle[] streamParticles = _streamParticles; int num = i; StreamParticle streamParticle = new StreamParticle { System = val }; EmissionModule emission = val.emission; streamParticle.BaseRate = ((EmissionModule)(ref emission)).rateOverTimeMultiplier; MainModule main = val.main; streamParticle.BaseSize = ((MainModule)(ref main)).startSizeMultiplier; streamParticles[num] = streamParticle; float streamTailSeconds = _streamTailSeconds; main = val.main; MinMaxCurve startLifetime = ((MainModule)(ref main)).startLifetime; _streamTailSeconds = Mathf.Max(streamTailSeconds, ((MinMaxCurve)(ref startLifetime)).constantMax); } _streamTailSeconds = Mathf.Min(_streamTailSeconds, 2f); } private void CreateStreamLight() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_streamObject == (Object)null) && (Plugin.FlameStreamLightEnabled == null || Plugin.FlameStreamLightEnabled.Value)) { GameObject val = new GameObject("Y4NGZ_FlamethrowerStream_Light"); val.transform.SetParent(_streamObject.transform, false); val.transform.localPosition = Vector3.zero; _streamLight = val.AddComponent(); _streamLight.type = (LightType)2; _streamLight.color = new Color(1f, 0.42f, 0.12f); _streamLight.range = 10f; _streamLight.intensity = ResolveVisibleLightIntensity(); _streamLight.shadows = (LightShadows)0; _streamLight.bounceIntensity = 0.28f; ((Behaviour)_streamLight).enabled = false; } } private void AdvanceStreamEnvelope() { if (!((Object)(object)_streamObject == (Object)null) || !(_streamIntensity <= 0f) || !(_streamTarget <= 0f)) { float deltaTime = Time.deltaTime; if (_streamTarget > _streamIntensity) { float num = ((Plugin.FlameStreamAttackSeconds != null) ? Plugin.FlameStreamAttackSeconds.Value : 0.25f); _streamIntensity = Mathf.Min(_streamTarget, _streamIntensity + deltaTime / Mathf.Max(0.01f, num)); } else if (_streamTarget < _streamIntensity) { float num2 = ((Plugin.FlameStreamReleaseSeconds != null) ? Plugin.FlameStreamReleaseSeconds.Value : 0.6f); _streamIntensity = Mathf.Max(_streamTarget, _streamIntensity - deltaTime / Mathf.Max(0.01f, num2)); } if (_streamTailTimer > 0f) { _streamTailTimer = Mathf.Max(0f, _streamTailTimer - deltaTime); } ApplyStreamIntensity(); if (_streamIntensity <= 0f && _streamTailTimer <= 0f && !_streamEmitting && (Object)(object)_streamObject != (Object)null && _streamObject.activeSelf) { _streamObject.SetActive(false); } } } private void ApplyStreamIntensity() { //IL_005c: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Lerp(0.6f, 1f, _streamIntensity); if ((Object)(object)_streamObject != (Object)null && _streamObject.activeSelf && _streamParticles != null) { for (int i = 0; i < _streamParticles.Length; i++) { ParticleSystem system = _streamParticles[i].System; if (!((Object)(object)system == (Object)null)) { EmissionModule emission = system.emission; ((EmissionModule)(ref emission)).rateOverTimeMultiplier = _streamParticles[i].BaseRate * _streamIntensity; MainModule main = system.main; ((MainModule)(ref main)).startSizeMultiplier = _streamParticles[i].BaseSize * num; } } } if ((Object)(object)_streamLight != (Object)null) { ((Behaviour)_streamLight).enabled = _streamIntensity > 0f; if (((Behaviour)_streamLight).enabled) { float num2 = 0.75f + Mathf.PerlinNoise(Time.time * 15f, (float)((Object)this).GetInstanceID() * 0.01f) * 0.5f; _streamLight.intensity = ResolveVisibleLightIntensity() * _streamIntensity * num2; } } if ((Object)(object)_streamAudio != (Object)null) { _streamAudio.volume = _streamAudioVolume * _streamIntensity; if (_streamIntensity <= 0f && _streamAudio.isPlaying) { _streamAudio.Stop(); } } } private void ReleaseEffects() { _streamTarget = 0f; if ((Object)(object)_streamObject == (Object)null || !_streamEmitting) { return; } for (int i = 0; i < _streamParticles.Length; i++) { ParticleSystem system = _streamParticles[i].System; if ((Object)(object)system != (Object)null) { system.Stop(true, (ParticleSystemStopBehavior)1); } } _streamEmitting = false; _streamTailTimer = _streamTailSeconds; } private static float ResolveVisibleLightIntensity() { float num = ((Plugin.FlameStreamLightIntensity != null) ? Plugin.FlameStreamLightIntensity.Value : 4.5f); return Mathf.Max(4.5f, num); } private Transform ResolveEffectMuzzle() { Transform[] componentsInChildren; if (IsLocalHolder()) { PlayerControllerB playerHeldBy = ((GrabbableObject)_shotgun).playerHeldBy; if ((Object)(object)playerHeldBy != (Object)null) { componentsInChildren = ((Component)playerHeldBy).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((Object)val).name == "Y4NGZ_FlamethrowerMuzzle" && HasAncestorNamed(val, "Y4NGZ_FPSFlamethrowerProp")) { return val; } } } } Transform val2 = ((Component)this).transform.Find("Y4NGZ_FlamethrowerVisual"); if ((Object)(object)val2 == (Object)null) { return null; } componentsInChildren = ((Component)val2).GetComponentsInChildren(true); foreach (Transform val3 in componentsInChildren) { if (((Object)val3).name == "Y4NGZ_FlamethrowerMuzzle") { return val3; } } return null; } private void StopEffects() { _streamTarget = 0f; _streamIntensity = 0f; _streamTailTimer = 0f; _streamEmitting = false; if ((Object)(object)_streamObject != (Object)null) { ParticleSystem[] componentsInChildren = _streamObject.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].Stop(true, (ParticleSystemStopBehavior)0); } _streamObject.SetActive(false); } if ((Object)(object)_streamLight != (Object)null) { ((Behaviour)_streamLight).enabled = false; } if ((Object)(object)_streamAudio != (Object)null) { _streamAudio.volume = 0f; if (_streamAudio.isPlaying) { _streamAudio.Stop(); } } } private void SuppressVanillaGunPresentation() { if (!((Object)(object)_shotgun == (Object)null)) { _shotgun.safetyOn = true; _shotgun.hasHitGroundWithSafetyOff = false; _shotgun.misfireTimer = 0f; if ((Object)(object)_shotgun.gunShootParticle != (Object)null) { _shotgun.gunShootParticle.Stop(true, (ParticleSystemStopBehavior)0); ((Component)_shotgun.gunShootParticle).gameObject.SetActive(false); } } } private static FlamethrowerStreamDriver Find(ulong networkObjectId) { for (int num = Instances.Count - 1; num >= 0; num--) { FlamethrowerStreamDriver flamethrowerStreamDriver = Instances[num]; if ((Object)(object)flamethrowerStreamDriver == (Object)null) { Instances.RemoveAt(num); } else if ((Object)(object)flamethrowerStreamDriver._shotgun != (Object)null && ((NetworkBehaviour)flamethrowerStreamDriver._shotgun).NetworkObjectId == networkObjectId) { return flamethrowerStreamDriver; } } return null; } private static void OnClientDisconnect(ulong clientId) { if (!IsServer()) { return; } FlamethrowerStreamDriver[] array = Instances.ToArray(); foreach (FlamethrowerStreamDriver flamethrowerStreamDriver in array) { if ((Object)(object)flamethrowerStreamDriver != (Object)null && (Object)(object)((GrabbableObject)(flamethrowerStreamDriver._shotgun?)).playerHeldBy != (Object)null && ((GrabbableObject)flamethrowerStreamDriver._shotgun).playerHeldBy.playerClientId == clientId) { flamethrowerStreamDriver._serverReloading = false; flamethrowerStreamDriver._serverReloadRequested = 0; flamethrowerStreamDriver._serverReloadClientId = ulong.MaxValue; flamethrowerStreamDriver.ServerStopStream(broadcast: true); flamethrowerStreamDriver.BroadcastState(force: true, 0); } } } private static bool HasAncestorNamed(Transform transform, string name) { Transform val = transform; while ((Object)(object)val != (Object)null) { if (((Object)val).name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } private static bool IsServer() { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } private static bool Finite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (Finite(value.x) && Finite(value.y)) { return Finite(value.z); } return false; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal static class GrenadeContentAssets { internal const string BundleFileName = "y4ngz-upgrades-grenade-playeranimations.animationbundle"; internal const string BundleInternalName = "y4ngzupgrades-grenade-playeranimations"; internal const string PropPrefabName = "Y4NGZ_Grenade_Prop"; private static AssetBundle _bundle; private static GameObject _propPrefab; private static AudioClip _pinSound; private static AudioClip _throwSound; internal static GameObject LoadPropPrefab() { if ((Object)(object)_propPrefab != (Object)null) { return _propPrefab; } AssetBundle orLoadBundle = GetOrLoadBundle(); if ((Object)(object)orLoadBundle == (Object)null) { return null; } _propPrefab = orLoadBundle.LoadAsset("Y4NGZ_Grenade_Prop"); return _propPrefab; } internal static AudioClip LoadPinSound() { if ((Object)(object)_pinSound == (Object)null) { AssetBundle orLoadBundle = GetOrLoadBundle(); _pinSound = ((orLoadBundle != null) ? orLoadBundle.LoadAsset("S_Grenade_Pull_Pin") : null); } return _pinSound; } internal static AudioClip LoadThrowSound() { if ((Object)(object)_throwSound == (Object)null) { AssetBundle orLoadBundle = GetOrLoadBundle(); _throwSound = ((orLoadBundle != null) ? orLoadBundle.LoadAsset("S_Grenade_Throw") : null); } return _throwSound; } internal static GameObject CreateVisual(Transform parent) { GameObject val = LoadPropPrefab(); if ((Object)(object)val == (Object)null || (Object)(object)parent == (Object)null) { return null; } GameObject val2 = Object.Instantiate(val, parent, false); ((Object)val2).name = "Y4NGZ_GrenadeVisual"; val2.SetActive(true); Collider[] componentsInChildren = val2.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } Rigidbody[] componentsInChildren2 = val2.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.Destroy((Object)(object)componentsInChildren2[i]); } AudioSource[] componentsInChildren3 = val2.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.Destroy((Object)(object)componentsInChildren3[i]); } SetLayerRecursive(val2.transform, ((Component)parent).gameObject.layer); return val2; } private static AssetBundle GetOrLoadBundle() { if ((Object)(object)_bundle != (Object)null) { return _bundle; } foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if ((Object)(object)allLoadedAssetBundle != (Object)null && string.Equals(((Object)allLoadedAssetBundle).name, "y4ngzupgrades-grenade-playeranimations", StringComparison.OrdinalIgnoreCase)) { _bundle = allLoadedAssetBundle; return _bundle; } } string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = (string.IsNullOrEmpty(directoryName) ? null : Path.Combine(directoryName, "y4ngz-upgrades-grenade-playeranimations.animationbundle")); if (string.IsNullOrEmpty(text) || !File.Exists(text)) { return null; } _bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)_bundle == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Grenade] failed to load content bundle: " + text)); } } return _bundle; } private static void SetLayerRecursive(Transform root, int layer) { if (!((Object)(object)root == (Object)null)) { ((Component)root).gameObject.layer = layer; for (int i = 0; i < root.childCount; i++) { SetLayerRecursive(root.GetChild(i), layer); } } } } internal static class GrenadeLauncherContentAssets { internal const string BundleFileName = "y4ngz-interactions-grenadelauncher-iktargets.animationbundle"; internal const string BundleInternalName = "y4ngz-interactions-grenadelauncher-iktargets.animationbundle"; internal const string PropPrefabName = "Y4NGZ_FPSGrenadeLauncherProp"; private static AssetBundle _bundle; private static GameObject _propPrefab; private static Material _runtimeMaterial; internal static GameObject LoadPropPrefab() { if ((Object)(object)_propPrefab != (Object)null) { return _propPrefab; } AssetBundle orLoadBundle = GetOrLoadBundle(); if ((Object)(object)orLoadBundle == (Object)null) { return null; } _propPrefab = orLoadBundle.LoadAsset("Y4NGZ_FPSGrenadeLauncherProp"); if ((Object)(object)_propPrefab == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[GrenadeLauncher] consumer prop missing from y4ngz-interactions-grenadelauncher-iktargets.animationbundle."); } } return _propPrefab; } internal static Material LoadRuntimeWeaponMaterial() { //IL_0088: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_runtimeMaterial != (Object)null) { return _runtimeMaterial; } GameObject val = LoadPropPrefab(); Renderer val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren(true) : null); Material material = (((Object)(object)val2 != (Object)null) ? val2.sharedMaterial : null); Shader val3 = Shader.Find("HDRP/Lit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); if ((Object)(object)val3 == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)"[GrenadeLauncher] no supported runtime shader was found for the weapon model."); } return null; } _runtimeMaterial = new Material(val3) { name = "Y4NGZ_GrenadeLauncher_RuntimeMaterial", hideFlags = (HideFlags)61 }; Texture texture = GetTexture(material, "_BaseColorMap", "_MainTex"); Texture texture2 = GetTexture(material, "_NormalMap", "_BumpMap"); Texture texture3 = GetTexture(material, "_MaskMap", "_MetallicGlossMap"); SetTexture(_runtimeMaterial, texture, "_BaseColorMap", "_MainTex"); SetTexture(_runtimeMaterial, texture2, "_NormalMap", "_BumpMap"); SetTexture(_runtimeMaterial, texture3, "_MaskMap", "_MetallicGlossMap"); if ((Object)(object)texture2 != (Object)null) { _runtimeMaterial.EnableKeyword("_NORMALMAP"); } if (_runtimeMaterial.HasProperty("_BaseColor")) { _runtimeMaterial.SetColor("_BaseColor", Color.white); } if (_runtimeMaterial.HasProperty("_Color")) { _runtimeMaterial.SetColor("_Color", Color.white); } if (_runtimeMaterial.HasProperty("_Metallic")) { _runtimeMaterial.SetFloat("_Metallic", 0.35f); } if (_runtimeMaterial.HasProperty("_Smoothness")) { _runtimeMaterial.SetFloat("_Smoothness", 0.42f); } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[GrenadeLauncher] built runtime material with shader '" + ((Object)val3).name + "' (baseColor=" + ((Object)(object)texture != (Object)null) + ", normal=" + ((Object)(object)texture2 != (Object)null) + ", mask=" + ((Object)(object)texture3 != (Object)null) + ").")); } return _runtimeMaterial; } internal static void ApplyRuntimeWeaponMaterial(GameObject prop) { Material val = LoadRuntimeWeaponMaterial(); if ((Object)(object)prop == (Object)null || (Object)(object)val == (Object)null) { return; } Renderer[] componentsInChildren = prop.GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { Material[] sharedMaterials = val2.sharedMaterials; for (int j = 0; j < sharedMaterials.Length; j++) { sharedMaterials[j] = val; } val2.sharedMaterials = sharedMaterials; } } internal static GameObject CreateProjectileVisual(Transform parent) { //IL_0072: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) GameObject val = LoadPropPrefab(); Transform val2 = (((Object)(object)val != (Object)null) ? FindChild(val.transform, "slug1") : null); if ((Object)(object)val2 == (Object)null || (Object)(object)parent == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[GrenadeLauncher] authored slug1 projectile visual is unavailable."); } return null; } GameObject val3 = Object.Instantiate(((Component)val2).gameObject, parent, false); ((Object)val3).name = "Y4NGZ_GrenadeProjectileVisual"; val3.SetActive(true); val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); val3.transform.localScale = Vector3.one; ApplyRuntimeWeaponMaterial(val3); SetLayerRecursive(val3.transform, ((Component)parent).gameObject.layer); Collider[] componentsInChildren = val3.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } Rigidbody[] componentsInChildren2 = val3.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.Destroy((Object)(object)componentsInChildren2[i]); } Animator component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer[] componentsInChildren3 = val3.GetComponentsInChildren(true); if (componentsInChildren3.Length != 0) { Bounds bounds = componentsInChildren3[0].bounds; for (int j = 1; j < componentsInChildren3.Length; j++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren3[j].bounds); } float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z)); if (num > 0.0001f) { Transform transform = val3.transform; transform.localScale *= 0.16f / num; } bounds = componentsInChildren3[0].bounds; for (int k = 1; k < componentsInChildren3.Length; k++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren3[k].bounds); } Transform transform2 = val3.transform; transform2.position += parent.position - ((Bounds)(ref bounds)).center; } return val3; } private static AssetBundle GetOrLoadBundle() { if ((Object)(object)_bundle != (Object)null) { return _bundle; } foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if ((Object)(object)allLoadedAssetBundle != (Object)null && string.Equals(((Object)allLoadedAssetBundle).name, "y4ngz-interactions-grenadelauncher-iktargets.animationbundle", StringComparison.OrdinalIgnoreCase)) { _bundle = allLoadedAssetBundle; return _bundle; } } string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = (string.IsNullOrEmpty(directoryName) ? null : Path.Combine(directoryName, "y4ngz-interactions-grenadelauncher-iktargets.animationbundle")); if (string.IsNullOrEmpty(text) || !File.Exists(text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[GrenadeLauncher] consumer bundle missing: " + text)); } return null; } _bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)_bundle == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("[GrenadeLauncher] failed to load consumer bundle: " + text)); } } return _bundle; } private static Texture GetTexture(Material material, params string[] names) { if ((Object)(object)material == (Object)null) { return null; } foreach (string text in names) { if (material.HasProperty(text)) { Texture texture = material.GetTexture(text); if ((Object)(object)texture != (Object)null) { return texture; } } } return null; } private static void SetTexture(Material material, Texture texture, params string[] names) { if ((Object)(object)material == (Object)null || (Object)(object)texture == (Object)null) { return; } foreach (string text in names) { if (material.HasProperty(text)) { material.SetTexture(text, texture); } } } private static Transform FindChild(Transform root, string name) { if ((Object)(object)root == (Object)null) { return null; } if (string.Equals(((Object)root).name, name, StringComparison.OrdinalIgnoreCase)) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindChild(root.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static void SetLayerRecursive(Transform root, int layer) { ((Component)root).gameObject.layer = layer; for (int i = 0; i < root.childCount; i++) { SetLayerRecursive(root.GetChild(i), layer); } } } internal sealed class GrenadeLauncherProjectile : MonoBehaviour { private const float LaunchSpeed = 20f; private const float LaunchLift = 2.5f; private const float MaxFlightSeconds = 5f; private const float ClientCleanupSeconds = 7f; private const float KillRange = 1.35f; private const float DamageRange = 4.5f; private const int NonLethalDamage = 60; private const float PhysicsForce = 75f; private static readonly List Active = new List(); private Rigidbody _rigidbody; private ulong _weaponNetworkObjectId; private uint _shotId; private bool _authoritative; private bool _detonated; private bool _awaitingServerImpact; private float _spawnTime; internal static GameObject Spawn(Vector3 position, Vector3 direction, ulong weaponNetworkObjectId, uint shotId, bool authoritative) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_003a: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((((Vector3)(ref direction)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref direction)).normalized : Vector3.forward); GameObject val2 = new GameObject("Y4NGZ_GrenadeProjectile_" + shotId); val2.transform.position = position; val2.transform.rotation = Quaternion.LookRotation(val, Vector3.up); SphereCollider obj = val2.AddComponent(); obj.radius = 0.075f; ((Collider)obj).isTrigger = false; Rigidbody val3 = val2.AddComponent(); val3.useGravity = true; val3.mass = 0.4f; val3.drag = 0.035f; val3.angularDrag = 0.08f; val3.collisionDetectionMode = (CollisionDetectionMode)2; val3.interpolation = (RigidbodyInterpolation)1; if ((Object)(object)GrenadeLauncherContentAssets.CreateProjectileVisual(val2.transform) == (Object)null) { AttachFallbackVisual(val2.transform); } GrenadeLauncherProjectile grenadeLauncherProjectile = val2.AddComponent(); grenadeLauncherProjectile._rigidbody = val3; grenadeLauncherProjectile._weaponNetworkObjectId = weaponNetworkObjectId; grenadeLauncherProjectile._shotId = shotId; grenadeLauncherProjectile._authoritative = authoritative; grenadeLauncherProjectile._spawnTime = Time.time; IgnorePlayerCollisions((Collider)(object)obj); val3.velocity = val * 20f + Vector3.up * 2.5f; val3.angularVelocity = new Vector3(4f, 7f, 3f); Active.Add(grenadeLauncherProjectile); ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)($"[GrenadeLauncher] projectile {weaponNetworkObjectId}:{shotId} spawned " + $"authoritative={authoritative} at {position} velocity={val3.velocity}.")); } return val2; } internal static void DetonateSynced(ulong weaponNetworkObjectId, uint shotId, Vector3 position) { //IL_006a: 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_0041: Unknown result type (might be due to invalid IL or missing references) GrenadeLauncherProjectile grenadeLauncherProjectile = null; for (int i = 0; i < Active.Count; i++) { GrenadeLauncherProjectile grenadeLauncherProjectile2 = Active[i]; if (!((Object)(object)grenadeLauncherProjectile2 == (Object)null) && !grenadeLauncherProjectile2._detonated && grenadeLauncherProjectile2._weaponNetworkObjectId == weaponNetworkObjectId) { if ((Object)(object)grenadeLauncherProjectile == (Object)null) { grenadeLauncherProjectile = grenadeLauncherProjectile2; } if (grenadeLauncherProjectile2._shotId == shotId) { grenadeLauncherProjectile2.Detonate(position); return; } } } if ((Object)(object)grenadeLauncherProjectile != (Object)null) { grenadeLauncherProjectile.Detonate(position); } else { SpawnExplosion(position); } } internal static void DestroyAllActive() { GrenadeLauncherProjectile[] array = Active.ToArray(); Active.Clear(); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null) { Object.Destroy((Object)(object)((Component)array[i]).gameObject); } } } private void Update() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!_detonated) { float num = Time.time - _spawnTime; if (_authoritative && num >= 5f) { GrenadeLauncherPatches.PublishDetonation(_weaponNetworkObjectId, _shotId, ((Component)this).transform.position); } else if (!_authoritative && num >= 7f) { Cleanup(); } } } private void OnCollisionEnter(Collision collision) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0042: 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_0081: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if (_detonated || _awaitingServerImpact || ((Object)(object)collision.collider != (Object)null && (Object)(object)((Component)collision.collider).GetComponentInParent() != (Object)null)) { return; } Vector3 val; if (collision.contactCount <= 0) { val = ((Component)this).transform.position; } else { ContactPoint contact = collision.GetContact(0); val = ((ContactPoint)(ref contact)).point; } Vector3 position = val; if (_authoritative) { GrenadeLauncherPatches.PublishDetonation(_weaponNetworkObjectId, _shotId, position); return; } _awaitingServerImpact = true; ((Component)this).transform.position = position; if ((Object)(object)_rigidbody != (Object)null) { _rigidbody.velocity = Vector3.zero; _rigidbody.angularVelocity = Vector3.zero; _rigidbody.isKinematic = true; } } private void Detonate(Vector3 position) { //IL_0016: 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) if (!_detonated) { _detonated = true; ((Component)this).transform.position = position; SpawnExplosion(position); Cleanup(); } } private static void SpawnExplosion(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { Landmine.SpawnExplosion(position, true, 1.35f, 4.5f, 60, 75f, (GameObject)null, false); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[GrenadeLauncher] Landmine.SpawnExplosion threw: " + ex)); } } } private void Cleanup() { Active.Remove(this); if ((Object)(object)this != (Object)null && (Object)(object)((Component)this).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void OnDestroy() { Active.Remove(this); } private static void IgnorePlayerCollisions(Collider projectileCollider) { if ((Object)(object)projectileCollider == (Object)null || StartOfRound.Instance?.allPlayerScripts == null) { return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val == (Object)null) { continue; } Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)null) { Physics.IgnoreCollision(projectileCollider, componentsInChildren[j], true); } } } } private static void AttachFallbackVisual(Transform parent) { //IL_0033: 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) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)1); ((Object)obj).name = "Y4NGZ_GrenadeProjectileFallback"; obj.transform.SetParent(parent, false); obj.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); obj.transform.localScale = new Vector3(0.055f, 0.085f, 0.055f); Collider component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer component2 = obj.GetComponent(); Material val = GrenadeLauncherContentAssets.LoadRuntimeWeaponMaterial(); if ((Object)(object)component2 != (Object)null && (Object)(object)val != (Object)null) { component2.sharedMaterial = val; } } } internal sealed class HandGrenadeProjectile : MonoBehaviour { internal const float FuseSeconds = 3f; internal const float ThrowSpeed = 13f; private const float ThrowLift = 1.25f; private const float ClientCleanupSeconds = 6f; private const float KillRange = 1.35f; private const float DamageRange = 4.5f; private const int NonLethalDamage = 60; private const float PhysicsForce = 75f; private static readonly List Active = new List(); private ulong _playerNetworkObjectId; private uint _throwId; private bool _authoritative; private bool _detonated; private float _spawnTime; internal static GameObject Spawn(Vector3 position, Vector3 direction, ulong playerNetworkObjectId, uint throwId, bool authoritative) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_003a: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((((Vector3)(ref direction)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref direction)).normalized : Vector3.forward); GameObject val2 = new GameObject("Y4NGZ_HandGrenade_" + throwId); val2.transform.position = position; val2.transform.rotation = Quaternion.LookRotation(val, Vector3.up); SphereCollider val3 = val2.AddComponent(); val3.radius = 0.075f; ((Collider)val3).isTrigger = false; ((Collider)val3).material = BuildPhysicsMaterial(); Rigidbody obj = val2.AddComponent(); obj.useGravity = true; obj.mass = 0.55f; obj.drag = 0.05f; obj.angularDrag = 0.08f; obj.collisionDetectionMode = (CollisionDetectionMode)2; obj.interpolation = (RigidbodyInterpolation)1; if ((Object)(object)GrenadeContentAssets.CreateVisual(val2.transform) == (Object)null) { AttachFallbackVisual(val2.transform); } HandGrenadeProjectile handGrenadeProjectile = val2.AddComponent(); handGrenadeProjectile._playerNetworkObjectId = playerNetworkObjectId; handGrenadeProjectile._throwId = throwId; handGrenadeProjectile._authoritative = authoritative; handGrenadeProjectile._spawnTime = Time.time; IgnorePlayerCollisions((Collider)(object)val3); obj.velocity = val * 13f + Vector3.up * 1.25f; obj.angularVelocity = new Vector3(8f, 11f, 6f); Active.Add(handGrenadeProjectile); return val2; } internal static void DetonateSynced(ulong playerNetworkObjectId, uint throwId, Vector3 position) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < Active.Count; i++) { HandGrenadeProjectile handGrenadeProjectile = Active[i]; if (!((Object)(object)handGrenadeProjectile == (Object)null) && !handGrenadeProjectile._detonated && handGrenadeProjectile._playerNetworkObjectId == playerNetworkObjectId && handGrenadeProjectile._throwId == throwId) { handGrenadeProjectile.Detonate(position); return; } } SpawnExplosion(position); } internal static void DestroyAllActive() { HandGrenadeProjectile[] array = Active.ToArray(); Active.Clear(); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null) { Object.Destroy((Object)(object)((Component)array[i]).gameObject); } } } private void Update() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!_detonated) { float num = Time.time - _spawnTime; if (_authoritative && num >= 3f) { GrenadeThrowPatches.PublishDetonation(_playerNetworkObjectId, _throwId, ((Component)this).transform.position); } else if (!_authoritative && num >= 6f) { Cleanup(); } } } private void Detonate(Vector3 position) { //IL_0016: 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) if (!_detonated) { _detonated = true; ((Component)this).transform.position = position; SpawnExplosion(position); Cleanup(); } } private static void SpawnExplosion(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { Landmine.SpawnExplosion(position, true, 1.35f, 4.5f, 60, 75f, (GameObject)null, false); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Grenade] Landmine.SpawnExplosion threw: " + ex)); } } } private void Cleanup() { Active.Remove(this); if ((Object)(object)this != (Object)null && (Object)(object)((Component)this).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void OnDestroy() { Active.Remove(this); } private static void AttachFallbackVisual(Transform parent) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)obj).name = "Y4NGZ_HandGrenadeFallback"; obj.transform.SetParent(parent, false); obj.transform.localScale = Vector3.one * 0.15f; Collider component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } private static PhysicMaterial BuildPhysicsMaterial() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_002b: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown return new PhysicMaterial("Y4NGZ_HandGrenadePhysics") { dynamicFriction = 0.55f, staticFriction = 0.6f, bounciness = 0.3f, frictionCombine = (PhysicMaterialCombine)0, bounceCombine = (PhysicMaterialCombine)3, hideFlags = (HideFlags)61 }; } private static void IgnorePlayerCollisions(Collider projectileCollider) { PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if ((Object)(object)projectileCollider == (Object)null || array == null) { return; } foreach (PlayerControllerB val in array) { if ((Object)(object)val == (Object)null) { continue; } Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (Collider val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { Physics.IgnoreCollision(projectileCollider, val2, true); } } } } } internal enum ImpactMaterial { Neutral, Flesh, Insect, Metal, Ethereal, Inert } internal static class ImpactMaterialCatalog { private static readonly Dictionary Table = new Dictionary(StringComparer.Ordinal) { { "BundyAIChainsaw", ImpactMaterial.Flesh }, { "BundyAIBase", ImpactMaterial.Flesh }, { "BlacksiteSoldierAI", ImpactMaterial.Flesh }, { "CongregantAI", ImpactMaterial.Flesh }, { "WhistleblowerEnemyAI", ImpactMaterial.Flesh }, { "CookMonsterAI", ImpactMaterial.Flesh }, { "StriderAI", ImpactMaterial.Flesh }, { "ShyGuyAI", ImpactMaterial.Flesh }, { "CrawlerAI", ImpactMaterial.Flesh }, { "BaboonBirdAI", ImpactMaterial.Flesh }, { "BushWolfEnemy", ImpactMaterial.Flesh }, { "CaveDwellerAI", ImpactMaterial.Flesh }, { "GiantKiwiAI", ImpactMaterial.Flesh }, { "PumaAI", ImpactMaterial.Flesh }, { "SpiderMonsterAI", ImpactMaterial.Insect }, { "Arthrapod", ImpactMaterial.Insect }, { "SandSpiderAI", ImpactMaterial.Insect }, { "CentipedeAI", ImpactMaterial.Insect }, { "HoarderBugAI", ImpactMaterial.Insect }, { "ButlerBeesEnemyAI", ImpactMaterial.Insect }, { "RedLocustBees", ImpactMaterial.Insect }, { "DocileLocustBeesAI", ImpactMaterial.Insect }, { "FlowerSnakeEnemy", ImpactMaterial.Insect }, { "ForestGiantAI", ImpactMaterial.Insect }, { "PufferAI", ImpactMaterial.Insect }, { "FlowermanAI", ImpactMaterial.Insect }, { "MouthDogAI", ImpactMaterial.Insect }, { "MaskedPlayerEnemy", ImpactMaterial.Insect }, { "EyeMonsterAI", ImpactMaterial.Insect }, { "HarmonicAI", ImpactMaterial.Insect }, { "ButlerEnemyAI", ImpactMaterial.Insect }, { "BlobAI", ImpactMaterial.Insect }, { "DoublewingAI", ImpactMaterial.Insect }, { "SandWormAI", ImpactMaterial.Insect }, { "StingrayAI", ImpactMaterial.Insect }, { "CadaverBloomAI", ImpactMaterial.Insect }, { "CadaverGrowthAI", ImpactMaterial.Insect }, { "CoilCrabAI", ImpactMaterial.Insect }, { "VerminAI", ImpactMaterial.Insect }, { "HoneyFeederAI", ImpactMaterial.Insect }, { "MicBirdAI", ImpactMaterial.Insect }, { "MurkydereAI", ImpactMaterial.Insect }, { "OgopogoAI", ImpactMaterial.Insect }, { "LeafyBoiAI", ImpactMaterial.Insect }, { "ScissorsCreatureAI", ImpactMaterial.Metal }, { "Snipjack", ImpactMaterial.Metal }, { "CreepyDollAI", ImpactMaterial.Metal }, { "Hushdoll", ImpactMaterial.Metal }, { "SimonSaysAI", ImpactMaterial.Metal }, { "FlyingTVAi", ImpactMaterial.Metal }, { "Warden", ImpactMaterial.Metal }, { "RadMechAI", ImpactMaterial.Metal }, { "SpringManAI", ImpactMaterial.Metal }, { "NutcrackerEnemyAI", ImpactMaterial.Metal }, { "JesterAI", ImpactMaterial.Metal }, { "LockerAI", ImpactMaterial.Metal }, { "PoltergeistAI", ImpactMaterial.Ethereal }, { "Passenger", ImpactMaterial.Ethereal }, { "SeraphimEnemyAI", ImpactMaterial.Ethereal }, { "DressGirlAI", ImpactMaterial.Ethereal }, { "ClaySurgeonAI", ImpactMaterial.Inert }, { "DreadweaverAI", ImpactMaterial.Inert }, { "RockAI", ImpactMaterial.Inert }, { "FungiAI", ImpactMaterial.Inert } }; internal static readonly Color DefaultInsectTint = new Color(0.32f, 0.44f, 0.06f, 1f); internal static Color FleshTint = Color.clear; internal static Color InsectTint = DefaultInsectTint; internal static ImpactMaterial Resolve(EnemyAI enemy) { if ((Object)(object)enemy == (Object)null) { return ImpactMaterial.Neutral; } string text = (((Object)(object)enemy.enemyType != (Object)null) ? enemy.enemyType.enemyName : null); if (!string.IsNullOrEmpty(text) && Table.TryGetValue(text, out var value)) { LogClassification(text, enemy, value, "enemyName"); return value; } string name = ((object)enemy).GetType().Name; if (Table.TryGetValue(name, out var value2)) { LogClassification(text, enemy, value2, "typeName"); return value2; } LogClassification(text, enemy, ImpactMaterial.Neutral, "default"); return ImpactMaterial.Neutral; } internal static ImpactMaterial ResolveFromCollider(Collider collider) { EnemyAI val = EnemyFor(collider); if ((Object)(object)val != (Object)null) { return Resolve(val); } if (!IsMetalHazard(collider)) { return ImpactMaterial.Neutral; } return ImpactMaterial.Metal; } internal static EnemyAI EnemyFor(Collider collider) { if ((Object)(object)collider == (Object)null) { return null; } EnemyAICollisionDetect componentInParent = ((Component)collider).GetComponentInParent(); if (!((Object)(object)componentInParent != (Object)null)) { return null; } return componentInParent.mainScript; } internal static bool IsMetalHazard(Collider collider) { if ((Object)(object)collider == (Object)null) { return false; } if (!((Object)(object)((Component)collider).GetComponentInParent() != (Object)null)) { return (Object)(object)((Component)collider).GetComponentInParent() != (Object)null; } return true; } internal static bool Bleeds(ImpactMaterial material) { if (material != ImpactMaterial.Flesh) { return material == ImpactMaterial.Insect; } return true; } internal static Color BloodTint(ImpactMaterial material) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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 (Color)(material switch { ImpactMaterial.Flesh => FleshTint, ImpactMaterial.Insect => InsectTint, _ => Color.clear, }); } private static void LogClassification(string enemyName, EnemyAI enemy, ImpactMaterial material, string matchedOn) { string name = ((object)enemy).GetType().Name; if (WeaponVfxDiagnostics.Once("impact.creature." + name)) { WeaponVfxDiagnostics.Emit("Creature impact material (#119). enemyName='" + (enemyName ?? "") + "' " + $"type='{name}' material={material} matchedOn={matchedOn}."); } } } internal interface IY4NGZFpWeapon { string FpConfigId { get; } GrabbableObject FpGrabbable { get; } ShotgunItem FpLegacyShotgun { get; } } internal static class NativeWeaponRegistry { private const string LogPrefix = "[Y4NGZNative]"; private const int PropsLayer = 6; private const int ScanNodeFallbackLayer = 22; private const float RootGroundOffset = 0.06f; private static readonly Dictionary Prefabs = new Dictionary(); private static readonly Dictionary Items = new Dictionary(); private static readonly List PrefabHolders = new List(); private static bool _registered; private static Material _placeholderMaterial; internal static int RegisteredCount => Prefabs.Count; internal static GameObject PrefabFor(string configId) { if (!Prefabs.TryGetValue(configId ?? string.Empty, out var value)) { return null; } return value; } internal static Item ItemFor(string configId) { if (!Items.TryGetValue(configId ?? string.Empty, out var value)) { return null; } return value; } internal static bool TryRegisterAll() { if (_registered) { return true; } try { foreach (WeaponConfig item in WeaponCatalog.AllNative()) { BuildAndRegister(item); } _registered = true; if (Prefabs.Count > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)string.Format("{0} Registered {1} native weapons.", "[Y4NGZNative]", Prefabs.Count)); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Y4NGZNative] Registered 0 native weapons: the native weapon catalog yielded no entries. No Y4NGZ weapon will appear in game."); } } return true; } catch (Exception arg) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)string.Format("{0} Native weapon registration failed (other gameplay continues): {1}", "[Y4NGZNative]", arg)); } return false; } } private static void BuildAndRegister(WeaponConfig config) { if (config == null || (Object)(object)PrefabFor(config.Id) != (Object)null) { return; } if (!ArmoryContentConfig.IsWeaponEnabled(config.Id)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZNative] " + config.DisplayName + " is disabled in config; not registering it.")); } return; } GameObject holder; GameObject val = BuildPrefab(config, out holder); Item val2 = BuildItemProperties(config, val); Y4NGZWeaponBase component = val.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("Generated native weapon prefab '" + config.Id + "' has no Y4NGZWeaponBase."); } ((GrabbableObject)component).itemProperties = val2; val2.spawnPrefab = val; DawnLibCompat.FixMixerGroups(val); DawnLibCompat.RegisterNetworkPrefab(val); string weaponId = config.Id; DawnLibCompat.RegisterItem(weaponId, val2, () => ArmoryContentConfig.IsWeaponPurchasable(weaponId), () => ArmoryContentConfig.WeaponShopPrice(weaponId, config.CreditsWorth), config.ShopDescription, () => ArmoryContentConfig.WeaponInteriorWeight(weaponId)); Prefabs[config.Id] = val; Items[config.Id] = val2; if ((Object)(object)holder != (Object)null) { PrefabHolders.Add(holder); } NetworkObject component2 = val.GetComponent(); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Y4NGZNative] Registered native " + config.DisplayName + " " + $"(hash={component2?.GlobalObjectIdHash ?? 0}, magazine={config.MagazineSize}, " + $"rpm={config.RoundsPerMinute}, ammo={config.AmmoType}).")); } } private static GameObject BuildPrefab(WeaponConfig config, out GameObject holder) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) holder = new GameObject("Y4NGZ_" + config.Id + "_InactiveHolder"); ((Object)holder).hideFlags = (HideFlags)61; holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)holder); GameObject val = new GameObject("Y4NGZ_" + config.Id + "_Prefab"); val.transform.SetParent(holder.transform, false); ((Object)val).hideFlags = (HideFlags)0; val.layer = 6; SetTagSafe(val, "PhysicsProp"); NetworkObject obj = val.AddComponent(); obj.SynchronizeTransform = true; obj.SceneMigrationSynchronization = true; obj.SpawnWithObservers = true; obj.DontDestroyWithOwner = true; obj.AutoObjectParentSync = true; AssignStableNetworkHash(obj, config); Rigidbody val2 = val.AddComponent(); val2.isKinematic = true; val2.useGravity = false; val2.mass = 1f; val2.drag = 0.15f; val2.angularDrag = 4f; AudioSource obj2 = val.AddComponent(); obj2.playOnAwake = false; obj2.spatialBlend = 1f; obj2.dopplerLevel = 0f; obj2.maxDistance = 60f; obj2.rolloffMode = (AudioRolloffMode)1; Y4NGZWeaponBase y4NGZWeaponBase = val.AddComponent(); y4NGZWeaponBase.ConfigId = config.Id; y4NGZWeaponBase.Magazine = config.MagazineSize; y4NGZWeaponBase.SafetyOn = config.StartsWithSafetyOn; ApplyWeaponVfxConfig(y4NGZWeaponBase, config); ((GrabbableObject)y4NGZWeaponBase).grabbable = true; ((GrabbableObject)y4NGZWeaponBase).grabbableToEnemies = true; ((GrabbableObject)y4NGZWeaponBase).deactivated = false; ((GrabbableObject)y4NGZWeaponBase).isHeld = false; ((GrabbableObject)y4NGZWeaponBase).isPocketed = false; ((GrabbableObject)y4NGZWeaponBase).isInFactory = false; ((GrabbableObject)y4NGZWeaponBase).scrapValue = 0; ((GrabbableObject)y4NGZWeaponBase).rotateObject = false; ((GrabbableObject)y4NGZWeaponBase).propBody = val2; ((GrabbableObject)y4NGZWeaponBase).originalScale = Vector3.one; ((GrabbableObject)y4NGZWeaponBase).useCooldown = 0f; ((GrabbableObject)y4NGZWeaponBase).customGrabTooltip = "Pick up " + config.DisplayName; WeaponLandmarks weaponLandmarks = WeaponLandmarkCatalog.ById(config.Id); MeshRenderer mainObjectRenderer = BuildVisual(val, config, weaponLandmarks); Bounds val3 = ResolveMountedBounds(val, weaponLandmarks); BoxCollider val4 = val.AddComponent(); ((Collider)val4).isTrigger = false; val4.size = (Vector3)((weaponLandmarks != null) ? (((Bounds)(ref val3)).size + Vector3.one * 0.02f) : new Vector3(0.06f, 0.15f, 0.24f)); val4.center = (Vector3)((weaponLandmarks != null) ? ((Bounds)(ref val3)).center : new Vector3(0f, 0.02f, 0f)); ((Component)val4).gameObject.layer = 6; SetTagSafe(((Component)val4).gameObject, "PhysicsProp"); ((GrabbableObject)y4NGZWeaponBase).propColliders = (Collider[])(object)new Collider[1] { (Collider)val4 }; ((GrabbableObject)y4NGZWeaponBase).mainObjectRenderer = mainObjectRenderer; BuildScanNode(val, val4, config); return val; } internal static void RetuneInstance(GameObject instance, WeaponConfig config) { //IL_0056: 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_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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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) //IL_00c2: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)instance == (Object)null || config == null) { return; } ApplyWeaponVfxConfig(instance.GetComponent(), config); WeaponLandmarks weaponLandmarks = WeaponLandmarkCatalog.ById(config.Id); if (weaponLandmarks == null || string.IsNullOrEmpty(weaponLandmarks.VisualRootName)) { return; } Transform val = instance.transform.Find(weaponLandmarks.VisualRootName); if ((Object)(object)val == (Object)null) { return; } try { val.localPosition = ResolveVisualPosition(config, weaponLandmarks.VisualLocalPosition); val.localEulerAngles = ResolveVisualEuler(config, weaponLandmarks.VisualLocalEuler); val.localScale = Vector3.one * ResolveVisualScale(config, weaponLandmarks.VisualLocalScale); Bounds val2 = ResolveMountedBounds(instance, weaponLandmarks); BoxCollider component = instance.GetComponent(); if ((Object)(object)component != (Object)null) { component.size = ((Bounds)(ref val2)).size + Vector3.one * 0.02f; component.center = ((Bounds)(ref val2)).center; } if (WeaponVfxDiagnostics.Once("retune." + config.Id)) { string[] obj = new string[11] { "[Y4NGZNative] ", config.DisplayName, " mount retuned on spawn: pos=", null, null, null, null, null, null, null, null }; Vector3 val3 = val.localPosition; obj[3] = ((Vector3)(ref val3)).ToString("F3"); obj[4] = " euler="; val3 = val.localEulerAngles; obj[5] = ((Vector3)(ref val3)).ToString("F1"); obj[6] = " "; obj[7] = $"scale={val.localScale.x:F3} "; obj[8] = "grabBox="; object obj2; if (!((Object)(object)component != (Object)null)) { obj2 = ""; } else { val3 = component.size; obj2 = ((Vector3)(ref val3)).ToString("F3"); } obj[9] = (string)obj2; obj[10] = "."; WeaponVfxDiagnostics.Emit(string.Concat(obj)); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Mount retune failed for '" + config.Id + "' (the spawn-time mount stands): " + ex.Message)); } } } private static void ApplyWeaponVfxConfig(Y4NGZWeaponBase weapon, WeaponConfig config) { if (!((Object)(object)weapon == (Object)null) && config != null) { weapon.MuzzleFlashPrefabName = (string.IsNullOrWhiteSpace(config.MuzzleFlashPrefabName) ? "Y4NGZ_MuzzleFlash_01" : config.MuzzleFlashPrefabName); weapon.MuzzleFlashScale = Mathf.Max(0.01f, config.MuzzleFlashScale); } } private static MeshRenderer BuildVisual(GameObject root, WeaponConfig config, WeaponLandmarks landmarks) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject((landmarks != null && !string.IsNullOrEmpty(landmarks.VisualRootName)) ? landmarks.VisualRootName : ("Y4NGZ_" + config.Id + "Visual")); val.transform.SetParent(root.transform, false); val.layer = root.layer; if (landmarks != null) { val.transform.localPosition = ResolveVisualPosition(config, landmarks.VisualLocalPosition); val.transform.localEulerAngles = ResolveVisualEuler(config, landmarks.VisualLocalEuler); val.transform.localScale = Vector3.one * ResolveVisualScale(config, landmarks.VisualLocalScale); } if (TryMountModel(val, config)) { return null; } GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); obj.SetActive(false); ((Object)obj).name = ((landmarks != null && !string.IsNullOrEmpty(landmarks.PropMeshNode)) ? landmarks.PropMeshNode : ("Y4NGZ_" + config.Id + "_PlaceholderMesh")); obj.transform.SetParent(val.transform, false); Collider component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } obj.layer = root.layer; obj.transform.localScale = (Vector3)((landmarks != null) ? ((Bounds)(ref landmarks.ModelBounds)).size : new Vector3(0.036f, 0.138f, 0.227f)); obj.transform.localPosition = ((landmarks != null) ? ((Bounds)(ref landmarks.ModelBounds)).center : Vector3.zero); obj.SetActive(true); MeshRenderer component2 = obj.GetComponent(); Material val2 = _placeholderMaterial ?? (_placeholderMaterial = BuildPlaceholderMaterial()); if ((Object)(object)component2 != (Object)null && (Object)(object)val2 != (Object)null) { ((Renderer)component2).sharedMaterial = val2; } return component2; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Visual build failed for '" + config.Id + "' (the weapon still spawns and fires): " + ex.Message)); } return null; } } private static bool TryMountModel(GameObject visualRoot, WeaponConfig config) { //IL_0071: 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_0091: Unknown result type (might be due to invalid IL or missing references) WeaponModelAssetSet weaponModelAssetSet = ((config != null) ? WeaponModelRuntimeAssets.ById(config.Id) : null); if (weaponModelAssetSet == null || string.IsNullOrEmpty(weaponModelAssetSet.ModelAssetName)) { if (config != null) { return (Object)(object)WeaponVisuals.TryMountNativeModel(config.Id, visualRoot) != (Object)null; } return false; } try { GameObject val = WeaponModelRuntimeAssets.LoadPrefab(weaponModelAssetSet); if ((Object)(object)val == (Object)null) { return false; } GameObject obj = Object.Instantiate(val, visualRoot.transform, false); ((Object)obj).name = ((Object)val).name; obj.transform.localPosition = Vector3.zero; obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = Vector3.one; SetLayerRecursively(obj, visualRoot.layer); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZNative] Mounted the '" + config.Id + "' model from " + (WeaponModelRuntimeAssets.SourceFor(weaponModelAssetSet.ModelAssetName) ?? "unknown") + ".")); } return true; } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZNative] Model mount failed for '" + config.Id + "' (falling back to the placeholder box): " + ex.Message)); } return false; } } private static void SetLayerRecursively(GameObject root, int layer) { if (!((Object)(object)root == (Object)null)) { root.layer = layer; for (int i = 0; i < root.transform.childCount; i++) { SetLayerRecursively(((Component)root.transform.GetChild(i)).gameObject, layer); } } } private static Bounds ResolveMountedBounds(GameObject root, WeaponLandmarks landmarks) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00ca: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) if (landmarks == null) { return new Bounds(Vector3.zero, Vector3.one); } Transform val = ((!string.IsNullOrEmpty(landmarks.VisualRootName)) ? root.transform.Find(landmarks.VisualRootName) : null); if ((Object)(object)val == (Object)null) { return landmarks.ModelBounds; } Vector3 center = ((Bounds)(ref landmarks.ModelBounds)).center; Vector3 extents = ((Bounds)(ref landmarks.ModelBounds)).extents; bool flag = false; Bounds result = default(Bounds); Vector3 val2 = default(Vector3); for (int i = 0; i < 8; i++) { ((Vector3)(ref val2))..ctor(((i & 1) == 0) ? (center.x - extents.x) : (center.x + extents.x), ((i & 2) == 0) ? (center.y - extents.y) : (center.y + extents.y), ((i & 4) == 0) ? (center.z - extents.z) : (center.z + extents.z)); Vector3 val3 = root.transform.InverseTransformPoint(val.TransformPoint(val2)); if (!flag) { ((Bounds)(ref result))..ctor(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref result)).Encapsulate(val3); } } return result; } private static Vector3 ResolveVisualPosition(WeaponConfig config, Vector3 authored) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (config == null || !Plugin.TryGetNativeWeaponVisualConfig(config.Id, out var pos, out var _, out var _) || pos == null) { return authored; } Vector3 val = Plugin.ParseVectorOrDefault(pos.Value, config.NativeVisualConfigIsDelta ? Vector3.zero : authored); if (!config.NativeVisualConfigIsDelta) { return val; } return authored + val; } private static Vector3 ResolveVisualEuler(WeaponConfig config, Vector3 authored) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (config == null || !Plugin.TryGetNativeWeaponVisualConfig(config.Id, out var _, out var rot, out var _) || rot == null) { return authored; } Vector3 val = Plugin.ParseVectorOrDefault(rot.Value, config.NativeVisualConfigIsDelta ? Vector3.zero : authored); if (!config.NativeVisualConfigIsDelta) { return val; } Quaternion val2 = Quaternion.Euler(authored) * Quaternion.Euler(val); return ((Quaternion)(ref val2)).eulerAngles; } private static float ResolveVisualScale(WeaponConfig config, float authored) { if (config == null || !Plugin.TryGetNativeWeaponVisualConfig(config.Id, out var _, out var _, out var scale) || scale == null || scale.Value <= 0f) { return authored; } if (!config.NativeVisualConfigIsDelta) { return scale.Value; } return authored * scale.Value; } private static Material BuildPlaceholderMaterial() { //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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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) try { Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("HDRP/Unlit"); if ((Object)(object)val == (Object)null) { return null; } Material val2 = new Material(val) { name = "Y4NGZ_NativeWeapon_Placeholder", hideFlags = (HideFlags)61 }; Color val3 = default(Color); ((Color)(ref val3))..ctor(0.16f, 0.16f, 0.18f); if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", val3); } if (val2.HasProperty("_UnlitColor")) { val2.SetColor("_UnlitColor", val3); } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", val3); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", 0.8f); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", 0.45f); } return val2; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Placeholder material build failed: " + ex.Message)); } return null; } } private static void BuildScanNode(GameObject root, BoxCollider propCollider, WeaponConfig config) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //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_005c: 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) try { GameObject val = new GameObject("ScanNode"); val.transform.SetParent(root.transform, false); val.layer = ResolveLayer("ScanNode", 22); val.transform.localPosition = propCollider.center; BoxCollider obj = val.AddComponent(); ((Collider)obj).isTrigger = true; obj.size = propCollider.size + Vector3.one * 0.1f; ScanNodeProperties obj2 = val.AddComponent(); obj2.headerText = config.DisplayName; obj2.subText = DescribeWeapon(config); obj2.maxRange = 24; obj2.minRange = 1; obj2.requiresLineOfSight = false; obj2.nodeType = 0; obj2.creatureScanID = -1; obj2.scrapValue = 0; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Scan node setup failed for '" + config.DisplayName + "': " + ex.Message)); } } } private static string DescribeWeapon(WeaponConfig config) { return string.Format("{0}-round {1}", config.MagazineSize, config.TwoHanded ? "two-handed" : "sidearm"); } private static Item BuildItemProperties(WeaponConfig config, GameObject prefab) { //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) Item val = ScriptableObject.CreateInstance(); ((Object)val).name = "Y4NGZ_" + config.Id + "_Item"; val.itemName = config.DisplayName; val.spawnPositionTypes = new List(); val.twoHanded = config.TwoHanded; val.twoHandedAnimation = config.TwoHandedAnimation; val.weight = config.Weight; val.canBeGrabbedBeforeGameStart = config.CanBeGrabbedBeforeGameStart; val.disallowUtilitySlot = false; val.itemSpawnsOnGround = true; val.isConductiveMetal = config.ConductiveMetal; val.isScrap = config.IsScrap; val.creditsWorth = config.CreditsWorth; val.minValue = config.CreditsWorth; val.maxValue = config.CreditsWorth; val.spawnPrefab = prefab; val.requiresBattery = false; val.itemIcon = WeaponAssetLoader.LoadIconSprite(config.Id); val.grabAnim = config.GrabAnimation; val.grabAnimationTime = config.GrabAnimationTime; val.isDefensiveWeapon = config.DefensiveWeapon; val.syncGrabFunction = true; val.syncUseFunction = false; val.syncDiscardFunction = true; val.syncInteractLRFunction = true; val.saveItemVariable = true; val.holdButtonUse = config.FireMode == WeaponFireMode.FullAutoHitscan; val.itemIsTrigger = false; val.toolTips = new string[3] { "Fire : [LMB]", WeaponReloadInput.Tooltip("Reload"), "Turn safety off : [Q]" }; val.verticalOffset = config.VerticalOffset; val.floorYOffset = config.FloorYOffset; val.allowDroppingAheadOfPlayer = true; val.restingRotation = config.RestingRotation; val.rotationOffset = config.HeldRotationOffset; val.positionOffset = config.HeldPositionOffset; val.meshOffset = config.MeshOffset; val.canBeInspected = false; ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); return val; } private static void SetTagSafe(GameObject target, string tag) { try { target.tag = tag; } catch (Exception) { } } private static int ResolveLayer(string layerName, int fallback) { int num = LayerMask.NameToLayer(layerName); if (num < 0) { return fallback; } return num; } private static void AssignStableNetworkHash(NetworkObject networkObject, WeaponConfig config) { if ((Object)(object)networkObject == (Object)null || config == null) { return; } try { uint num; using (MD5 mD = MD5.Create()) { string text = (config.PreserveLegacyNetworkHash ? ".Weapon." : ".NativeWeapon."); num = BitConverter.ToUInt32(mD.ComputeHash(Encoding.UTF8.GetBytes("com.y4ngz.betterarmory" + text + config.Id)), 0); } (typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic))?.SetValue(networkObject, num); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Failed to assign network hash for '" + config.Id + "': " + ex.Message)); } } } internal static void TryApplyWeaponAudio() { try { ShotgunItem val = FindVanillaShotgunPrefab(); AudioClip fireClip = ((val?.gunShootSFX != null && val.gunShootSFX.Length != 0) ? val.gunShootSFX[0] : null); foreach (KeyValuePair prefab in Prefabs) { GameObject value = prefab.Value; Y4NGZWeaponBase y4NGZWeaponBase = (((Object)(object)value != (Object)null) ? value.GetComponent() : null); if ((Object)(object)y4NGZWeaponBase == (Object)null) { continue; } WeaponModelAssetSet weaponModelAssetSet = WeaponModelRuntimeAssets.ById(prefab.Key); WeaponConfig weaponConfig = WeaponCatalog.ById(prefab.Key); if (weaponConfig != null && weaponConfig.ReuseVanillaShotgunItemAssets && (Object)(object)((GrabbableObject)(val?)).itemProperties != (Object)null && Items.TryGetValue(prefab.Key, out var value2) && (Object)(object)value2 != (Object)null) { if ((Object)(object)value2.itemIcon == (Object)null) { value2.itemIcon = ((GrabbableObject)val).itemProperties.itemIcon; } value2.grabSFX = ((GrabbableObject)val).itemProperties.grabSFX; value2.dropSFX = ((GrabbableObject)val).itemProperties.dropSFX; value2.pocketSFX = ((GrabbableObject)val).itemProperties.pocketSFX; value2.throwSFX = ((GrabbableObject)val).itemProperties.throwSFX; value2.clinkAudios = ((GrabbableObject)val).itemProperties.clinkAudios; } AudioClip[] array = LoadAuthoredFireClips(weaponModelAssetSet); AudioClip[] array2 = LoadAuthoredClipSlots(weaponModelAssetSet, weaponModelAssetSet?.FireMechanicalClipNames); AudioClip val2 = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, weaponModelAssetSet?.ReloadTacClipName); AudioClip val3 = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, weaponModelAssetSet?.ReloadEmptyClipName); AudioClip val4 = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, weaponModelAssetSet?.ReloadStageStartClipName); AudioClip val5 = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, weaponModelAssetSet?.ReloadStageLoopClipName); AudioClip val6 = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, weaponModelAssetSet?.ReloadStageEndClipName); y4NGZWeaponBase.FireClips = array; y4NGZWeaponBase.FireMechanicalClips = array2; y4NGZWeaponBase.FireMechanicalClipDelaySeconds = ((array2 == null) ? null : weaponModelAssetSet?.FireMechanicalClipDelaySeconds); y4NGZWeaponBase.ReloadTacClip = val2; y4NGZWeaponBase.ReloadEmptyClip = val3; y4NGZWeaponBase.ReloadStageStartClip = val4; y4NGZWeaponBase.ReloadStageLoopClip = val5; y4NGZWeaponBase.ReloadStageEndClip = val6; y4NGZWeaponBase.FireClip = fireClip; y4NGZWeaponBase.DryFireClip = val?.noAmmoSFX; y4NGZWeaponBase.ReloadStartClip = val?.gunReloadSFX; y4NGZWeaponBase.ReloadFinishClip = val?.gunReloadFinishSFX; y4NGZWeaponBase.SafetyOnClip = val?.switchSafetyOnSFX; y4NGZWeaponBase.SafetyOffClip = val?.switchSafetyOffSFX; int num = CountResolvedClips(array2); int num2 = ((array != null) ? array.Length : 0) + num + (((Object)(object)val2 != (Object)null) ? 1 : 0) + (((Object)(object)val3 != (Object)null) ? 1 : 0) + (((Object)(object)val4 != (Object)null) ? 1 : 0) + (((Object)(object)val5 != (Object)null) ? 1 : 0) + (((Object)(object)val6 != (Object)null) ? 1 : 0); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)(string.Format("{0} '{1}' audio: authored={2} ", "[Y4NGZNative]", prefab.Key, num2) + $"(fire x{((array != null) ? array.Length : 0)}, fireMechanical={num}, " + $"reloadTac={(Object)(object)val2 != (Object)null}, " + $"reloadEmpty={(Object)(object)val3 != (Object)null}, stagedReload=" + $"{(Object)(object)val4 != (Object)null}/{(Object)(object)val5 != (Object)null}/{(Object)(object)val6 != (Object)null}); " + "vanilla shotgun fills the rest (dry fire, safety" + ((array == null) ? ", fire" : string.Empty) + ").")); } } WeaponSoundRegistry.TryApplyAll(); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZNative] Audio assignment failed (weapons still fire silently): " + ex.Message)); } } } private static AudioClip[] LoadAuthoredFireClips(WeaponModelAssetSet assets) { if (assets?.FireClipNames == null || assets.FireClipNames.Length == 0) { return null; } List list = new List(); string[] fireClipNames = assets.FireClipNames; foreach (string assetName in fireClipNames) { AudioClip val = WeaponModelRuntimeAssets.LoadClip(assets, assetName); if ((Object)(object)val != (Object)null) { list.Add(val); } } if (list.Count <= 0) { return null; } return list.ToArray(); } private static AudioClip[] LoadAuthoredClipSlots(WeaponModelAssetSet assets, string[] clipNames) { if (assets == null || clipNames == null || clipNames.Length == 0) { return null; } AudioClip[] array = (AudioClip[])(object)new AudioClip[clipNames.Length]; bool flag = false; for (int i = 0; i < clipNames.Length; i++) { array[i] = WeaponModelRuntimeAssets.LoadClip(assets, clipNames[i]); flag |= (Object)(object)array[i] != (Object)null; } if (!flag) { return null; } return array; } private static int CountResolvedClips(AudioClip[] clips) { if (clips == null) { return 0; } int num = 0; for (int i = 0; i < clips.Length; i++) { if ((Object)(object)clips[i] != (Object)null) { num++; } } return num; } private static ShotgunItem FindVanillaShotgunPrefab() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if (instance?.allItemsList?.itemsList != null) { foreach (Item items in instance.allItemsList.itemsList) { ShotgunItem val = (((Object)(object)items != (Object)null && (Object)(object)items.spawnPrefab != (Object)null) ? items.spawnPrefab.GetComponent() : null); if ((Object)(object)val != (Object)null) { return val; } } } ShotgunItem[] array = Resources.FindObjectsOfTypeAll(); foreach (ShotgunItem val2 in array) { if ((Object)(object)val2 != (Object)null) { Scene scene = ((Component)val2).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return val2; } } } return null; } internal static void DebugSpawnAtLocalPlayer(WeaponConfig config) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) if (config == null) { return; } GameObject val = (TryRegisterAll() ? PrefabFor(config.Id) : null); if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Debug spawn skipped: " + config.DisplayName + " is not registered.")); } return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Y4NGZNative] Debug spawn requires being the host."); } return; } PlayerControllerB val2 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); Vector3 val3 = (((Object)(object)val2 != (Object)null) ? (((Component)val2).transform.position + ((Component)val2).transform.forward * 1.4f + Vector3.up * 0.6f) : Vector3.up); GameObject val4 = Object.Instantiate(val, val3, Quaternion.identity); val4.SetActive(true); NetworkObject component = val4.GetComponent(); if ((Object)(object)component == (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)("[Y4NGZNative] Debug spawn failed: '" + config.Id + "' instance has no NetworkObject.")); } Object.Destroy((Object)(object)val4); return; } try { component.Spawn(false); } catch (Exception arg) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)("[Y4NGZNative] NetworkObject.Spawn() threw for '" + config.Id + "' — the prefab is " + $"likely absent from the NetworkManager's registered prefab list (registration timing). {arg}")); } Object.Destroy((Object)(object)val4); return; } int num = ((Plugin.WeaponsDevGrantShells != null) ? Plugin.WeaponsDevGrantShells.Value : 0); if (num > 0 && AmmoReserve.Get(config.AmmoType) <= 0) { AmmoReserve.Set(config.AmmoType, num); ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)string.Format("{0} Dev-granted {1} rounds ({2}) to the reserve.", "[Y4NGZNative]", num, config.AmmoType)); } } LogLandmarkState(val4, config); ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogInfo((object)("[Y4NGZNative] Debug-spawned a " + config.DisplayName + " near the local player " + $"(hash={component.GlobalObjectIdHash}, nid={component.NetworkObjectId}).")); } } internal static void LogLandmarkState(GameObject instance, WeaponConfig config) { //IL_00ae: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) WeaponLandmarks weaponLandmarks = WeaponLandmarkCatalog.ById(config.Id); if (weaponLandmarks == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZNative] " + config.DisplayName + " has no landmark entry.")); } return; } bool flag = WeaponLandmarkResolver.ResolvedHostIsAuthoritative(instance, weaponLandmarks); Vector3 measuredSize; bool flag2 = WeaponLandmarkResolver.MatchesAuthoredGeometry(instance, weaponLandmarks, 0.005f, out measuredSize); Vector3 origin; Vector3 direction; bool flag3 = WeaponLandmarkResolver.TryGetBore(instance, weaponLandmarks, out origin, out direction); bool flag4 = (Object)(object)instance != (Object)null && (Object)(object)instance.GetComponentInChildren(true) != (Object)null; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)(string.Format("{0} {1} landmarks: hostAuthoritative={2} ", "[Y4NGZNative]", config.DisplayName, flag) + $"geometryMatches={flag2} measured={measuredSize} expected={((Bounds)(ref weaponLandmarks.ModelBounds)).size} " + $"bore={flag3} muzzle={origin} dir={direction} " + "visual=" + (flag4 ? "model" : "placeholder box") + ".")); } } } internal sealed class VfxInstanceCache { internal sealed class Entry { public GameObject Instance; public float ExpiresAt; public ParticleSystem[] Systems; public string PoolKey; public Vector3 BaseScale; public object State; } private readonly int _maxLive; private readonly int _maxPooled; private readonly List _live; private readonly Dictionary> _pool; private int _pooledCount; internal int LiveCount => _live.Count; internal VfxInstanceCache(int maxLive, int maxPooled = 0) { _maxLive = maxLive; _maxPooled = maxPooled; _live = new List(maxLive); _pool = ((maxPooled > 0) ? new Dictionary>() : null); } internal Entry LiveEntryAt(int index) { if (index < 0 || index >= _live.Count) { return null; } return _live[index]; } internal void VisitLive(Action visitor) { if (visitor == null) { return; } float time = Time.time; for (int i = 0; i < _live.Count; i++) { Entry entry = _live[i]; if (entry != null && (Object)(object)entry.Instance != (Object)null) { visitor(entry, Mathf.Max(0f, entry.ExpiresAt - time)); } } } internal void EnforceCapacityForNewInstance() { while (_live.Count >= _maxLive) { Release(_live[0]); _live.RemoveAt(0); } } internal void EnforcePerKeyCapacityForNewInstance(string poolKey, int maxLivePerKey) { if (string.IsNullOrEmpty(poolKey) || maxLivePerKey <= 0) { return; } int num = 0; for (int i = 0; i < _live.Count; i++) { if (_live[i].PoolKey == poolKey) { num++; } } int num2 = 0; while (num >= maxLivePerKey && num2 < _live.Count) { if (_live[num2].PoolKey != poolKey) { num2++; continue; } Release(_live[num2]); _live.RemoveAt(num2); num--; } } internal bool TryRent(string poolKey, out Entry entry) { entry = null; if (_pool == null || string.IsNullOrEmpty(poolKey)) { return false; } if (!_pool.TryGetValue(poolKey, out var value)) { return false; } while (value.Count > 0 && entry == null) { Entry entry2 = value.Pop(); _pooledCount--; if (entry2 != null && (Object)(object)entry2.Instance != (Object)null) { entry = entry2; } } return entry != null; } internal void Track(Entry entry, float lifetimeSeconds) { if (entry != null && !((Object)(object)entry.Instance == (Object)null)) { entry.ExpiresAt = Time.time + lifetimeSeconds; _live.Add(entry); } } internal void Refresh(Entry entry, float lifetimeSeconds) { if (entry != null && !((Object)(object)entry.Instance == (Object)null)) { int num = _live.IndexOf(entry); if (num >= 0) { _live.RemoveAt(num); entry.ExpiresAt = Time.time + lifetimeSeconds; _live.Add(entry); } } } internal Entry Track(GameObject instance, ParticleSystem[] systems, float lifetimeSeconds) { if ((Object)(object)instance == (Object)null) { return null; } Entry entry = new Entry { Instance = instance, Systems = systems }; Track(entry, lifetimeSeconds); return entry; } internal void RetireExpired() { float time = Time.time; for (int num = _live.Count - 1; num >= 0; num--) { Entry entry = _live[num]; if ((Object)(object)entry.Instance == (Object)null) { _live.RemoveAt(num); } else if (time >= entry.ExpiresAt || !AnySystemAlive(entry.Systems)) { Release(entry); _live.RemoveAt(num); } } } internal void StopAll() { for (int i = 0; i < _live.Count; i++) { if ((Object)(object)_live[i].Instance != (Object)null) { Object.Destroy((Object)(object)_live[i].Instance); } } _live.Clear(); if (_pool == null) { return; } foreach (KeyValuePair> item in _pool) { Stack value = item.Value; while (value.Count > 0) { Entry entry = value.Pop(); if (entry != null && (Object)(object)entry.Instance != (Object)null) { Object.Destroy((Object)(object)entry.Instance); } } } _pool.Clear(); _pooledCount = 0; } private void Release(Entry entry) { if (entry == null || (Object)(object)entry.Instance == (Object)null) { return; } if (_pool == null || string.IsNullOrEmpty(entry.PoolKey) || _pooledCount >= _maxPooled) { Object.Destroy((Object)(object)entry.Instance); return; } ParticleSystem[] systems = entry.Systems; if (systems != null) { for (int i = 0; i < systems.Length; i++) { if ((Object)(object)systems[i] != (Object)null) { systems[i].Stop(false, (ParticleSystemStopBehavior)0); } } } entry.Instance.transform.SetParent((Transform)null, false); entry.Instance.SetActive(false); entry.ExpiresAt = 0f; if (!_pool.TryGetValue(entry.PoolKey, out var value)) { value = new Stack(); _pool.Add(entry.PoolKey, value); } value.Push(entry); _pooledCount++; } private static bool AnySystemAlive(ParticleSystem[] systems) { if (systems == null) { return true; } for (int i = 0; i < systems.Length; i++) { if ((Object)(object)systems[i] != (Object)null && systems[i].IsAlive(false)) { return true; } } return false; } } internal static class WeaponAccuracy { private const float WalkSpeedReference = 4.6f; private const float MoveBloomFollowSpeed = 9f; private const float AirborneDwellSeconds = 0.08f; private const float StaleStateSeconds = 1f; private static bool _cosmeticListLogged; private static string _trackedConfigId = string.Empty; private static float _shotBloom; private static float _moveBloom; private static float _airborneFor; private static float _resolvedSpread; private static float _lastAdvanceTime = -999f; private static int _lastAdvanceFrame = -1; internal static float AimSteadiness { get; private set; } = 1f; internal static float MoveBloomDegrees => _moveBloom; internal static float ShotBloomDegrees => _shotBloom; internal static float BaseHalfAngleDegrees(WeaponConfig config) { if (config == null) { return 0f; } if (config.FireMode == WeaponFireMode.ContinuousStream) { return Mathf.Atan2(0.9f, 8f) * 57.29578f; } return Mathf.Max(0f, config.SpreadDegrees); } internal static float Sample(PlayerControllerB player, WeaponConfig config) { if (config == null) { return 0f; } float num = BaseHalfAngleDegrees(config); if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)GameNetworkManager.Instance?.localPlayerController) { return num; } Advance(player, config, num); return _resolvedSpread; } internal static void OnShotFired(WeaponConfig config) { if (config != null && !(config.ShotBloomMaxDegrees <= 0f) && !(config.ShotBloomPerShotDegrees <= 0f)) { if (config.Id != _trackedConfigId) { ResetFor(config.Id); } _shotBloom = Mathf.Min(_shotBloom + config.ShotBloomPerShotDegrees, config.ShotBloomMaxDegrees); _lastAdvanceFrame = -1; } } internal static void LogCosmeticSpreadWeapons() { if (_cosmeticListLogged) { return; } _cosmeticListLogged = true; List list = new List(); foreach (WeaponConfig item in WeaponCatalog.All()) { if (item.SpreadIsCosmetic) { list.Add($"{item.DisplayName} ({item.SpreadDegrees:0.##} deg)"); } } foreach (WeaponConfig item2 in WeaponCatalog.AllNative()) { if (item2.SpreadIsCosmetic) { list.Add($"{item2.DisplayName} ({item2.SpreadDegrees:0.##} deg)"); } } if (list.Count == 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[Y4NGZWeapons.accuracy] Every registered weapon consumes its own spread; no reticle is sized from a number nothing reads."); } return; } bool flag = Plugin.CrosshairHonestSizingOnly == null || Plugin.CrosshairHonestSizingOnly.Value; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)($"[Y4NGZWeapons.accuracy] Spread is COSMETIC on {list.Count} weapon(s): " + string.Join(", ", list.ToArray()) + ". These fire through vanilla ShotgunItem.ShootGun, which applies no spread at all. " + $"'Crosshair / Honest Sizing Only' = {flag}, so their reticles draw " + (flag ? "a fixed per-family size instead of their authored cone." : "their authored cone anyway — decorative, by config.") + " Each clears as it migrates to the native base (#117).")); } } private static void ResetFor(string configId) { _trackedConfigId = configId ?? string.Empty; _shotBloom = 0f; _moveBloom = 0f; _airborneFor = 0f; _resolvedSpread = 0f; AimSteadiness = 1f; _lastAdvanceFrame = -1; } private static void Advance(PlayerControllerB player, WeaponConfig config, float baseSpread) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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) float time = Time.time; if (config.Id != _trackedConfigId || time - _lastAdvanceTime > 1f) { ResetFor(config.Id); } if (Time.frameCount != _lastAdvanceFrame) { float num = Mathf.Clamp(time - _lastAdvanceTime, 0f, 0.25f); _lastAdvanceTime = time; _lastAdvanceFrame = Time.frameCount; float num2 = Mathf.Max(0.5f, config.RecoilRecoverySpeed); _shotBloom *= Mathf.Exp((0f - num2) * num); if (_shotBloom < 0.001f) { _shotBloom = 0f; } CharacterController thisController = player.thisController; bool num3 = (Object)(object)thisController != (Object)null && thisController.isGrounded; Vector3 val = (((Object)(object)thisController != (Object)null) ? thisController.velocity : Vector3.zero); val.y = 0f; AimSteadiness = 1f - Mathf.Clamp01(((Vector3)(ref val)).magnitude / 4.6f); bool flag = !num3 && !player.isClimbingLadder && !player.isPlayerSliding && !player.inSpecialInteractAnimation; _airborneFor = (flag ? (_airborneFor + num) : 0f); bool flag2 = player.isFallingFromJump || (flag && _airborneFor >= 0.08f); float num4 = config.MoveBloomMaxDegrees * (1f - AimSteadiness) + (player.isSprinting ? config.SprintBloomDegrees : 0f) + (flag2 ? config.AirborneBloomDegrees : 0f); _moveBloom = Mathf.Lerp(_moveBloom, num4, 1f - Mathf.Exp(-9f * num)); float num5 = 0f; WeaponRecoilDriver activeDriver = WeaponRecoil.ActiveDriver; if ((Object)(object)activeDriver != (Object)null) { num5 = Mathf.Max(0f, config.RecoilBloomScale) * activeDriver.PendingKickDegrees; } float num6 = ((num3 && player.isCrouching) ? Mathf.Clamp(config.CrouchSpreadMultiplier, 0.05f, 1f) : 1f); _resolvedSpread = Mathf.Max(0f, (baseSpread + _shotBloom + _moveBloom + num5) * num6); } } internal static float HalfAngleToViewRadius(float halfAngleDeg, float viewHeightUnits, float verticalFovDeg) { if (halfAngleDeg <= 0f || viewHeightUnits <= 0f) { return 0f; } float num = Mathf.Clamp(verticalFovDeg, 1f, 179f) * 0.5f * (MathF.PI / 180f); return 0.5f * viewHeightUnits * Mathf.Tan(halfAngleDeg * (MathF.PI / 180f)) / Mathf.Tan(num); } } internal static class WeaponAssetLoader { private static readonly Dictionary IconCache = new Dictionary(); internal static string AssetDirectory() { try { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); return string.IsNullOrEmpty(directoryName) ? null : Path.Combine(directoryName, "WeaponAssets"); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Could not resolve WeaponAssets directory: " + ex.Message)); } return null; } } internal static Mesh LoadMesh(string path, string label) { //IL_00b9: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Expected O, but got Unknown try { if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] " + label + " mesh missing: " + (path ?? ""))); } return null; } using BinaryReader binaryReader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)); int num = binaryReader.ReadInt32(); binaryReader.ReadInt32(); if (num != 1213417305) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons] " + label + " mesh has an invalid magic value.")); } return null; } int num2 = ReadCount(binaryReader, label, "vertices"); Vector3[] array = (Vector3[])(object)new Vector3[num2]; for (int i = 0; i < num2; i++) { array[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()); } int num3 = ReadCount(binaryReader, label, "normals"); Vector3[] array2 = (Vector3[])(object)new Vector3[num3]; for (int j = 0; j < num3; j++) { array2[j] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()); } int num4 = ReadCount(binaryReader, label, "UVs"); Vector2[] array3 = (Vector2[])(object)new Vector2[num4]; for (int k = 0; k < num4; k++) { array3[k] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle()); } int num5 = ReadCount(binaryReader, label, "triangle indices"); int[] array4 = new int[num5]; for (int l = 0; l < num5; l++) { array4[l] = binaryReader.ReadInt32(); } Mesh val = new Mesh { name = "Y4NGZ_" + SafeAssetName(label), indexFormat = (IndexFormat)1, hideFlags = (HideFlags)61 }; val.vertices = array; if (num3 == num2) { val.normals = array2; } if (num4 == num2) { val.uv = array3; } val.triangles = array4; if (num3 != num2) { val.RecalculateNormals(); } val.RecalculateBounds(); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[Y4NGZWeapons] {label} mesh loaded: {num2} verts, {num5 / 3} tris."); } return val; } catch (Exception ex) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)("[Y4NGZWeapons] " + label + " mesh failed to load: " + ex.Message)); } return null; } } internal static Material BuildMaterial(string directory, string filePrefix, string label) { //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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown try { Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] No usable shader for " + label + " material.")); } return null; } Material val2 = new Material(val) { name = "Y4NGZ_" + SafeAssetName(label) + "_Mat", hideFlags = (HideFlags)61 }; if (!string.IsNullOrWhiteSpace(directory) && !string.IsNullOrWhiteSpace(filePrefix)) { Texture2D val3 = LoadPng(Path.Combine(directory, filePrefix + "_albedo.png"), linear: false); Texture2D val4 = LoadPng(Path.Combine(directory, filePrefix + "_normal.png"), linear: true); if ((Object)(object)val3 != (Object)null) { if (val2.HasProperty("_BaseColorMap")) { val2.SetTexture("_BaseColorMap", (Texture)(object)val3); } if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)val3); } } if ((Object)(object)val4 != (Object)null) { if (val2.HasProperty("_NormalMap")) { val2.SetTexture("_NormalMap", (Texture)(object)val4); val2.EnableKeyword("_NORMALMAP"); } if (val2.HasProperty("_BumpMap")) { val2.SetTexture("_BumpMap", (Texture)(object)val4); } } } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", 0.35f); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", 0.2f); } return val2; } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons] " + label + " material failed to build: " + ex.Message)); } return null; } } internal static Texture2D LoadPng(string path, bool linear) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown try { if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] texture missing: " + (path ?? ""))); } return null; } byte[] array = File.ReadAllBytes(path); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear) { hideFlags = (HideFlags)61 }; if (!ImageConversion.LoadImage(val, array)) { Object.Destroy((Object)(object)val); return null; } return val; } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons] texture failed to load (" + (path ?? "") + "): " + ex.Message)); } return null; } } internal static Sprite LoadIconSprite(string id) { //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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(id)) { return null; } if (IconCache.TryGetValue(id, out var value)) { return value; } Sprite val = null; try { string text = AssetDirectory(); string text2 = (string.IsNullOrWhiteSpace(text) ? null : Path.Combine(text, "Icons", id + ".png")); if (!string.IsNullOrWhiteSpace(text2) && File.Exists(text2)) { byte[] array = File.ReadAllBytes(text2); Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, true, false) { name = "Y4NGZ_" + SafeAssetName(id) + "_Icon", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1, hideFlags = (HideFlags)61 }; if (ImageConversion.LoadImage(val2, array)) { val = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), 100f); if ((Object)(object)val != (Object)null) { ((Object)val).name = "Y4NGZ_" + SafeAssetName(id) + "_IconSprite"; ((Object)val).hideFlags = (HideFlags)61; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons] Inventory icon loaded for '" + id + "' " + $"({((Texture)val2).width}x{((Texture)val2).height}).")); } } } else { Object.Destroy((Object)(object)val2); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons] Inventory icon failed to decode: " + text2)); } } } } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZWeapons] Inventory icon failed to load for '" + id + "': " + ex.Message)); } val = null; } IconCache[id] = val; return val; } internal static float LongestAxis(Vector3 size) { //IL_0000: 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_0016: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z))); } private static int ReadCount(BinaryReader reader, string label, string part) { int num = reader.ReadInt32(); if (num < 0 || num > 10000000) { throw new InvalidDataException($"{label} mesh has an invalid {part} count ({num})."); } return num; } private static string SafeAssetName(string label) { if (!string.IsNullOrWhiteSpace(label)) { return label.Replace(" ", string.Empty); } return "RuntimeAsset"; } } internal static class WeaponBulletHoleDecals { private sealed class DecalState { private readonly MeshRenderer[] _renderers; private readonly Color[] _baseColors; private readonly MaterialPropertyBlock[] _blocks; private float _opacity = -1f; internal Collider Collider; internal Vector3 Normal; internal int StackSlot; private const float FadeSteps = 8f; internal int RendererCount => _renderers.Length; internal DecalState(MeshRenderer[] renderers) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) _renderers = renderers; _baseColors = (Color[])(object)new Color[renderers.Length]; _blocks = (MaterialPropertyBlock[])(object)new MaterialPropertyBlock[renderers.Length]; for (int i = 0; i < renderers.Length; i++) { MeshRenderer val = renderers[i]; Material val2 = (((Object)(object)val != (Object)null) ? ((Renderer)val).sharedMaterial : null); _baseColors[i] = (((Object)(object)val2 != (Object)null && val2.HasProperty(ColorProperty)) ? val2.GetColor(ColorProperty) : Color.white); _blocks[i] = new MaterialPropertyBlock(); } } internal void SetOpacity(float opacity, bool force) { //IL_0071: 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_0092: Unknown result type (might be due to invalid IL or missing references) opacity = Mathf.Clamp01(opacity); if (opacity < 1f) { opacity = Mathf.Ceil(opacity * 8f) / 8f; } if (!force && Mathf.Abs(opacity - _opacity) < 0.001f) { return; } _opacity = opacity; for (int i = 0; i < _renderers.Length; i++) { MeshRenderer val = _renderers[i]; if (!((Object)(object)val == (Object)null)) { if (opacity >= 1f) { ((Renderer)val).SetPropertyBlock((MaterialPropertyBlock)null); continue; } Color val2 = _baseColors[i]; val2.a *= opacity; MaterialPropertyBlock val3 = _blocks[i]; val3.SetColor(ColorProperty, val2); ((Renderer)val).SetPropertyBlock(val3); } } } } internal const float DefaultLifetimeSeconds = 15f; internal const float DefaultFadeSeconds = 2f; internal const int DefaultMaxLive = 32; internal const float DefaultScale = 1f; private const float MinimumLifetimeSeconds = 5f; private const float MaximumLifetimeSeconds = 120f; private const int MinimumMaxLive = 8; private const int MaximumMaxLive = 256; private const float OverlapRadiusMeters = 0.08f; private const float SameSurfaceNormalDot = 0.94f; private static readonly int ColorProperty = Shader.PropertyToID("_Color"); private static readonly Action FadeVisitor = UpdateFade; private static readonly string[] InstanceDiagnosticKeys = new string[3] { "decal.instance.default", "decal.instance.metal", "decal.instance.wood" }; private static readonly string[] DefaultFamily = new string[5] { "Y4NGZ_BulletHole_Default_01", "Y4NGZ_BulletHole_Default_02", "Y4NGZ_BulletHole_Default_03", "Y4NGZ_BulletHole_Default_04", "Y4NGZ_BulletHole_Default_05" }; private static readonly string[] MetalFamily = new string[4] { "Y4NGZ_BulletHole_Metal_01", "Y4NGZ_BulletHole_Metal_02", "Y4NGZ_BulletHole_Metal_03", "Y4NGZ_BulletHole_Metal_04" }; private static readonly string[] WoodFamily = new string[5] { "Y4NGZ_BulletHole_Wood_01", "Y4NGZ_BulletHole_Wood_02", "Y4NGZ_BulletHole_Wood_03", "Y4NGZ_BulletHole_Wood_04", "Y4NGZ_BulletHole_Wood_05" }; private static VfxInstanceCache _cache; private static bool _enabled = true; private static float _lifetimeSeconds = 15f; private static float _fadeSeconds = 2f; private static float _scale = 1f; private static int _maxLive = 32; internal static void Configure(bool enabled, float lifetimeSeconds, float fadeSeconds, int maxLive, float scale) { int num = Mathf.Clamp(maxLive, 8, 256); bool num2 = _cache == null || num != _maxLive; _enabled = enabled; _lifetimeSeconds = Mathf.Clamp(lifetimeSeconds, 5f, 120f); _fadeSeconds = Mathf.Clamp(fadeSeconds, 0f, _lifetimeSeconds); _scale = Mathf.Clamp(scale, 0.1f, 5f); _maxLive = num; if (num2) { _cache?.StopAll(); _cache = new VfxInstanceCache(_maxLive, _maxLive); } else if (!_enabled) { _cache.StopAll(); } } internal static void PlayWorldHit(WeaponHit hit, WeaponWorldImpactFamily family) { //IL_0046: 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_004b: 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_004d: 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_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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) if (!_enabled || (Object)(object)hit.Collider == (Object)null) { return; } EnsureCache(); _cache.RetireExpired(); Vector3 val = ((((Vector3)(ref hit.Normal)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref hit.Normal)).normalized : Vector3.up); Vector3 val2 = ((Mathf.Abs(Vector3.Dot(val, Vector3.up)) > 0.95f) ? Vector3.forward : Vector3.up); Quaternion val3 = Quaternion.AngleAxis(Random.Range(0f, 360f), val) * Quaternion.LookRotation(val, val2); VfxInstanceCache.Entry overlapped; int num = FindStackSlot(hit.Collider, hit.Point, val, out overlapped); if (overlapped != null) { ReplaceInPlace(overlapped, hit, val, val3); return; } _cache.EnforceCapacityForNewInstance(); string[] array = PrefabsFor(family); string text = array[Random.Range(0, array.Length)]; GameObject val4 = WeaponVfxRuntimeAssets.LoadPrefab(text); if ((Object)(object)val4 == (Object)null) { if (WeaponVfxDiagnostics.Once("decal.noprefab." + family)) { WeaponVfxDiagnostics.Emit("Bullet hole aborted: prefab '" + text + "' did not resolve."); } return; } float num2 = BulletHoleDecalModel.OffsetForStackSlot(num); Vector3 val5 = hit.Point + val * num2; VfxInstanceCache.Entry entry = RentDecal(text, val4); if (entry != null) { GameObject instance = entry.Instance; instance.transform.SetParent((Transform)null, true); instance.transform.SetPositionAndRotation(val5, val3); instance.transform.localScale = entry.BaseScale * (_scale * Random.Range(0.9f, 1.1f)); instance.transform.SetParent(((Component)hit.Collider).transform, true); instance.SetActive(true); DecalState decalState = (DecalState)entry.State; decalState.Collider = hit.Collider; decalState.Normal = val; decalState.StackSlot = num; decalState.SetOpacity(1f, force: true); _cache.Track(entry, _lifetimeSeconds); WeaponVfxHousekeeping.EnsureDriver(); if (WeaponVfxDiagnostics.Once(DiagnosticKeyFor(family))) { string[] obj = new string[11] { $"Bullet hole fired. family={family} prefab='{text}' ", "source=", WeaponVfxRuntimeAssets.SourceFor(text) ?? "", " origin=", ((Vector3)(ref val5)).ToString("F3"), " normal=", ((Vector3)(ref val)).ToString("F3"), " ", null, null, null }; object arg = num2; object arg2 = num; Vector3 lossyScale = instance.transform.lossyScale; obj[8] = string.Format("offset={0:F4} stack={1} scale={2} ", arg, arg2, ((Vector3)(ref lossyScale)).ToString("F3")); obj[9] = $"parent='{((Object)hit.Collider).name}' renderers={decalState.RendererCount} "; obj[10] = $"lifetime={_lifetimeSeconds:F1}s fade={_fadeSeconds:F1}s cap={_maxLive}"; WeaponVfxDiagnostics.Emit(string.Concat(obj)); } } } private static void ReplaceInPlace(VfxInstanceCache.Entry decal, WeaponHit hit, Vector3 normal, Quaternion orientation) { //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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0097: 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) DecalState decalState = (DecalState)decal.State; Vector3 val = hit.Point + normal * BulletHoleDecalModel.OffsetForStackSlot(decalState.StackSlot); GameObject instance = decal.Instance; instance.transform.SetParent((Transform)null, true); instance.transform.SetPositionAndRotation(val, orientation); instance.transform.localScale = decal.BaseScale * (_scale * Random.Range(0.9f, 1.1f)); instance.transform.SetParent(((Component)hit.Collider).transform, true); decalState.Collider = hit.Collider; decalState.Normal = normal; decalState.SetOpacity(1f, force: true); _cache.Refresh(decal, _lifetimeSeconds); } private static string DiagnosticKeyFor(WeaponWorldImpactFamily family) { if (family < WeaponWorldImpactFamily.Default || (int)family >= InstanceDiagnosticKeys.Length) { return InstanceDiagnosticKeys[0]; } return InstanceDiagnosticKeys[(int)family]; } private static string[] PrefabsFor(WeaponWorldImpactFamily family) { return family switch { WeaponWorldImpactFamily.Metal => MetalFamily, WeaponWorldImpactFamily.Wood => WoodFamily, _ => DefaultFamily, }; } private static VfxInstanceCache.Entry RentDecal(string prefabName, GameObject prefab) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (_cache.TryRent(prefabName, out var entry)) { return entry; } GameObject val = Object.Instantiate(prefab); MeshRenderer[] componentsInChildren = val.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { Object.Destroy((Object)(object)val); if (WeaponVfxDiagnostics.Once("decal.norenderer." + prefabName)) { WeaponVfxDiagnostics.Emit("Bullet hole aborted: '" + prefabName + "' contains no MeshRenderer."); } return null; } return new VfxInstanceCache.Entry { Instance = val, Systems = null, PoolKey = prefabName, BaseScale = val.transform.localScale, State = new DecalState(componentsInChildren) }; } private static int FindStackSlot(Collider collider, Vector3 point, Vector3 normal, out VfxInstanceCache.Entry overlapped) { //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) //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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) overlapped = null; int num = 0; float num2 = 0.0064f; for (int i = 0; i < _cache.LiveCount; i++) { VfxInstanceCache.Entry entry = _cache.LiveEntryAt(i); if (entry == null || (Object)(object)entry.Instance == (Object)null || !(entry.State is DecalState decalState) || (Object)(object)decalState.Collider != (Object)(object)collider || Vector3.Dot(decalState.Normal, normal) < 0.94f) { continue; } Vector3 val = entry.Instance.transform.position - point; if (!(((Vector3)(ref val)).sqrMagnitude > num2)) { if (overlapped == null) { overlapped = entry; } num = Mathf.Max(num, decalState.StackSlot + 1); } } return num % 19; } private static void EnsureCache() { if (_cache == null) { _cache = new VfxInstanceCache(_maxLive, _maxLive); } } private static void UpdateFade(VfxInstanceCache.Entry entry, float remainingSeconds) { if (entry.State is DecalState decalState) { decalState.SetOpacity(BulletHoleDecalModel.OpacityForRemaining(remainingSeconds, _fadeSeconds), force: false); } } internal static void UpdateExternal() { if (_cache != null && _cache.LiveCount != 0) { _cache.VisitLive(FadeVisitor); _cache.RetireExpired(); } } internal static void StopAll() { _cache?.StopAll(); } } internal enum WeaponAmmoType { ShotgunShells, Fuel, Grenades, SmallCaliberRounds, HeavyCaliberRounds } internal enum WeaponFireMode { HitscanPellets, HitscanSingle, FullAutoHitscan, ContinuousStream, LobbedProjectile } internal enum WeaponCrosshairFamily { Rifle, Marksman, Pistol, ShotgunBracket, Stream, Projectile } internal sealed class WeaponConfig { public string Id; public string DisplayName; public WeaponAmmoType AmmoType; public WeaponFireMode FireMode; public int MagazineSize = 2; public bool ReloadFillsMagazine; public float RecoilPitchDegrees = 3.2f; public float RecoilYawDegrees = 0.9f; public float RecoilRecoverySpeed = 8f; public float RecoilPermanentClimbFraction = 0.2f; public int PelletCount = 8; public float SpreadDegrees = 10f; public float FireCooldownSeconds; public int EnemyDamageClose = 1; public int EnemyDamageFar = 1; public int PlayerDamageClose = 20; public int PlayerDamageFar = 10; public float EnemyCastRadiusMeters = 0.3f; public WeaponCrosshairFamily CrosshairFamily; public float MoveBloomMaxDegrees; public float SprintBloomDegrees; public float AirborneBloomDegrees; public float CrouchSpreadMultiplier = 1f; public float ShotBloomPerShotDegrees; public float ShotBloomMaxDegrees; public float RecoilBloomScale = 0.35f; public bool SpreadIsCosmetic; public int CreditsWorth = 90; public string ShopDescription = string.Empty; public bool Native; public float RoundsPerMinute; public float MaxRangeMeters = 60f; public float Weight = 1.08f; public bool TwoHanded; public bool TwoHandedAnimation; public bool DefensiveWeapon = true; public bool StartsWithSafetyOn = true; public bool CanBeGrabbedBeforeGameStart = true; public bool ConductiveMetal = true; public bool IsScrap; public string GrabAnimation = string.Empty; public float GrabAnimationTime = 0.3f; public float VerticalOffset = 0.06f; public int FloorYOffset; public Vector3 RestingRotation = Vector3.zero; public Vector3 HeldRotationOffset = Vector3.zero; public Vector3 HeldPositionOffset = Vector3.zero; public bool MeshOffset; public bool ReuseVanillaShotgunItemAssets; public bool PreserveLegacyNetworkHash; public bool NativeVisualConfigIsDelta; public float ReloadSeconds = 1.9f; public float ReloadStartSeconds; public float ReloadPerRoundSeconds; public float ReloadEndSeconds; public float ReloadEmptySeconds; public string MuzzleFlashPrefabName = "Y4NGZ_MuzzleFlash_01"; public float MuzzleFlashScale = 1f; public float ShotNoiseRange = 26f; public float ShotNoiseLoudness = 0.85f; internal bool HasStagedReload { get { if (ReloadStartSeconds > 0f && ReloadPerRoundSeconds > 0f) { return ReloadEndSeconds > 0f; } return false; } } internal bool HasStagedEmptyReload => ReloadEmptySeconds > 0f; internal float ResolveFireInterval() { if (RoundsPerMinute > 0f) { return 60f / RoundsPerMinute; } return Mathf.Max(0f, FireCooldownSeconds); } internal float ResolveReloadDuration(bool wasEmpty, int roundsDrawn) { if (wasEmpty && HasStagedEmptyReload) { return ReloadEmptySeconds; } if (HasStagedReload) { return ReloadStartSeconds + (float)Mathf.Max(1, roundsDrawn) * ReloadPerRoundSeconds + ReloadEndSeconds; } return ReloadSeconds; } } internal static class WeaponCatalog { internal const string HeavyShotgunId = "heavy_shotgun"; internal static readonly WeaponConfig HeavyShotgun = new WeaponConfig { Id = "heavy_shotgun", DisplayName = "Heavy Shotgun", Native = true, AmmoType = WeaponAmmoType.ShotgunShells, FireMode = WeaponFireMode.HitscanPellets, MagazineSize = 4, ReloadFillsMagazine = false, FireCooldownSeconds = 0.7f, ReloadSeconds = 3.167f, RecoilPitchDegrees = 4.4f, RecoilYawDegrees = 1.1f, RecoilRecoverySpeed = 7f, RecoilPermanentClimbFraction = 0.2f, PelletCount = 10, SpreadDegrees = 11f, MaxRangeMeters = 30f, EnemyDamageClose = 1, EnemyDamageFar = 1, PlayerDamageClose = 100, PlayerDamageFar = 25, CrosshairFamily = WeaponCrosshairFamily.ShotgunBracket, MoveBloomMaxDegrees = 0f, SprintBloomDegrees = 0f, AirborneBloomDegrees = 0.6f, CrouchSpreadMultiplier = 0.85f, ShotBloomPerShotDegrees = 0.6f, ShotBloomMaxDegrees = 1.8f, SpreadIsCosmetic = false, Weight = 1.15f, TwoHanded = false, TwoHandedAnimation = true, DefensiveWeapon = true, StartsWithSafetyOn = false, CanBeGrabbedBeforeGameStart = false, ConductiveMetal = false, IsScrap = true, GrabAnimation = "HoldShotgun", GrabAnimationTime = 0f, VerticalOffset = 0.12f, FloorYOffset = 90, RestingRotation = new Vector3(180f, 0f, -90f), HeldRotationOffset = new Vector3(-90.89f, -1.5f, 0f), HeldPositionOffset = new Vector3(0f, 0.39f, 0f), MeshOffset = true, ReuseVanillaShotgunItemAssets = true, PreserveLegacyNetworkHash = true, NativeVisualConfigIsDelta = true, MuzzleFlashPrefabName = "Y4NGZ_MuzzleFlash_03", MuzzleFlashScale = 1f, ShotNoiseRange = 30f, ShotNoiseLoudness = 1f, CreditsWorth = 110, ShopDescription = "A short, brutal pump gun built for corridors. Wide pattern, heavy kick, and it feeds from the same shells the company's own shotgun uses." }; internal const string RevolverId = "revolver"; internal static readonly WeaponConfig Revolver = new WeaponConfig { Id = "revolver", DisplayName = "Revolver", Native = true, AmmoType = WeaponAmmoType.SmallCaliberRounds, FireMode = WeaponFireMode.HitscanSingle, MagazineSize = 5, ReloadFillsMagazine = true, FireCooldownSeconds = 0.7f, ReloadSeconds = 8.5f, ReloadStartSeconds = 1.6f, ReloadPerRoundSeconds = 1.08f, ReloadEndSeconds = 1.5f, RecoilPitchDegrees = 3f, RecoilYawDegrees = 0.7f, RecoilRecoverySpeed = 9f, RecoilPermanentClimbFraction = 0.2f, PelletCount = 1, SpreadDegrees = 2f, MaxRangeMeters = 60f, EnemyDamageClose = 2, EnemyDamageFar = 2, PlayerDamageClose = 60, PlayerDamageFar = 30, CrosshairFamily = WeaponCrosshairFamily.Pistol, MoveBloomMaxDegrees = 0.5f, SprintBloomDegrees = 0.35f, AirborneBloomDegrees = 0.9f, CrouchSpreadMultiplier = 0.65f, ShotBloomPerShotDegrees = 0.4f, ShotBloomMaxDegrees = 1.2f, SpreadIsCosmetic = false, Weight = 1.15f, TwoHanded = false, TwoHandedAnimation = true, DefensiveWeapon = true, StartsWithSafetyOn = false, CanBeGrabbedBeforeGameStart = false, ConductiveMetal = false, IsScrap = true, GrabAnimation = "HoldShotgun", GrabAnimationTime = 0f, VerticalOffset = 0.12f, FloorYOffset = 90, RestingRotation = new Vector3(180f, 0f, -90f), HeldRotationOffset = new Vector3(-90.89f, -1.5f, 0f), HeldPositionOffset = new Vector3(0f, 0.39f, 0f), MeshOffset = true, ReuseVanillaShotgunItemAssets = true, PreserveLegacyNetworkHash = true, NativeVisualConfigIsDelta = true, MuzzleFlashPrefabName = "Y4NGZ_MuzzleFlash_01", MuzzleFlashScale = 0.65f, ShotNoiseRange = 26f, ShotNoiseLoudness = 0.85f, CreditsWorth = 80, ShopDescription = "A cylinder, no magazine, nothing to jam. Deliberate work at short range; the reload is slow enough that you will want cover for it." }; internal const string FlameThrowerId = "flame_thrower"; internal static readonly WeaponConfig FlameThrower = new WeaponConfig { Id = "flame_thrower", DisplayName = "Flame Thrower", AmmoType = WeaponAmmoType.Fuel, FireMode = WeaponFireMode.ContinuousStream, MagazineSize = 100, ReloadFillsMagazine = true, RecoilPitchDegrees = 0f, RecoilYawDegrees = 0f, RecoilRecoverySpeed = 0f, PelletCount = 0, SpreadDegrees = 0f, FireCooldownSeconds = 0f, EnemyDamageClose = 1, EnemyDamageFar = 1, PlayerDamageClose = 1, PlayerDamageFar = 1, Weight = 1.18f, TwoHanded = true, TwoHandedAnimation = true, CrosshairFamily = WeaponCrosshairFamily.Stream, RecoilBloomScale = 0f, CreditsWorth = 120, ShopDescription = "Sprays burning fuel in a short cone and leaves the floor alight behind it. Runs off fuel tanks, not rounds. Mind the tank on your back." }; internal const string GrenadeLauncherId = "grenade_launcher"; internal static readonly WeaponConfig GrenadeLauncher = new WeaponConfig { Id = "grenade_launcher", DisplayName = "Grenade Launcher", AmmoType = WeaponAmmoType.Grenades, FireMode = WeaponFireMode.LobbedProjectile, MagazineSize = 6, ReloadFillsMagazine = true, RecoilPitchDegrees = 4f, RecoilYawDegrees = 0.6f, RecoilRecoverySpeed = 7f, PelletCount = 1, SpreadDegrees = 0f, FireCooldownSeconds = 0.45f, EnemyDamageClose = 1, EnemyDamageFar = 1, PlayerDamageClose = 60, PlayerDamageFar = 45, CrosshairFamily = WeaponCrosshairFamily.Projectile, RecoilBloomScale = 0f, SpreadIsCosmetic = true, CreditsWorth = 130, ShopDescription = "A break-open launcher that lobs the same grenades you would otherwise throw. Explosives do not check whose side you are on." }; internal const string MX16A4Id = "mx16a4"; internal static readonly WeaponConfig MX16A4 = new WeaponConfig { Id = "mx16a4", DisplayName = "Assault Rifle", Native = true, AmmoType = WeaponAmmoType.HeavyCaliberRounds, FireMode = WeaponFireMode.FullAutoHitscan, MagazineSize = 30, ReloadFillsMagazine = true, ReloadSeconds = 2.7f, RoundsPerMinute = 750f, PelletCount = 1, SpreadDegrees = 2f, MaxRangeMeters = 80f, EnemyDamageClose = 1, EnemyDamageFar = 1, PlayerDamageClose = 28, PlayerDamageFar = 18, CrosshairFamily = WeaponCrosshairFamily.Rifle, MoveBloomMaxDegrees = 1f, SprintBloomDegrees = 0.8f, AirborneBloomDegrees = 1.8f, CrouchSpreadMultiplier = 0.6f, ShotBloomPerShotDegrees = 0.35f, ShotBloomMaxDegrees = 3f, RecoilPitchDegrees = 2.4f, RecoilYawDegrees = 0.7f, RecoilRecoverySpeed = 6.5f, RecoilPermanentClimbFraction = 0.25f, Weight = 1.16f, TwoHanded = true, TwoHandedAnimation = true, DefensiveWeapon = true, StartsWithSafetyOn = true, ReuseVanillaShotgunItemAssets = true, MuzzleFlashPrefabName = "Y4NGZ_MuzzleFlash_01", MuzzleFlashScale = 1f, ShotNoiseRange = 30f, ShotNoiseLoudness = 0.9f, CreditsWorth = 140, ShopDescription = "Select-fire rifle chambered for heavy calibre. Holds a long burst, and the cone opens up fast if you hold the trigger down. Two hands, always." }; internal const string Kar98KId = "kar98k"; internal static readonly WeaponConfig Kar98K = new WeaponConfig { Id = "kar98k", DisplayName = "Bolt-Action Rifle", Native = true, AmmoType = WeaponAmmoType.HeavyCaliberRounds, FireMode = WeaponFireMode.HitscanSingle, MagazineSize = 5, ReloadFillsMagazine = true, RoundsPerMinute = 200f, ReloadSeconds = 4.6667f, ReloadEmptySeconds = 4.6667f, ReloadStartSeconds = 1.2667f, ReloadPerRoundSeconds = 0.7667f, ReloadEndSeconds = 2f, PelletCount = 1, SpreadDegrees = 0.65f, MaxRangeMeters = 110f, EnemyDamageClose = 2, EnemyDamageFar = 2, PlayerDamageClose = 85, PlayerDamageFar = 55, CrosshairFamily = WeaponCrosshairFamily.Marksman, MoveBloomMaxDegrees = 1.4f, SprintBloomDegrees = 1.2f, AirborneBloomDegrees = 2.4f, CrouchSpreadMultiplier = 0.5f, ShotBloomPerShotDegrees = 0.5f, ShotBloomMaxDegrees = 1f, RecoilPitchDegrees = 6f, RecoilYawDegrees = 1f, RecoilRecoverySpeed = 5.5f, RecoilPermanentClimbFraction = 0.35f, Weight = 1.2f, TwoHanded = true, TwoHandedAnimation = true, DefensiveWeapon = true, StartsWithSafetyOn = true, ReuseVanillaShotgunItemAssets = true, MuzzleFlashPrefabName = "Y4NGZ_MuzzleFlash_03", MuzzleFlashScale = 1f, ShotNoiseRange = 38f, ShotNoiseLoudness = 1f, CreditsWorth = 165, ShopDescription = "Bolt-action marksman rifle on heavy calibre. The tightest shot in the catalogue if you stand still for it, and nearly useless on the move." }; internal const string X18Id = "x18"; internal static readonly WeaponConfig X18 = new WeaponConfig { Id = "x18", DisplayName = "Pistol", Native = true, AmmoType = WeaponAmmoType.SmallCaliberRounds, FireMode = WeaponFireMode.HitscanSingle, MagazineSize = 17, ReloadFillsMagazine = true, ReloadSeconds = 2.316667f, ReloadEmptySeconds = 2.583333f, RoundsPerMinute = 900f, PelletCount = 1, SpreadDegrees = 2.2f, MaxRangeMeters = 55f, EnemyDamageClose = 1, EnemyDamageFar = 1, PlayerDamageClose = 22, PlayerDamageFar = 12, CrosshairFamily = WeaponCrosshairFamily.Pistol, MoveBloomMaxDegrees = 0.65f, SprintBloomDegrees = 0.5f, AirborneBloomDegrees = 1.1f, CrouchSpreadMultiplier = 0.65f, ShotBloomPerShotDegrees = 0.28f, ShotBloomMaxDegrees = 2.4f, RecoilPitchDegrees = 1.35f, RecoilYawDegrees = 0.45f, RecoilRecoverySpeed = 8.5f, RecoilPermanentClimbFraction = 0.2f, Weight = 1.06f, TwoHanded = false, TwoHandedAnimation = false, DefensiveWeapon = true, StartsWithSafetyOn = true, ReuseVanillaShotgunItemAssets = true, MuzzleFlashPrefabName = "Y4NGZ_MuzzleFlash_01", MuzzleFlashScale = 0.65f, ShotNoiseRange = 24f, ShotNoiseLoudness = 0.8f, CreditsWorth = 95, ShopDescription = "Semi-automatic sidearm on small calibre. One shot per click, a deep magazine, and light enough to keep a hand free for the ladder." }; internal static IEnumerable All() { yield return FlameThrower; } internal static IEnumerable AllNative() { yield return HeavyShotgun; yield return Revolver; yield return MX16A4; yield return Kar98K; yield return X18; } internal static IEnumerable AllRegistered() { foreach (WeaponConfig item in All()) { yield return item; } foreach (WeaponConfig item2 in AllNative()) { yield return item2; } } internal static WeaponConfig ById(string id) { foreach (WeaponConfig item in All()) { if (item.Id == id) { return item; } } foreach (WeaponConfig item2 in AllNative()) { if (item2.Id == id) { return item2; } } return HeavyShotgun; } } internal static class WeaponCreatureBlood { internal static bool Enabled = true; internal static float BurstScale = 1f; private static bool? _bloodFxPluginPresent; private static float AmmoScale(WeaponAmmoType ammo) { return ammo switch { WeaponAmmoType.SmallCaliberRounds => 1f, WeaponAmmoType.HeavyCaliberRounds => 1.45f, WeaponAmmoType.ShotgunShells => 1.7f, WeaponAmmoType.Grenades => 2.2f, WeaponAmmoType.Fuel => 1f, _ => 1f, }; } internal static void Play(WeaponHit hit, EnemyAI enemy, ImpactMaterial material, int contacts, WeaponAmmoType ammo) { if (!Enabled || (Object)(object)enemy == (Object)null || !ImpactMaterialCatalog.Bleeds(material)) { return; } if (!BloodFxPluginPresent()) { if (WeaponVfxDiagnostics.Once("impact.creature.blood.plugin-absent")) { WeaponVfxDiagnostics.Emit("Creature blood (#120) is unavailable: the Y4NGZBloodFX plugin (com.y4ngz.bloodfx) is not installed. Flesh and insect creatures will draw no impact effect."); } } else { PlayViaBloodFx(hit, enemy, material, contacts, ammo); } } private static bool BloodFxPluginPresent() { if (!_bloodFxPluginPresent.HasValue) { _bloodFxPluginPresent = Chainloader.PluginInfos.ContainsKey("com.y4ngz.bloodfx"); } return _bloodFxPluginPresent.Value; } [MethodImpl(MethodImplOptions.NoInlining)] private static void PlayViaBloodFx(WeaponHit hit, EnemyAI enemy, ImpactMaterial material, int contacts, WeaponAmmoType ammo) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_0049: 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_0050: 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_0075: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) if (!BloodFxBridge.IsAvailable) { if (WeaponVfxDiagnostics.Once("impact.creature.blood.unavailable")) { WeaponVfxDiagnostics.Emit("Creature blood (#120) is unavailable: Y4NGZBloodFX is disabled in config or its bundle did not load. Flesh and insect creatures will draw no impact effect. Check '[08 - Blood FX] Enabled' in com.y4ngz.bloodfx.cfg and the Y4NGZBloodFX log."); } return; } Vector3 travel = ((((Vector3)(ref hit.Normal)).sqrMagnitude > 1E-06f) ? (-((Vector3)(ref hit.Normal)).normalized) : Vector3.zero); Color val = ImpactMaterialCatalog.BloodTint(material); float num = Mathf.Max(0.01f, BurstScale * AmmoScale(ammo)); bool flag = BloodFxBridge.PlayCreatureBleed(((Object)enemy).GetInstanceID(), hit.Point, travel, val, contacts, num); if (WeaponVfxDiagnostics.Once("impact.creature.blood." + material.ToString() + "." + ammo)) { WeaponVfxDiagnostics.Emit($"Creature blood (#120). material={material} " + $"tint=({val.r:F2},{val.g:F2},{val.b:F2},{val.a:F2})" + ((val.a > 0f) ? string.Empty : " [authored asset colour]") + " " + $"enemy='{((object)enemy).GetType().Name}' contacts={contacts} " + $"ammo={ammo} scale={num:F2} (burst={BurstScale:F2} x ammo={AmmoScale(ammo):F2}) " + string.Format("point={0} travel={1} drew={2}. ", ((Vector3)(ref hit.Point)).ToString("F3"), ((Vector3)(ref travel)).ToString("F3"), flag) + "drew=False is normal for a gated event (too far, or rate limited); enable '[08 - Blood FX] Debug Logging' in com.y4ngz.bloodfx.cfg (Y4NGZBloodFX plugin) for the reason."); } } } internal sealed class WeaponDevSpawnHost : MonoBehaviour { internal static Key SpawnKey = (Key)68; internal static Key SpawnRevolverKey = (Key)69; internal static Key SpawnFlamethrowerKey = (Key)66; internal static Key SpawnNativeKey = (Key)71; internal static Key? VfxIsolationKey = (Key)102; internal static bool Enabled = true; internal static bool AutoSpawn = true; private static readonly string[] IsolationPrefabs = new string[8] { "Y4NGZ_MuzzleFlash_01", "Y4NGZ_MuzzleFlash_02", "Y4NGZ_MuzzleFlash_03", "Y4NGZ_HitImpact_Concrete_01", "Y4NGZ_HitImpact_Concrete_02", "Y4NGZ_HitImpact_Metal_01", "Y4NGZ_HitImpact_Wood_01", "Y4NGZ_HitImpact_Wood_02" }; private int _isolationIndex; private int _lastFrame = -1; private bool _loggedAlive; private bool _autoSpawned; private float _controlledSince = -1f; internal static void Ensure() { //IL_0056: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) GameObject host = ArmoryPersistentRunner.Host; if (!((Object)(object)host == (Object)null) && !((Object)(object)host.GetComponent() != (Object)null)) { host.AddComponent(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZWeapons] Dev spawn host attached (enabled={Enabled}, autoSpawn={AutoSpawn}, shotgun={SpawnKey}, revolver={SpawnRevolverKey}, flamethrower={SpawnFlamethrowerKey}, native={SpawnNativeKey})."); } } } private void Update() { //IL_0029: 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_0092: 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_00b4: Unknown result type (might be due to invalid IL or missing references) if (!_loggedAlive) { _loggedAlive = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZWeapons] Dev spawn host Update is live (enabled={Enabled}, key={SpawnKey}, " + "keyboard=" + ((Keyboard.current != null) ? "ok" : "null") + ").")); } } if (TryVfxIsolationTest() || !Enabled) { return; } TryAutoSpawn(); Keyboard current = Keyboard.current; if (current == null) { return; } bool wasPressedThisFrame = ((ButtonControl)current[SpawnKey]).wasPressedThisFrame; bool wasPressedThisFrame2 = ((ButtonControl)current[SpawnRevolverKey]).wasPressedThisFrame; bool wasPressedThisFrame3 = ((ButtonControl)current[SpawnFlamethrowerKey]).wasPressedThisFrame; bool wasPressedThisFrame4 = ((ButtonControl)current[SpawnNativeKey]).wasPressedThisFrame; if ((!wasPressedThisFrame && !wasPressedThisFrame2 && !wasPressedThisFrame3 && !wasPressedThisFrame4) || _lastFrame == Time.frameCount) { return; } _lastFrame = Time.frameCount; if (wasPressedThisFrame4) { bool flag = false; foreach (WeaponConfig item in WeaponCatalog.AllNative()) { flag = true; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Y4NGZWeapons] Dev spawn key pressed — attempting native " + item.DisplayName + " spawn.")); } NativeWeaponRegistry.DebugSpawnAtLocalPlayer(item); } if (!flag) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)"[Y4NGZWeapons] Dev spawn key pressed — no native weapons are registered."); } } } else { WeaponConfig weaponConfig = (wasPressedThisFrame3 ? WeaponCatalog.FlameThrower : (wasPressedThisFrame2 ? WeaponCatalog.Revolver : WeaponCatalog.HeavyShotgun)); ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)("[Y4NGZWeapons] Dev spawn key pressed — attempting " + weaponConfig.DisplayName + " spawn.")); } WeaponRuntimeRegistry.DebugSpawnAtLocalPlayer(weaponConfig); } } private bool TryVfxIsolationTest() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!VfxIsolationKey.HasValue || !WeaponVfxDiagnostics.Enabled) { return false; } Keyboard current = Keyboard.current; if (current == null || !((ButtonControl)current[VfxIsolationKey.Value]).wasPressedThisFrame) { return false; } if (_lastFrame == Time.frameCount) { return true; } _lastFrame = Time.frameCount; string text = IsolationPrefabs[_isolationIndex]; _isolationIndex = (_isolationIndex + 1) % IsolationPrefabs.Length; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons] VFX isolation test key pressed — spawning '" + text + "' " + $"({_isolationIndex}/{IsolationPrefabs.Length} next).")); } WeaponMuzzleFlash.PlayIsolatedInFrontOfCamera(text); return true; } private void TryAutoSpawn() { if (_autoSpawned || !AutoSpawn) { return; } NetworkManager singleton = NetworkManager.Singleton; PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if ((Object)(object)singleton == (Object)null || !singleton.IsServer || (Object)(object)val == (Object)null || !val.isPlayerControlled || val.isPlayerDead) { _controlledSince = -1f; return; } if (_controlledSince < 0f) { _controlledSince = Time.time; } if (!(Time.time - _controlledSince < 2.5f)) { _autoSpawned = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[Y4NGZWeapons] Dev auto-spawn firing (host + player controlled)."); } WeaponRuntimeRegistry.DebugSpawnAtLocalPlayer(WeaponCatalog.HeavyShotgun); } } } [HarmonyPatch] public static class WeaponFirstPersonAnimation { private sealed class FpWeaponProfile { public string ConfigId; public string PackId; public string InteractionId; public string ManifestFileName; public string PackDisplayName; public string ArmsFireTrigger; public string ArmsReloadTrigger; public string ArmsReloadEmptyTrigger = string.Empty; public string ArmsReloadRoundsTriggerPrefix = string.Empty; public string ArmsDrawTrigger; public string ArmsFiringBool = string.Empty; public string PropNameSubstring; public string PropFireTrigger; public string PropFireEmptyTrigger = string.Empty; public string PropReloadTrigger; public string PropReloadEmptyTrigger = string.Empty; public string PropReloadRoundsTriggerPrefix = string.Empty; public string PropDrawTrigger; public string PropFiringBool = string.Empty; public float EquipDrawChance; public string LeftHandAnchorChildName; public string FingerPosesFileName; public Func PropMaterial; public Func PropMaterials; public bool PackRegistered; public bool ManifestMissingPermanent; public bool MissingManifestLogged; public bool RegistrationFailureLogged; public bool FingerPosesLoadAttempted; public StaticFingerPose[] FingerPoses; public bool FingerPosesAdditive; } [Serializable] private sealed class StaticFingerPose { public string hand = string.Empty; public string relativePath = string.Empty; public Quaternion localRotation = Quaternion.identity; public Vector3 curlAxis = Vector3.zero; } private struct FingerBinding { public Transform Bone; public Quaternion LocalRotation; public Vector3 CurlAxis; public bool IsLeft; public bool IsTip; public bool IsThumb; } [Serializable] private sealed class StaticFingerPoseFile { public string mode = string.Empty; public StaticFingerPose[] poses; } [CompilerGenerated] private static class <>O { public static UnityAction <0>__OnBeforeRenderEnforceFingerPoses; } private static readonly FpWeaponProfile HeavyShotgunFpProfile = new FpWeaponProfile { ConfigId = "heavy_shotgun", PackId = "y4ngz.upgrades.heavyshotgun.fp", InteractionId = "y4ngz.heavy_shotgun.livebody", ManifestFileName = "y4ngz-interactions-heavyshotgun-livebody.manifest.json", PackDisplayName = "Y4NGZ Heavy Shotgun First Person", ArmsFireTrigger = "Y4NGZ_HeavyShotgun_Fire", ArmsReloadTrigger = "Y4NGZ_HeavyShotgun_Reload", PropNameSubstring = "Y4NGZ_FPSHeavyShotgunProp", PropFireTrigger = "Y4NGZ_HeavyShotgunProp_Fire", PropReloadTrigger = "Y4NGZ_HeavyShotgunProp_Reload", LeftHandAnchorChildName = "pump", FingerPosesFileName = "y4ngz-heavyshotgun-fp-finger-poses.json", PropMaterial = WeaponVisuals.GetHeavyShotgunMaterial }; private static readonly FpWeaponProfile RevolverFpProfile = new FpWeaponProfile { ConfigId = "revolver", PackId = "y4ngz.upgrades.revolver.fp", InteractionId = "y4ngz.revolver.livebody", ManifestFileName = "y4ngz-interactions-revolver-livebody.manifest.json", PackDisplayName = "Y4NGZ Revolver First Person", ArmsFireTrigger = "Y4NGZ_Revolver_Fire", ArmsReloadTrigger = "Y4NGZ_Revolver_Reload", ArmsDrawTrigger = "Y4NGZ_Revolver_Draw", PropNameSubstring = "Y4NGZ_FPSRevolverProp", PropFireTrigger = "Y4NGZ_RevolverProp_Fire", PropReloadTrigger = "Y4NGZ_RevolverProp_Reload", PropDrawTrigger = "Y4NGZ_RevolverProp_Draw", EquipDrawChance = 0.5f, LeftHandAnchorChildName = null, FingerPosesFileName = "y4ngz-revolver-fp-finger-poses.json", PropMaterial = () => WeaponVisuals.GetMaterial("revolver") }; private static readonly FpWeaponProfile FlamethrowerFpProfile = new FpWeaponProfile { ConfigId = "flame_thrower", PackId = "y4ngz.upgrades.flamethrower.fp", InteractionId = "y4ngz.flamethrower.livebody", ManifestFileName = "y4ngz-interactions-flamethrower-livebody.manifest.json", PackDisplayName = "Y4NGZ Flamethrower First Person", ArmsReloadTrigger = "Y4NGZ_Flamethrower_Reload", ArmsFiringBool = "Y4NGZ_Flamethrower_Firing", PropNameSubstring = "Y4NGZ_FPSFlamethrowerProp", PropReloadTrigger = "Y4NGZ_FlamethrowerProp_Reload", PropFiringBool = "Y4NGZ_FlamethrowerProp_Firing", LeftHandAnchorChildName = null, FingerPosesFileName = "y4ngz-flamethrower-fp-finger-poses.json", PropMaterial = FlamethrowerContentAssets.LoadRuntimeWeaponMaterial }; private static readonly FpWeaponProfile GrenadeLauncherFpProfile = new FpWeaponProfile { ConfigId = "grenade_launcher", PackId = "y4ngz.upgrades.grenadelauncher.fp", InteractionId = "y4ngz.grenade_launcher.livebody", ManifestFileName = "y4ngz-interactions-grenadelauncher-livebody.manifest.json", PackDisplayName = "Y4NGZ Grenade Launcher First Person", ArmsFireTrigger = "Y4NGZ_GrenadeLauncher_Fire", ArmsReloadTrigger = "Y4NGZ_GrenadeLauncher_Reload", ArmsDrawTrigger = "Y4NGZ_GrenadeLauncher_Draw", PropNameSubstring = "Y4NGZ_FPSGrenadeLauncherProp", PropFireTrigger = "Y4NGZ_GrenadeLauncherProp_Fire", PropReloadTrigger = "Y4NGZ_GrenadeLauncherProp_Reload", PropDrawTrigger = "Y4NGZ_GrenadeLauncherProp_Draw", EquipDrawChance = 1f, LeftHandAnchorChildName = null, FingerPosesFileName = "y4ngz-grenadelauncher-fp-finger-poses.json", PropMaterial = GrenadeLauncherContentAssets.LoadRuntimeWeaponMaterial }; private static readonly FpWeaponProfile MX16A4FpProfile = new FpWeaponProfile { ConfigId = "mx16a4", PackId = "y4ngz.upgrades.mx16a4.fp", InteractionId = "y4ngz.mx16a4.livebody", ManifestFileName = "y4ngz-upgrades-mx16a4-livebody.manifest.json", PackDisplayName = "Y4NGZ MX16A4 First Person", ArmsFireTrigger = "Y4NGZ_MX16A4_Fire", ArmsReloadTrigger = "Y4NGZ_MX16A4_Reload", ArmsReloadEmptyTrigger = "Y4NGZ_MX16A4_ReloadEmpty", PropNameSubstring = "Y4NGZ_FPSMX16A4Prop", PropFireTrigger = "Y4NGZ_MX16A4Prop_Fire", PropReloadTrigger = "Y4NGZ_MX16A4Prop_Reload", PropReloadEmptyTrigger = "Y4NGZ_MX16A4Prop_ReloadEmpty", LeftHandAnchorChildName = null, FingerPosesFileName = "y4ngz-mx16a4-fp-finger-poses.json", PropMaterials = () => WeaponModelRuntimeAssets.LoadWeaponMaterials("mx16a4") }; private static readonly FpWeaponProfile Kar98KFpProfile = new FpWeaponProfile { ConfigId = "kar98k", PackId = "y4ngz.upgrades.kar98k.fp", InteractionId = "y4ngz.kar98k.livebody", ManifestFileName = "y4ngz-upgrades-kar98k-livebody.manifest.json", PackDisplayName = "Y4NGZ Kar98K First Person", ArmsFireTrigger = "Y4NGZ_Kar98K_Fire", ArmsReloadTrigger = "Y4NGZ_Kar98K_Reload1", ArmsReloadEmptyTrigger = "Y4NGZ_Kar98K_ReloadEmpty", ArmsReloadRoundsTriggerPrefix = "Y4NGZ_Kar98K_Reload", PropNameSubstring = "Y4NGZ_FPSKar98KProp", PropFireTrigger = "Y4NGZ_Kar98KProp_Fire", PropReloadTrigger = "Y4NGZ_Kar98KProp_Reload1", PropReloadEmptyTrigger = "Y4NGZ_Kar98KProp_ReloadEmpty", PropReloadRoundsTriggerPrefix = "Y4NGZ_Kar98KProp_Reload", LeftHandAnchorChildName = null, FingerPosesFileName = "y4ngz-kar98k-fp-finger-poses.json", PropMaterials = () => WeaponModelRuntimeAssets.LoadWeaponMaterials("kar98k") }; private static readonly FpWeaponProfile X18FpProfile = new FpWeaponProfile { ConfigId = "x18", PackId = "y4ngz.upgrades.x18.fp", InteractionId = "y4ngz.x18.livebody", ManifestFileName = "y4ngz-upgrades-x18-livebody.manifest.json", PackDisplayName = "Y4NGZ X18 First Person", ArmsFireTrigger = "Y4NGZ_X18_Fire", ArmsReloadTrigger = "Y4NGZ_X18_Reload", ArmsReloadEmptyTrigger = "Y4NGZ_X18_ReloadEmpty", PropNameSubstring = "Y4NGZ_FPSX18Prop", PropFireTrigger = "Y4NGZ_X18Prop_Fire", PropFireEmptyTrigger = "Y4NGZ_X18Prop_FireEmpty", PropReloadTrigger = "Y4NGZ_X18Prop_Reload", PropReloadEmptyTrigger = "Y4NGZ_X18Prop_ReloadEmpty", LeftHandAnchorChildName = null, FingerPosesFileName = "y4ngz-x18-fp-finger-poses.json", PropMaterials = () => WeaponModelRuntimeAssets.LoadWeaponMaterials("x18") }; private static readonly FpWeaponProfile[] FpProfiles = new FpWeaponProfile[7] { HeavyShotgunFpProfile, RevolverFpProfile, FlamethrowerFpProfile, GrenadeLauncherFpProfile, MX16A4FpProfile, Kar98KFpProfile, X18FpProfile }; private static FpWeaponProfile _activeProfile = HeavyShotgunFpProfile; private const string LeftArmTargetPath = "metarig/spine.003/RigArms/LeftArm/ArmsLeftArm_target"; private const string RightArmTargetPath = "metarig/spine.003/RigArms/RightArm/ArmsRightArm_target"; private const string LeftArmUpperPath = "metarig/spine.003/shoulder.L/arm.L_upper"; private const string LeftArmLowerPath = "metarig/spine.003/shoulder.L/arm.L_upper/arm.L_lower"; private const string LeftHandPath = "metarig/spine.003/shoulder.L/arm.L_upper/arm.L_lower/hand.L"; private const string RightHandPath = "metarig/spine.003/shoulder.R/arm.R_upper/arm.R_lower/hand.R"; private const float LeftHandGunAnchorDiagIntervalSeconds = 2f; internal static bool FingerCurlDiagnostics; private const float LeftHandPumpPullMeters = 0f; private const float PropLandmarkFrameToleranceMeters = 0.005f; private static readonly Dictionary HiddenRendererStates = new Dictionary(); private static bool _startFailureLogged; private static bool _exitRequested; private static InteractionAnimationHandle _activeHandle = InteractionAnimationHandle.Empty; private static IY4NGZFpWeapon _activeWeapon; private static Animator _propAnimator; private static Transform _propRoot; private static Vector3 _propBaseLocalPosition; private static Quaternion _propBaseLocalRotation = Quaternion.identity; private static Vector3 _propBaseLocalScale = Vector3.one; private static Vector3 _propMuzzleLocal; private static bool _hasPropMuzzleLocal; private static bool _propRootIsLandmarkFrame; private static Transform _muzzleParticleTransform; private static Vector3 _muzzleParticleOriginalLocalPosition; private static Quaternion _muzzleParticleOriginalLocalRotation = Quaternion.identity; private static bool _muzzleParticleOriginalCaptured; private static Transform _leftHandGunAnchorCachedPropRoot; private static Transform _leftArmIkTarget; private static Transform _rightArmIkTarget; private static Transform _leftArmUpperBone; private static Transform _leftArmLowerBone; private static Transform _leftHandBone; private static Transform _rightHandBone; private static Transform _pumpTransform; private static bool _leftHandGunAnchorResolveAttempted; private static bool _leftHandGunAnchorResolved; private static bool _leftHandGunAnchorMissingLogged; private static bool _leftHandGunAnchorTickFailureLogged; private static float _nextLeftHandGunAnchorDiagTime; private static readonly List _fingerPoseBindings = new List(); private static readonly List _fingerPoseFinal = new List(); private static Transform _fingerPoseCachedLeftHand; private static Transform _fingerPoseCachedRightHand; private static float _nextFingerDiagTime; private static bool _onBeforeRenderHooked; private static bool _onBeforeRenderFireLogged; private static int _gloveBisectStep; private static readonly List _gloveBisectDisabled = new List(); private static bool _gloveBisectCandidatesLogged; public static Vector3 PropPosDeltaLive { get; set; } = Vector3.zero; public static Vector3 PropRotDeltaLive { get; set; } = Vector3.zero; public static float PropScaleMultLive { get; set; } = 1f; public static bool PropTuningLiveOverride { get; set; } public static float FingerCurlDeltaLeftLive { get; set; } public static float FingerTipCurlDeltaLeftLive { get; set; } public static float ThumbCurlDeltaLeftLive { get; set; } public static float FingerCurlDeltaRightLive { get; set; } public static float FingerTipCurlDeltaRightLive { get; set; } public static float ThumbCurlDeltaRightLive { get; set; } private static FpWeaponProfile ProfileFor(IY4NGZFpWeapon weapon) { string b = (IsAlive(weapon) ? weapon.FpConfigId : null); FpWeaponProfile[] fpProfiles = FpProfiles; foreach (FpWeaponProfile fpWeaponProfile in fpProfiles) { if (string.Equals(fpWeaponProfile.ConfigId, b, StringComparison.Ordinal)) { return fpWeaponProfile; } } return HeavyShotgunFpProfile; } internal static bool ApiOwnsPlayerBody(PlayerControllerB player) { if ((Object)(object)player != (Object)null) { InteractionAnimationHandle val = default(InteractionAnimationHandle); if (!LCInteractionAnimationAPI.TryGetActiveInteraction(player, (InteractionAnimationPresentationKind)1, ref val)) { return LCInteractionAnimationAPI.TryGetActiveInteraction(player, (InteractionAnimationPresentationKind)0, ref val); } return true; } return false; } private static bool IsAlive(IY4NGZFpWeapon weapon) { if (weapon != null) { return (Object)(object)weapon.FpGrabbable != (Object)null; } return false; } private static bool SameWeapon(IY4NGZFpWeapon a, IY4NGZFpWeapon b) { if (!IsAlive(a) || !IsAlive(b)) { return false; } return (Object)(object)a.FpGrabbable == (Object)(object)b.FpGrabbable; } internal static void PreloadPacks() { FpWeaponProfile activeProfile = _activeProfile; try { FpWeaponProfile[] fpProfiles = FpProfiles; string text = default(string); for (int i = 0; i < fpProfiles.Length; i++) { FpWeaponProfile fpWeaponProfile = (_activeProfile = fpProfiles[i]); if (EnsurePackRegistered() && !LCInteractionAnimationAPI.TryPreloadInteractionAssets(fpWeaponProfile.PackId, fpWeaponProfile.InteractionId, ref text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] preload failed (" + fpWeaponProfile.ConfigId + "): " + text)); } } } } finally { _activeProfile = activeProfile; } } internal static void OnWeaponFired(IY4NGZFpWeapon weapon, PlayerControllerB firedBy, bool magazineNowEmpty = false) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (IsEnabled() && IsAlive(weapon) && IsLocalPlayer(firedBy) && HasActiveInteractionFor(weapon, firedBy)) { LCInteractionAnimationAPI.TryFireInteractionTrigger(_activeHandle, _activeProfile.ArmsFireTrigger); string triggerName = ((magazineNowEmpty && !string.IsNullOrWhiteSpace(_activeProfile.PropFireEmptyTrigger)) ? _activeProfile.PropFireEmptyTrigger : _activeProfile.PropFireTrigger); FirePropTrigger(firedBy, triggerName); } } internal static void OnWeaponReloadStarted(IY4NGZFpWeapon weapon, PlayerControllerB reloadedBy, bool wasEmpty = false, int roundsDrawn = 1) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled() || !IsAlive(weapon) || !IsLocalPlayer(reloadedBy) || !HasActiveInteractionFor(weapon, reloadedBy)) { return; } int num; string text; if (wasEmpty) { num = ((!string.IsNullOrWhiteSpace(_activeProfile.ArmsReloadEmptyTrigger)) ? 1 : 0); if (num != 0) { text = _activeProfile.ArmsReloadEmptyTrigger; goto IL_0053; } } else { num = 0; } text = _activeProfile.ArmsReloadTrigger; goto IL_0053; IL_0053: string text2 = text; string triggerName = ((num != 0 && !string.IsNullOrWhiteSpace(_activeProfile.PropReloadEmptyTrigger)) ? _activeProfile.PropReloadEmptyTrigger : _activeProfile.PropReloadTrigger); if (num == 0 && !string.IsNullOrWhiteSpace(_activeProfile.ArmsReloadRoundsTriggerPrefix)) { int num2 = Mathf.Clamp(roundsDrawn, 1, 4); text2 = _activeProfile.ArmsReloadRoundsTriggerPrefix + num2; } if (num == 0 && !string.IsNullOrWhiteSpace(_activeProfile.PropReloadRoundsTriggerPrefix)) { int num3 = Mathf.Clamp(roundsDrawn, 1, 4); triggerName = _activeProfile.PropReloadRoundsTriggerPrefix + num3; } LCInteractionAnimationAPI.TryFireInteractionTrigger(_activeHandle, text2); FirePropTrigger(reloadedBy, triggerName); } internal static void SetContinuousFiring(IY4NGZFpWeapon weapon, PlayerControllerB firedBy, bool firing) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled() || !IsAlive(weapon) || !IsLocalPlayer(firedBy) || !HasActiveInteractionFor(weapon, firedBy)) { return; } if (!string.IsNullOrWhiteSpace(_activeProfile.ArmsFiringBool)) { LCInteractionAnimationAPI.TrySetInteractionBool(_activeHandle, _activeProfile.ArmsFiringBool, firing); } if (!string.IsNullOrWhiteSpace(_activeProfile.PropFiringBool)) { Animator val = ResolvePropAnimator(firedBy); if ((Object)(object)val != (Object)null) { val.SetBool(_activeProfile.PropFiringBool, firing); } } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] private static void PostPlayerUpdate(PlayerControllerB __instance) { if (IsLocalPlayer(__instance)) { TickLocalPlayer(__instance); } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] private static void PostPlayerLateUpdate(PlayerControllerB __instance) { try { if (IsLocalPlayer(__instance)) { TickLocalPlayerLateUpdate(__instance); } } catch (Exception ex) { if (!_leftHandGunAnchorTickFailureLogged) { _leftHandGunAnchorTickFailureLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] left-hand gun anchor tick failed: " + ex.Message)); } } } } [HarmonyPatch(typeof(GrabbableObject), "EquipItem")] [HarmonyPostfix] private static void EquipItem_Postfix(GrabbableObject __instance) { try { if (TryGetWeapon(__instance, out var weapon)) { PlayerControllerB playerHeldBy = __instance.playerHeldBy; if (IsLocalPlayer(playerHeldBy) && !WeaponThirdPersonAnimation.ShouldUseLocalThirdPerson(playerHeldBy, weapon.FpConfigId)) { TryStartInteraction(weapon, playerHeldBy); } } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons.FP] EquipItem postfix threw: {arg}"); } } } [HarmonyPatch(typeof(GrabbableObject), "PocketItem")] [HarmonyPostfix] private static void PocketItem_Postfix(GrabbableObject __instance) { try { if (TryGetWeapon(__instance, out var weapon) && (IsLocalPlayer(__instance.playerHeldBy) || SameWeapon(weapon, _activeWeapon))) { BeginInteractionExit(weapon); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons.FP] PocketItem postfix threw: {arg}"); } } } [HarmonyPatch(typeof(GrabbableObject), "DiscardItem")] [HarmonyPostfix] private static void DiscardItem_Postfix(GrabbableObject __instance) { try { if (TryGetWeapon(__instance, out var weapon) && (IsLocalPlayer(__instance.playerHeldBy) || SameWeapon(weapon, _activeWeapon))) { BeginInteractionExit(weapon); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons.FP] DiscardItem postfix threw: {arg}"); } } } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] [HarmonyPostfix] private static void PostDisconnect() { StopInteractionImmediate((InteractionAnimationStopReason)0); FpWeaponProfile[] fpProfiles = FpProfiles; for (int i = 0; i < fpProfiles.Length; i++) { fpProfiles[i].PackRegistered = false; } } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static void PostEndOfGame() { StopInteractionImmediate((InteractionAnimationStopReason)0); } private static void TickLocalPlayer(PlayerControllerB player) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) IY4NGZFpWeapon weapon = null; GrabbableObject val = (((Object)(object)player != (Object)null) ? player.currentlyHeldObjectServer : null); if ((Object)(object)val != (Object)null) { TryGetWeapon(val, out weapon); } if (IsAlive(weapon) && WeaponThirdPersonAnimation.ShouldUseLocalThirdPerson(player, weapon.FpConfigId)) { if (((InteractionAnimationHandle)(ref _activeHandle)).IsValid) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogMessage((object)("[Y4NGZWeapons.FP] yielding " + weapon.FpConfigId + " body ownership to local third-person presentation.")); } StopInteractionImmediate((InteractionAnimationStopReason)2); } return; } if (!((InteractionAnimationHandle)(ref _activeHandle)).IsValid) { if (IsAlive(weapon) && ShouldSelfHealFirstPersonSession(weapon.FpConfigId) && (Object)(object)val != (Object)null && !val.isPocketed && !player.isClimbingLadder && !player.inSpecialInteractAnimation && !UpgradesBridge.IsDebugThirdPersonCamActive()) { TryStartInteraction(weapon, player); } return; } if (!LCInteractionAnimationAPI.IsInteractionActive(_activeHandle)) { ClearInteractionState(); return; } if (!IsEnabled() || (Object)(object)player == (Object)null || player.isPlayerDead) { StopInteractionImmediate((InteractionAnimationStopReason)0); return; } if (!IsAlive(_activeWeapon)) { StopInteractionImmediate((InteractionAnimationStopReason)0); return; } if (!_exitRequested) { GrabbableObject fpGrabbable = _activeWeapon.FpGrabbable; if ((Object)(object)fpGrabbable == (Object)null || (Object)(object)fpGrabbable.playerHeldBy != (Object)(object)player || fpGrabbable.isPocketed || (Object)(object)player.currentlyHeldObjectServer != (Object)(object)fpGrabbable) { BeginInteractionExit(_activeWeapon); return; } } Transform val2 = ResolvePropRoot(player); if ((Object)(object)val2 != (Object)null) { ApplyPropTuning(val2); UpdateMuzzleParticlePose(val2); } if (!_exitRequested) { TickGloveBisect(player); HideHeldVisuals(_activeWeapon); } } private static bool ShouldSelfHealFirstPersonSession(string configId) { if (!string.Equals(configId, "heavy_shotgun", StringComparison.Ordinal) && !string.Equals(configId, "kar98k", StringComparison.Ordinal) && !string.Equals(configId, "x18", StringComparison.Ordinal) && !string.Equals(configId, "mx16a4", StringComparison.Ordinal) && !string.Equals(configId, "revolver", StringComparison.Ordinal) && !string.Equals(configId, "flame_thrower", StringComparison.Ordinal)) { return string.Equals(configId, "grenade_launcher", StringComparison.Ordinal); } return true; } private static void TickLocalPlayerLateUpdate(PlayerControllerB player) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled() || !((InteractionAnimationHandle)(ref _activeHandle)).IsValid || !LCInteractionAnimationAPI.IsInteractionActive(_activeHandle) || (Object)(object)player == (Object)null || player.isPlayerDead) { return; } Transform val = ResolvePropRoot(player); if (!((Object)(object)val == (Object)null)) { if (IsLeftHandGunAnchorEnabled() && !string.IsNullOrEmpty(_activeProfile.LeftHandAnchorChildName)) { ApplyLeftHandGunAnchor(player, val); } ApplyStaticFingerPoses(player, val); } } private static Quaternion LiveCurlDelta(in FingerBinding binding) { //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) //IL_0015: 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_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) Vector3 curlAxis = binding.CurlAxis; if (((Vector3)(ref curlAxis)).sqrMagnitude < 0.5f) { return Quaternion.identity; } float num = ((!binding.IsThumb) ? ((!binding.IsTip) ? (binding.IsLeft ? FingerCurlDeltaLeftLive : FingerCurlDeltaRightLive) : (binding.IsLeft ? FingerTipCurlDeltaLeftLive : FingerTipCurlDeltaRightLive)) : (binding.IsLeft ? ThumbCurlDeltaLeftLive : ThumbCurlDeltaRightLive)); if (num != 0f) { return Quaternion.AngleAxis(num, binding.CurlAxis); } return Quaternion.identity; } private static Quaternion ResolveEnforcedRotation(in FingerBinding binding) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_0013: 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) if (!_activeProfile.FingerPosesAdditive) { return binding.LocalRotation * LiveCurlDelta(in binding); } return binding.Bone.localRotation * LiveCurlDelta(in binding); } private static void OnBeforeRenderEnforceFingerPoses() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!((InteractionAnimationHandle)(ref _activeHandle)).IsValid || !LCInteractionAnimationAPI.IsInteractionActive(_activeHandle) || _fingerPoseBindings.Count == 0) { return; } if (!_onBeforeRenderFireLogged) { _onBeforeRenderFireLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZWeapons.FP] onBeforeRender finger enforcement IS firing (bindings={_fingerPoseBindings.Count})."); } } for (int i = 0; i < _fingerPoseBindings.Count && i < _fingerPoseFinal.Count; i++) { FingerBinding fingerBinding = _fingerPoseBindings[i]; if ((Object)(object)fingerBinding.Bone != (Object)null) { fingerBinding.Bone.localRotation = _fingerPoseFinal[i]; } } } private static void ApplyStaticFingerPoses(PlayerControllerB player, Transform propRoot) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) if (!TryEnsureLeftHandGunAnchorCache(player, propRoot)) { return; } EnsureFingerPosesLoaded(); if (_activeProfile.FingerPoses == null || _activeProfile.FingerPoses.Length == 0) { return; } if ((Object)(object)_fingerPoseCachedLeftHand != (Object)(object)_leftHandBone || (Object)(object)_fingerPoseCachedRightHand != (Object)(object)_rightHandBone) { RebuildFingerPoseBindings(player); LogFingerSkinningDiagnostics(player); } if (!_onBeforeRenderHooked) { _onBeforeRenderHooked = true; object obj = <>O.<0>__OnBeforeRenderEnforceFingerPoses; if (obj == null) { UnityAction val = OnBeforeRenderEnforceFingerPoses; <>O.<0>__OnBeforeRenderEnforceFingerPoses = val; obj = (object)val; } Application.onBeforeRender += (UnityAction)obj; } int num; if (FingerCurlDiagnostics) { num = ((Time.time >= _nextFingerDiagTime) ? 1 : 0); if (num != 0) { _nextFingerDiagTime = Time.time + 2f; } } else { num = 0; } if (num != 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.FP] finger-curl-live: " + $"L curl={FingerCurlDeltaLeftLive:0.#} tip={FingerTipCurlDeltaLeftLive:0.#} thumb={ThumbCurlDeltaLeftLive:0.#} | " + $"R curl={FingerCurlDeltaRightLive:0.#} tip={FingerTipCurlDeltaRightLive:0.#} thumb={ThumbCurlDeltaRightLive:0.#}")); } } while (_fingerPoseFinal.Count < _fingerPoseBindings.Count) { _fingerPoseFinal.Add(Quaternion.identity); } for (int i = 0; i < _fingerPoseBindings.Count; i++) { FingerBinding binding = _fingerPoseBindings[i]; if (!((Object)(object)binding.Bone == (Object)null)) { Quaternion val2 = ResolveEnforcedRotation(in binding); _fingerPoseFinal[i] = val2; binding.Bone.localRotation = val2; } } } private static void EnsureFingerPosesLoaded() { FpWeaponProfile activeProfile = _activeProfile; if (activeProfile.FingerPosesLoadAttempted) { return; } activeProfile.FingerPosesLoadAttempted = true; try { string text = Path.Combine(GetConsumerAssetRoot(), activeProfile.FingerPosesFileName); if (!File.Exists(text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] finger poses file not found (grip enforcement disabled): " + text)); } return; } StaticFingerPoseFile staticFingerPoseFile = JsonUtility.FromJson(File.ReadAllText(text)); activeProfile.FingerPoses = staticFingerPoseFile?.poses; activeProfile.FingerPosesAdditive = string.Equals(staticFingerPoseFile?.mode, "additive", StringComparison.OrdinalIgnoreCase); ManualLogSource log2 = Plugin.Log; if (log2 != null) { string configId = activeProfile.ConfigId; StaticFingerPose[] fingerPoses = activeProfile.FingerPoses; log2.LogInfo((object)string.Format("[Y4NGZWeapons.FP] finger poses loaded ({0}): {1} mode={2}", configId, (fingerPoses != null) ? fingerPoses.Length : 0, activeProfile.FingerPosesAdditive ? "additive" : "absolute")); } } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZWeapons.FP] finger poses load failed: " + ex.Message)); } activeProfile.FingerPoses = null; } } private static void RebuildFingerPoseBindings(PlayerControllerB player) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) _fingerPoseBindings.Clear(); _fingerPoseFinal.Clear(); _fingerPoseCachedLeftHand = _leftHandBone; _fingerPoseCachedRightHand = _rightHandBone; Transform[] array = (((Object)(object)player != (Object)null && (Object)(object)player.thisPlayerModelArms != (Object)null) ? player.thisPlayerModelArms.bones : Array.Empty()); StaticFingerPose[] fingerPoses = _activeProfile.FingerPoses; foreach (StaticFingerPose staticFingerPose in fingerPoses) { if (staticFingerPose == null || string.IsNullOrEmpty(staticFingerPose.relativePath)) { continue; } int num = staticFingerPose.relativePath.LastIndexOf('/'); string text = ((num >= 0) ? staticFingerPose.relativePath.Substring(num + 1) : staticFingerPose.relativePath); Transform[] array2 = array; foreach (Transform val in array2) { if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, text, StringComparison.Ordinal)) { _fingerPoseBindings.Add(new FingerBinding { Bone = val, LocalRotation = staticFingerPose.localRotation, CurlAxis = staticFingerPose.curlAxis, IsLeft = string.Equals(staticFingerPose.hand, "hand.L", StringComparison.Ordinal), IsTip = text.EndsWith(".001", StringComparison.Ordinal), IsThumb = staticFingerPose.relativePath.StartsWith("finger1", StringComparison.Ordinal) }); } } } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZWeapons.FP] finger pose bindings resolved: {_fingerPoseBindings.Count} transforms " + $"from {_activeProfile.FingerPoses.Length} poses (local FP renderer bones only).")); } } private static void LogFingerSkinningDiagnostics(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return; } try { SkinnedMeshRenderer[] componentsInChildren = ((Component)player).gameObject.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val in componentsInChildren) { Transform[] bones = val.bones; if (bones == null) { continue; } foreach (Transform val2 in bones) { if (!((Object)(object)val2 == (Object)null) && string.Equals(((Object)val2).name, "finger2.R", StringComparison.Ordinal)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.FP] finger-skin-diag: smr=" + BuildPathUnder(((Component)player).transform, ((Component)val).transform) + " enabled=" + ((Renderer)val).enabled + " boneInstance=" + ((Object)val2).GetInstanceID() + " bonePath=" + BuildPathUnder(((Component)player).transform, val2))); } } } } foreach (FingerBinding fingerPoseBinding in _fingerPoseBindings) { if ((Object)(object)fingerPoseBinding.Bone != (Object)null && string.Equals(((Object)fingerPoseBinding.Bone).name, "finger2.R", StringComparison.Ordinal)) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Y4NGZWeapons.FP] finger-skin-diag: ENFORCING instance=" + ((Object)fingerPoseBinding.Bone).GetInstanceID() + " path=" + BuildPathUnder(((Component)player).transform, fingerPoseBinding.Bone))); } } } } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZWeapons.FP] finger-skin-diag failed: " + ex.Message)); } } } private static string BuildPathUnder(Transform root, Transform node) { if ((Object)(object)node == (Object)null) { return "(null)"; } List list = new List(); Transform val = node; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static void TickGloveBisect(PlayerControllerB player) { Keyboard current = Keyboard.current; if (current == null || !((ButtonControl)current[(Key)70]).wasPressedThisFrame) { return; } if (!_gloveBisectCandidatesLogged) { _gloveBisectCandidatesLogged = true; LogGloveBisectCandidates(player); } RestoreGloveBisect(logRestore: false); _gloveBisectStep = (_gloveBisectStep + 1) % 4; switch (_gloveBisectStep) { case 1: DisableForBisect((Renderer)(object)player.thisPlayerModel); DisableForBisect((Renderer)(object)player.thisPlayerModelLOD1); DisableForBisect((Renderer)(object)player.thisPlayerModelLOD2); break; case 2: { Transform[] componentsInChildren = ((Component)player).gameObject.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((Object)val).name.IndexOf("scavEmoteSkeleton", StringComparison.OrdinalIgnoreCase) >= 0) { Renderer[] componentsInChildren2 = ((Component)val).GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren2.Length; j++) { DisableForBisect(componentsInChildren2[j]); } } } break; } case 3: DisableForBisect((Renderer)(object)player.thisPlayerModelArms); break; } string arg = _gloveBisectStep switch { 1 => "vanilla body LOD1+LOD2", 2 => "emote-clone (scavEmoteSkeleton) renderers", 3 => "FP arms (thisPlayerModelArms / Circle)", _ => "nothing (all restored — baseline)", }; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZWeapons.FP] glove-bisect step {_gloveBisectStep}: disabled {arg} " + $"({_gloveBisectDisabled.Count} renderer(s)). Screenshot now, then press Insert for the next step.")); } } private static void DisableForBisect(Renderer renderer) { if (!((Object)(object)renderer == (Object)null) && renderer.enabled) { renderer.enabled = false; _gloveBisectDisabled.Add(renderer); } } private static void RestoreGloveBisect(bool logRestore = true) { foreach (Renderer item in _gloveBisectDisabled) { if ((Object)(object)item != (Object)null) { item.enabled = true; } } if (logRestore && _gloveBisectDisabled.Count > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZWeapons.FP] glove-bisect: restored {_gloveBisectDisabled.Count} renderer(s)."); } } _gloveBisectDisabled.Clear(); if (logRestore) { _gloveBisectStep = 0; } } private static void LogGloveBisectCandidates(PlayerControllerB player) { try { Dump("bodyLOD0", (Renderer)(object)player.thisPlayerModel); Dump("bodyLOD1", (Renderer)(object)player.thisPlayerModelLOD1); Dump("bodyLOD2", (Renderer)(object)player.thisPlayerModelLOD2); Dump("fpArms", (Renderer)(object)player.thisPlayerModelArms); Transform[] componentsInChildren = ((Component)player).gameObject.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((Object)val).name.IndexOf("scavEmoteSkeleton", StringComparison.OrdinalIgnoreCase) >= 0) { Renderer[] componentsInChildren2 = ((Component)val).GetComponentsInChildren(true); foreach (Renderer r in componentsInChildren2) { Dump("emoteClone", r); } break; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] glove-candidates dump failed: " + ex.Message)); } } void Dump(string label, Renderer val2) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)val2 == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Y4NGZWeapons.FP] glove-candidates: " + label + "=(null)")); } } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[Y4NGZWeapons.FP] glove-candidates: " + label + " path=" + BuildPathUnder(((Component)player).transform, ((Component)val2).transform) + " " + $"enabled={val2.enabled} shadows={val2.shadowCastingMode}")); } } } } private static bool HasActiveInteractionFor(IY4NGZFpWeapon weapon, PlayerControllerB player) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!((InteractionAnimationHandle)(ref _activeHandle)).IsValid) { return false; } if (!LCInteractionAnimationAPI.IsInteractionActive(_activeHandle)) { ClearInteractionState(); return false; } if (!_exitRequested && SameWeapon(_activeWeapon, weapon)) { return IsLocalPlayer(player); } return false; } private static void TryStartInteraction(IY4NGZFpWeapon weapon, PlayerControllerB player) { //IL_002d: 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_0079: Unknown result type (might be due to invalid IL or missing references) //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_00a9: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled() || !IsAlive(weapon) || (Object)(object)player == (Object)null || player.isPlayerDead) { return; } if (((InteractionAnimationHandle)(ref _activeHandle)).IsValid) { if (LCInteractionAnimationAPI.IsInteractionActive(_activeHandle)) { if (!_exitRequested && SameWeapon(_activeWeapon, weapon)) { HideHeldVisuals(weapon); return; } StopInteractionImmediate((InteractionAnimationStopReason)2); } else { ClearInteractionState(); } } _activeProfile = ProfileFor(weapon); if (!EnsurePackRegistered()) { return; } InteractionAnimationHandle activeHandle = default(InteractionAnimationHandle); string text = default(string); if (!LCInteractionAnimationAPI.TryStartInteraction(new InteractionAnimationRequest { Player = player, PackId = _activeProfile.PackId, InteractionId = _activeProfile.InteractionId }, ref activeHandle, ref text)) { if (!_startFailureLogged) { _startFailureLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] start rejected: " + text)); } } } else { Plugin.ReloadWeaponFpPropConfig(); _activeHandle = activeHandle; _activeWeapon = weapon; RestoreMuzzleParticleTransform(); ResetPropAttachState(); ResetLeftHandGunAnchorState(); _startFailureLogged = false; HideHeldVisuals(weapon); TryPlayEquipDraw(player); } } private static void TryPlayEquipDraw(PlayerControllerB player) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) FpWeaponProfile activeProfile = _activeProfile; if (activeProfile == null || activeProfile.EquipDrawChance <= 0f || string.IsNullOrWhiteSpace(activeProfile.ArmsDrawTrigger)) { return; } bool flag = Random.value < Mathf.Clamp01(activeProfile.EquipDrawChance); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.FP] equip draw roll (" + activeProfile.ConfigId + "): " + string.Format("{0} chance={1:0.##}", flag ? "DRAW" : "hold", activeProfile.EquipDrawChance))); } if (flag) { LCInteractionAnimationAPI.TryFireInteractionTrigger(_activeHandle, activeProfile.ArmsDrawTrigger); if (!string.IsNullOrWhiteSpace(activeProfile.PropDrawTrigger)) { FirePropTrigger(player, activeProfile.PropDrawTrigger); } } } private static void BeginInteractionExit(IY4NGZFpWeapon weapon) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) if (!SameWeapon(weapon, _activeWeapon) || !((InteractionAnimationHandle)(ref _activeHandle)).IsValid || _exitRequested) { return; } string text = default(string); if (!LCInteractionAnimationAPI.IsInteractionActive(_activeHandle)) { ClearInteractionState(); } else if (!LCInteractionAnimationAPI.TryBeginInteractionExit(_activeHandle, ref text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] graceful exit rejected: " + text)); } LCInteractionAnimationAPI.TryStopInteraction(_activeHandle, (InteractionAnimationStopReason)0); ClearInteractionState(); } else { _exitRequested = true; } } internal static void StopForHeldItemStow(PlayerControllerB player) { if (((InteractionAnimationHandle)(ref _activeHandle)).IsValid && IsLocalPlayer(player)) { StopInteractionImmediate((InteractionAnimationStopReason)2); } } private static void StopInteractionImmediate(InteractionAnimationStopReason reason) { //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) if (((InteractionAnimationHandle)(ref _activeHandle)).IsValid) { LCInteractionAnimationAPI.TryStopInteraction(_activeHandle, reason); } ClearInteractionState(); } private static void ClearInteractionState() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) RestoreGloveBisect(); RestoreHeldVisuals(); RestoreMuzzleParticleTransform(); _activeHandle = InteractionAnimationHandle.Empty; _activeWeapon = null; ResetPropAttachState(); ResetLeftHandGunAnchorState(); _exitRequested = false; } private static bool EnsurePackRegistered() { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown FpWeaponProfile activeProfile = _activeProfile; if (activeProfile.PackRegistered) { return true; } if (activeProfile.ManifestMissingPermanent) { return false; } string consumerAssetRoot = GetConsumerAssetRoot(); string text = Path.Combine(consumerAssetRoot, activeProfile.ManifestFileName); if (!File.Exists(text)) { activeProfile.ManifestMissingPermanent = true; if (!activeProfile.MissingManifestLogged) { activeProfile.MissingManifestLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] manifest not found: " + text)); } } return false; } string manifestJson; try { manifestJson = File.ReadAllText(text); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons.FP] manifest read failed: " + ex.Message)); } return false; } InteractionAnimationPackDefinition val = new InteractionAnimationPackDefinition(); val.PackId = activeProfile.PackId; val.Version = "0.1.0"; val.AssetRootPath = consumerAssetRoot; val.Interactions = (InteractionAnimationDefinition[])(object)new InteractionAnimationDefinition[1] { new InteractionAnimationDefinition { InteractionId = activeProfile.InteractionId, PresentationKind = (InteractionAnimationPresentationKind)1, ManifestJson = manifestJson } }; string text2 = default(string); if (!LCInteractionAnimationAPI.TryRegisterInteractionPack(val, ref text2)) { if (string.Equals(text2, "pack_already_registered", StringComparison.OrdinalIgnoreCase)) { activeProfile.PackRegistered = true; return true; } if (!activeProfile.RegistrationFailureLogged) { activeProfile.RegistrationFailureLogged = true; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZWeapons.FP] pack registration failed: " + text2)); } } return false; } activeProfile.PackRegistered = true; activeProfile.RegistrationFailureLogged = false; ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)("[Y4NGZWeapons.FP] registered " + activeProfile.PackDisplayName + " animation pack.")); } return true; } private static string GetConsumerAssetRoot() { return Path.GetDirectoryName(typeof(Plugin).Assembly.Location) ?? string.Empty; } private static void FirePropTrigger(PlayerControllerB player, string triggerName) { Animator val = ResolvePropAnimator(player); if (!((Object)(object)val == (Object)null)) { val.SetTrigger(triggerName); } } private static Animator ResolvePropAnimator(PlayerControllerB player) { Transform val = ResolvePropRoot(player); if ((Object)(object)val == (Object)null) { return null; } if ((Object)(object)_propAnimator == (Object)null) { _propAnimator = ((Component)val).GetComponentInChildren(true); } return _propAnimator; } public static string GetPropTuningSummary() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) GetEffectivePropTuning(out var posDelta, out var rotDelta, out var scaleMult); return "pos=" + WeaponFirstPersonAnimationLogFormat.Vector(posDelta) + " rot=" + WeaponFirstPersonAnimationLogFormat.Vector(rotDelta) + " scale=" + WeaponFirstPersonAnimationLogFormat.Float(scaleMult); } public static void PersistLiveTuningToConfig() { //IL_000c: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (Plugin.WeaponsFpPropPosDelta != null) { Plugin.WeaponsFpPropPosDelta.Value = WeaponFirstPersonAnimationLogFormat.VectorCsv(PropPosDeltaLive); } if (Plugin.WeaponsFpPropRotDelta != null) { Plugin.WeaponsFpPropRotDelta.Value = WeaponFirstPersonAnimationLogFormat.VectorCsv(PropRotDeltaLive); } if (Plugin.WeaponsFpPropScaleMult != null) { Plugin.WeaponsFpPropScaleMult.Value = PropScaleMultLive; } Plugin.ReloadWeaponFpPropConfig(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.FP] persisted live prop tuning: pos=" + WeaponFirstPersonAnimationLogFormat.Vector(PropPosDeltaLive) + " rot=" + WeaponFirstPersonAnimationLogFormat.Vector(PropRotDeltaLive) + " scale=" + WeaponFirstPersonAnimationLogFormat.Float(PropScaleMultLive))); } } private static void GetEffectivePropTuning(out Vector3 posDelta, out Vector3 rotDelta, out float scaleMult) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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) //IL_0008: 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_0013: 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) if (PropTuningLiveOverride) { posDelta = PropPosDeltaLive; rotDelta = PropRotDeltaLive; scaleMult = PropScaleMultLive; } else { posDelta = Plugin.WeaponsFpPropPosDeltaValue; rotDelta = Plugin.WeaponsFpPropRotDeltaValue; scaleMult = Plugin.WeaponsFpPropScaleMultValue; } } private static void ApplyPropTuning(Transform propRoot) { //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_001c: 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_002c: 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) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)propRoot == (Object)null)) { GetEffectivePropTuning(out var posDelta, out var rotDelta, out var scaleMult); propRoot.localPosition = _propBaseLocalPosition + posDelta; propRoot.localRotation = _propBaseLocalRotation * Quaternion.Euler(rotDelta); propRoot.localScale = _propBaseLocalScale * scaleMult; } } private static Transform ResolvePropRoot(PlayerControllerB player) { if ((Object)(object)_propRoot != (Object)null) { return _propRoot; } Transform val = FindChildByNameSubstring(((Object)(object)player != (Object)null) ? player.localArmsTransform : null, _activeProfile.PropNameSubstring); if ((Object)(object)val == (Object)null && (Object)(object)player != (Object)null) { val = FindChildByNameSubstring(((Component)player).transform, _activeProfile.PropNameSubstring); } if ((Object)(object)val == (Object)null) { return null; } _propRoot = val; _propAnimator = ((Component)val).GetComponentInChildren(true); InitializeResolvedProp(val); return _propRoot; } private static void InitializeResolvedProp(Transform propRoot) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)propRoot == (Object)null) { return; } _propBaseLocalPosition = propRoot.localPosition; _propBaseLocalRotation = propRoot.localRotation; _propBaseLocalScale = propRoot.localScale; _hasPropMuzzleLocal = TryComputeMuzzleLocal(propRoot, out _propMuzzleLocal); if (!_hasPropMuzzleLocal) { _propMuzzleLocal = Vector3.zero; } _propRootIsLandmarkFrame = PropRootMatchesLandmarkFrame(propRoot, out var measuredSize, out var expectedSize); ApplyPropTuning(propRoot); GetEffectivePropTuning(out var posDelta, out var rotDelta, out var scaleMult); Material[] array = ((_activeProfile.PropMaterials != null) ? _activeProfile.PropMaterials() : null); if (array != null && array.Length != 0) { ApplyMaterialsToPropRenderers(propRoot, array); } else { Material val = ((_activeProfile.PropMaterial != null) ? _activeProfile.PropMaterial() : null); if ((Object)(object)val != (Object)null) { ApplyMaterialToPropRenderers(propRoot, val); } } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.FP] prop tuned: posDelta=" + WeaponFirstPersonAnimationLogFormat.Vector(posDelta) + " rotDelta=" + WeaponFirstPersonAnimationLogFormat.Vector(rotDelta) + " scaleMult=" + WeaponFirstPersonAnimationLogFormat.Float(scaleMult) + " muzzleLocal=" + WeaponFirstPersonAnimationLogFormat.Vector(_propMuzzleLocal) + " " + $"landmarkFrame={_propRootIsLandmarkFrame} " + "measuredSize=" + WeaponFirstPersonAnimationLogFormat.Vector(measuredSize) + " expectedSize=" + WeaponFirstPersonAnimationLogFormat.Vector(expectedSize) + " sizeResidualMm=" + FormatMillimetres(measuredSize - expectedSize) + " frameToleranceMm=" + 5f.ToString("0.##", CultureInfo.InvariantCulture))); } } private static string FormatMillimetres(Vector3 metres) { //IL_0000: 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) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = metres * 1000f; return "(" + val.x.ToString("0.##", CultureInfo.InvariantCulture) + "," + val.y.ToString("0.##", CultureInfo.InvariantCulture) + "," + val.z.ToString("0.##", CultureInfo.InvariantCulture) + ")"; } private static bool PropRootMatchesLandmarkFrame(Transform propRoot, out Vector3 measuredSize, out Vector3 expectedSize) { //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) //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_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) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) measuredSize = Vector3.zero; expectedSize = Vector3.zero; WeaponLandmarks weaponLandmarks = ActiveLandmarks(); if (weaponLandmarks == null || (Object)(object)propRoot == (Object)null) { return false; } expectedSize = ((Bounds)(ref weaponLandmarks.ModelBounds)).size; if (!TryComputePropLocalBounds(propRoot, out var bounds)) { return false; } measuredSize = ((Bounds)(ref bounds)).size; if (Mathf.Abs(measuredSize.x - expectedSize.x) <= 0.005f && Mathf.Abs(measuredSize.y - expectedSize.y) <= 0.005f) { return Mathf.Abs(measuredSize.z - expectedSize.z) <= 0.005f; } return false; } private static WeaponLandmarks ActiveLandmarks() { if (!IsAlive(_activeWeapon)) { return null; } return WeaponLandmarkCatalog.ById(_activeWeapon.FpConfigId); } internal static bool TryGetFirstPersonBore(IY4NGZFpWeapon weapon, PlayerControllerB heldBy, WeaponLandmarks landmarks, out Vector3 origin, out Vector3 direction, out Transform host) { //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) //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_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_0067: 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_0072: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00b6: Unknown result type (might be due to invalid IL or missing references) origin = Vector3.zero; direction = Vector3.forward; host = null; if (landmarks == null || !IsEnabled() || !IsAlive(weapon) || !IsLocalPlayer(heldBy)) { return false; } if (!HasActiveInteractionFor(weapon, heldBy)) { return false; } Transform propRoot = _propRoot; if ((Object)(object)propRoot == (Object)null || !_propRootIsLandmarkFrame) { return false; } origin = propRoot.TransformPoint(landmarks.MuzzlePosition); Vector3 muzzleForward = landmarks.MuzzleForward; Vector3 val = ((((Vector3)(ref muzzleForward)).sqrMagnitude < 1E-08f) ? propRoot.forward : propRoot.TransformDirection(((Vector3)(ref muzzleForward)).normalized)); direction = ((((Vector3)(ref val)).sqrMagnitude < 1E-08f) ? propRoot.forward : ((Vector3)(ref val)).normalized); host = propRoot; return true; } private static void ApplyMaterialToPropRenderers(Transform propRoot, Material material) { if (!((Object)(object)propRoot == (Object)null) && !((Object)(object)material == (Object)null)) { MeshRenderer[] componentsInChildren = ((Component)propRoot).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { AssignSharedMaterial((Renderer)(object)componentsInChildren[i], material); } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)propRoot).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { AssignSharedMaterial((Renderer)(object)componentsInChildren2[i], material); } } } private static void ApplyMaterialsToPropRenderers(Transform propRoot, Material[] materials) { if ((Object)(object)propRoot == (Object)null || materials == null || materials.Length == 0) { return; } Renderer[] componentsInChildren = ((Component)propRoot).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer))) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { val.sharedMaterial = materials[0]; continue; } int num = Mathf.Min(sharedMaterials.Length, materials.Length); for (int j = 0; j < num; j++) { if ((Object)(object)materials[j] != (Object)null) { sharedMaterials[j] = materials[j]; } } val.sharedMaterials = sharedMaterials; } } private static void AssignSharedMaterial(Renderer renderer, Material material) { if ((Object)(object)renderer == (Object)null || (Object)(object)material == (Object)null) { return; } Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials != null && sharedMaterials.Length != 0) { for (int i = 0; i < sharedMaterials.Length; i++) { sharedMaterials[i] = material; } renderer.sharedMaterials = sharedMaterials; } else { renderer.sharedMaterial = material; } } private static bool TryComputeMuzzleLocal(Transform propRoot, out Vector3 muzzleLocal) { //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) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_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) muzzleLocal = Vector3.zero; if (!TryComputePropLocalBounds(propRoot, out var bounds)) { return false; } muzzleLocal = new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y, ((Bounds)(ref bounds)).max.z); return true; } private static bool TryComputePropLocalBounds(Transform propRoot, out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) bounds = default(Bounds); if ((Object)(object)propRoot == (Object)null) { return false; } bool hasBounds = false; MeshRenderer[] componentsInChildren = ((Component)propRoot).GetComponentsInChildren(true); foreach (MeshRenderer renderer in componentsInChildren) { EncapsulateRendererBounds(propRoot, (Renderer)(object)renderer, ref bounds, ref hasBounds); } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)propRoot).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer renderer2 in componentsInChildren2) { EncapsulateRendererBounds(propRoot, (Renderer)(object)renderer2, ref bounds, ref hasBounds); } return hasBounds; } private static void EncapsulateRendererBounds(Transform propRoot, Renderer renderer, ref Bounds bounds, ref bool hasBounds) { //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_0028: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0059: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_00af: 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) //IL_009a: 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_00a4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)propRoot == (Object)null || (Object)(object)renderer == (Object)null || !TryGetRendererLocalBounds(renderer, out var bounds2)) { return; } Vector3 min = ((Bounds)(ref bounds2)).min; Vector3 max = ((Bounds)(ref bounds2)).max; Vector3 val = default(Vector3); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { ((Vector3)(ref val))..ctor((i == 0) ? min.x : max.x, (j == 0) ? min.y : max.y, (k == 0) ? min.z : max.z); Vector3 val2 = propRoot.InverseTransformPoint(((Component)renderer).transform.TransformPoint(val)); if (!hasBounds) { bounds = new Bounds(val2, Vector3.zero); hasBounds = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2); } } } } } private static bool TryGetRendererLocalBounds(Renderer renderer, out Bounds bounds) { //IL_0001: 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_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) bounds = default(Bounds); if ((Object)(object)renderer == (Object)null) { return false; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if ((Object)(object)val != (Object)null && (Object)(object)val.sharedMesh != (Object)null) { bounds = val.sharedMesh.bounds; return true; } MeshFilter component = ((Component)renderer).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { bounds = component.sharedMesh.bounds; return true; } return false; } private static void UpdateMuzzleParticlePose(Transform propRoot) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)propRoot == (Object)null || !_hasPropMuzzleLocal || !IsAlive(_activeWeapon)) { return; } ShotgunItem fpLegacyShotgun = _activeWeapon.FpLegacyShotgun; ParticleSystem val = (((Object)(object)fpLegacyShotgun != (Object)null) ? fpLegacyShotgun.gunShootParticle : null); Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : null); if ((Object)(object)val2 == (Object)null) { return; } if (!_muzzleParticleOriginalCaptured || (Object)(object)_muzzleParticleTransform != (Object)(object)val2) { if (_muzzleParticleOriginalCaptured) { RestoreMuzzleParticleTransform(); } _muzzleParticleTransform = val2; _muzzleParticleOriginalLocalPosition = val2.localPosition; _muzzleParticleOriginalLocalRotation = val2.localRotation; _muzzleParticleOriginalCaptured = true; } val2.position = propRoot.TransformPoint(_propMuzzleLocal); val2.rotation = propRoot.rotation; } private static void RestoreMuzzleParticleTransform() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0028: Unknown result type (might be due to invalid IL or missing references) if (_muzzleParticleOriginalCaptured && (Object)(object)_muzzleParticleTransform != (Object)null) { _muzzleParticleTransform.localPosition = _muzzleParticleOriginalLocalPosition; _muzzleParticleTransform.localRotation = _muzzleParticleOriginalLocalRotation; } _muzzleParticleTransform = null; _muzzleParticleOriginalLocalPosition = Vector3.zero; _muzzleParticleOriginalLocalRotation = Quaternion.identity; _muzzleParticleOriginalCaptured = false; } private static void ResetPropAttachState() { //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_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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) _propAnimator = null; _propRoot = null; _propBaseLocalPosition = Vector3.zero; _propBaseLocalRotation = Quaternion.identity; _propBaseLocalScale = Vector3.one; _propMuzzleLocal = Vector3.zero; _hasPropMuzzleLocal = false; _propRootIsLandmarkFrame = false; } private static void ApplyLeftHandGunAnchor(PlayerControllerB player, Transform propRoot) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0037: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_006f: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_008c: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //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) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)propRoot == (Object)null || !TryEnsureLeftHandGunAnchorCache(player, propRoot)) { return; } Vector3 position = _leftArmIkTarget.position; Quaternion rotation = _leftArmIkTarget.rotation; Vector3 val = _rightArmIkTarget.position + _rightArmIkTarget.rotation * _propBaseLocalPosition; Quaternion val2 = Quaternion.Inverse(_rightArmIkTarget.rotation * _propBaseLocalRotation); Vector3 val3 = val2 * (position - val); Quaternion val4 = val2 * rotation; Vector3 val5 = propRoot.position + propRoot.rotation * val3; Quaternion rotation2 = propRoot.rotation * val4; if ((Object)(object)_pumpTransform != (Object)null) { Vector3 val6 = _pumpTransform.position - val5; float magnitude = ((Vector3)(ref val6)).magnitude; if (magnitude > 0.0001f) { val5 += val6 / magnitude * Mathf.Min(0f, magnitude); } } Vector3 position2 = _leftArmUpperBone.position; float num = (Vector3.Distance(_leftArmUpperBone.position, _leftArmLowerBone.position) + Vector3.Distance(_leftArmLowerBone.position, _leftHandBone.position)) * 0.97f; Vector3 val7 = val5 - position2; if (num > 0.0001f && ((Vector3)(ref val7)).magnitude > num) { val5 = position2 + ((Vector3)(ref val7)).normalized * num; } Vector3 val8 = val5 - position; float magnitude2 = ((Vector3)(ref val8)).magnitude; _leftArmIkTarget.position = val5; _leftArmIkTarget.rotation = rotation2; LogLeftHandGunAnchorDiagnostics(player, val5, magnitude2); } private static bool TryEnsureLeftHandGunAnchorCache(PlayerControllerB player, Transform propRoot) { if ((Object)(object)_leftHandGunAnchorCachedPropRoot == (Object)(object)propRoot && _leftHandGunAnchorResolveAttempted) { return _leftHandGunAnchorResolved; } ResetLeftHandGunAnchorState(); _leftHandGunAnchorCachedPropRoot = propRoot; _leftHandGunAnchorResolveAttempted = true; _nextLeftHandGunAnchorDiagTime = Time.time; Transform val = ResolveArmsRigSearchRoot(player); _leftArmIkTarget = FindRigTransform(val, "metarig/spine.003/RigArms/LeftArm/ArmsLeftArm_target", "ArmsLeftArm_target"); _rightArmIkTarget = FindRigTransform(val, "metarig/spine.003/RigArms/RightArm/ArmsRightArm_target", "ArmsRightArm_target"); _leftArmUpperBone = FindRigTransform(val, "metarig/spine.003/shoulder.L/arm.L_upper", "arm.L_upper"); _leftArmLowerBone = FindRigTransform(val, "metarig/spine.003/shoulder.L/arm.L_upper/arm.L_lower", "arm.L_lower"); _leftHandBone = FindRigTransform(val, "metarig/spine.003/shoulder.L/arm.L_upper/arm.L_lower/hand.L", "hand.L"); _rightHandBone = FindRigTransform(val, "metarig/spine.003/shoulder.R/arm.R_upper/arm.R_lower/hand.R", "hand.R"); bool flag = !string.IsNullOrEmpty(_activeProfile.LeftHandAnchorChildName); _pumpTransform = (flag ? FindChildByExactName(propRoot, _activeProfile.LeftHandAnchorChildName) : null); _leftHandGunAnchorResolved = (Object)(object)val != (Object)null && (Object)(object)_leftArmIkTarget != (Object)null && (Object)(object)_rightArmIkTarget != (Object)null && (Object)(object)_leftArmUpperBone != (Object)null && (Object)(object)_leftArmLowerBone != (Object)null && (Object)(object)_leftHandBone != (Object)null && (Object)(object)_rightHandBone != (Object)null && (!flag || (Object)(object)_pumpTransform != (Object)null); if (!_leftHandGunAnchorResolved && !_leftHandGunAnchorMissingLogged) { _leftHandGunAnchorMissingLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] left-hand gun anchor disabled for this attach; missing rig piece(s): " + $"armsRoot={(Object)(object)val != (Object)null} " + $"leftTarget={(Object)(object)_leftArmIkTarget != (Object)null} rightTarget={(Object)(object)_rightArmIkTarget != (Object)null} " + $"leftUpper={(Object)(object)_leftArmUpperBone != (Object)null} leftLower={(Object)(object)_leftArmLowerBone != (Object)null} " + $"leftHand={(Object)(object)_leftHandBone != (Object)null} rightHand={(Object)(object)_rightHandBone != (Object)null} " + $"pump={(Object)(object)_pumpTransform != (Object)null}.")); } } return _leftHandGunAnchorResolved; } private static Transform ResolveArmsRigSearchRoot(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return null; } try { if ((Object)(object)player.localArmsTransform != (Object)null) { return player.localArmsTransform; } } catch { } try { if ((Object)(object)player.playerModelArmsMetarig != (Object)null) { return player.playerModelArmsMetarig; } } catch { } return null; } private static Transform FindRigTransform(Transform root, string relativePath, string fallbackName) { Transform val = FindChildByRelativePath(root, relativePath); if ((Object)(object)val != (Object)null) { return val; } if (!string.IsNullOrEmpty(relativePath) && relativePath.StartsWith("metarig/", StringComparison.Ordinal)) { val = FindChildByRelativePath(root, relativePath.Substring("metarig/".Length)); if ((Object)(object)val != (Object)null) { return val; } } if (!string.IsNullOrEmpty(relativePath) && relativePath.StartsWith("metarig/spine.003/", StringComparison.Ordinal)) { val = FindChildByRelativePath(root, relativePath.Substring("metarig/spine.003/".Length)); if ((Object)(object)val != (Object)null) { return val; } } return FindChildByExactName(root, fallbackName); } private static Transform FindChildByRelativePath(Transform root, string relativePath) { if ((Object)(object)root == (Object)null || string.IsNullOrWhiteSpace(relativePath)) { return null; } string[] array = relativePath.Split('/'); Transform val = root; for (int i = ((array.Length != 0 && string.Equals(((Object)val).name, array[0], StringComparison.Ordinal)) ? 1 : 0); i < array.Length; i++) { string text = array[i]; if (string.IsNullOrEmpty(text)) { return null; } val = FindDirectChildByExactName(val, text); if ((Object)(object)val == (Object)null) { return null; } } return val; } private static Transform FindDirectChildByExactName(Transform root, string childName) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(childName)) { return null; } for (int i = 0; i < root.childCount; i++) { Transform child = root.GetChild(i); if ((Object)(object)child != (Object)null && string.Equals(((Object)child).name, childName, StringComparison.Ordinal)) { return child; } } return null; } private static Transform FindChildByExactName(Transform root, string childName) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(childName)) { return null; } if (string.Equals(((Object)root).name, childName, StringComparison.Ordinal)) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindChildByExactName(root.GetChild(i), childName); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static void LogLeftHandGunAnchorDiagnostics(PlayerControllerB player, Vector3 targetWorldPosition, float correctionMagnitude) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_00b1: 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) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextLeftHandGunAnchorDiagTime) { return; } _nextLeftHandGunAnchorDiagTime = Time.time + 2f; Camera val = null; try { val = (((Object)(object)player != (Object)null) ? player.gameplayCamera : null); } catch { } Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)_leftArmUpperBone == (Object)null) && !((Object)(object)_leftArmLowerBone == (Object)null) && !((Object)(object)_leftHandBone == (Object)null) && !((Object)(object)_pumpTransform == (Object)null)) { Vector3 vector = val2.InverseTransformPoint(targetWorldPosition); Vector3 vector2 = val2.InverseTransformPoint(_leftHandBone.position); Vector3 vector3 = val2.InverseTransformPoint(_pumpTransform.position); float number = Vector3.Distance(_leftArmUpperBone.position, targetWorldPosition); float number2 = Vector3.Distance(_leftArmUpperBone.position, _leftArmLowerBone.position) + Vector3.Distance(_leftArmLowerBone.position, _leftHandBone.position); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.FP] lh-diag: target=" + WeaponFirstPersonAnimationLogFormat.Vector(vector) + " solvedWrist=" + WeaponFirstPersonAnimationLogFormat.Vector(vector2) + " pump=" + WeaponFirstPersonAnimationLogFormat.Vector(vector3) + " targetDist=" + WeaponFirstPersonAnimationLogFormat.Float(number) + " chainLen=" + WeaponFirstPersonAnimationLogFormat.Float(number2) + " corr=" + WeaponFirstPersonAnimationLogFormat.Float(correctionMagnitude))); } } } private static void ResetLeftHandGunAnchorState() { _fingerPoseBindings.Clear(); _fingerPoseFinal.Clear(); _fingerPoseCachedLeftHand = null; _fingerPoseCachedRightHand = null; _leftHandGunAnchorCachedPropRoot = null; _leftArmIkTarget = null; _rightArmIkTarget = null; _leftArmUpperBone = null; _leftArmLowerBone = null; _leftHandBone = null; _rightHandBone = null; _pumpTransform = null; _leftHandGunAnchorResolveAttempted = false; _leftHandGunAnchorResolved = false; _leftHandGunAnchorMissingLogged = false; _leftHandGunAnchorTickFailureLogged = false; _nextLeftHandGunAnchorDiagTime = 0f; } private static Transform FindChildByNameSubstring(Transform root, string substring) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(substring)) { return null; } if (((Object)root).name != null && ((Object)root).name.IndexOf(substring, StringComparison.OrdinalIgnoreCase) >= 0) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindChildByNameSubstring(root.GetChild(i), substring); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static void HideHeldVisuals(IY4NGZFpWeapon weapon) { if (!IsAlive(weapon)) { return; } Renderer[] visualRenderers = WeaponVisuals.GetVisualRenderers(((Component)weapon.FpGrabbable).gameObject); foreach (Renderer val in visualRenderers) { if (!((Object)(object)val == (Object)null)) { if (!HiddenRendererStates.ContainsKey(val)) { HiddenRendererStates[val] = val.enabled; } val.enabled = false; } } } private static void RestoreHeldVisuals() { GrabbableObject val = (IsAlive(_activeWeapon) ? _activeWeapon.FpGrabbable : null); bool flag = (Object)(object)val != (Object)null && val.isPocketed; foreach (KeyValuePair hiddenRendererState in HiddenRendererStates) { if ((Object)(object)hiddenRendererState.Key != (Object)null) { hiddenRendererState.Key.enabled = !flag && hiddenRendererState.Value; } } HiddenRendererStates.Clear(); } private static bool TryGetWeapon(GrabbableObject grabbable, out IY4NGZFpWeapon weapon) { weapon = (((Object)(object)grabbable != (Object)null) ? ((Component)grabbable).GetComponent() : null); return IsAlive(weapon); } private static bool IsEnabled() { if (Plugin.WeaponsHeavyShotgunFpAnimation != null) { return Plugin.WeaponsHeavyShotgunFpAnimation.Value; } return true; } private static bool IsLeftHandGunAnchorEnabled() { if (Plugin.WeaponsFpLeftHandGunAnchor != null) { return Plugin.WeaponsFpLeftHandGunAnchor.Value; } return true; } private static bool IsLocalPlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return false; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController ?? StartOfRound.Instance?.localPlayerController; if (!((Object)(object)player == (Object)(object)val)) { if ((Object)(object)val == (Object)null && ((NetworkBehaviour)player).IsOwner) { return player.isPlayerControlled; } return false; } return true; } } internal static class WeaponFirstPersonAnimationLogFormat { internal static string Vector(Vector3 vector) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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) return "(" + Float(vector.x) + "," + Float(vector.y) + "," + Float(vector.z) + ")"; } internal static string VectorCsv(Vector3 vector) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) return Float(vector.x) + "," + Float(vector.y) + "," + Float(vector.z); } internal static string Float(float number) { return number.ToString("0.###", CultureInfo.InvariantCulture); } } public static class WeaponHostingApi { public const int ProtocolVersion = 1; private const string LogPrefix = "[Y4NGZWeaponHosting]"; private const string HostedVisualSuffix = " (HostedVisual)"; private static readonly HashSet Reported = new HashSet(StringComparer.Ordinal); private static readonly List SingleHit = new List(1); public static bool IsWeaponAvailable(string configId) { try { if (string.IsNullOrEmpty(configId)) { return false; } WeaponConfig weaponConfig = WeaponCatalog.ById(configId); if (weaponConfig == null || !string.Equals(weaponConfig.Id, configId, StringComparison.Ordinal)) { return false; } return WeaponModelRuntimeAssets.AssetsAvailable(configId); } catch (Exception e) { ReportOnce("available:" + configId, e); return false; } } public static GameObject GetItemPrefab(string configId) { try { return NativeWeaponRegistry.PrefabFor(configId); } catch (Exception e) { ReportOnce("prefab:" + configId, e); return null; } } public static GameObject InstantiateWorldModel(string configId, Transform parent) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)parent == (Object)null) { return null; } WeaponModelAssetSet weaponModelAssetSet = WeaponModelRuntimeAssets.ById(configId); if (weaponModelAssetSet == null) { ReportOnce("model:noset:" + configId, "'" + configId + "' has no bundled world model in this build."); return null; } GameObject val = WeaponModelRuntimeAssets.LoadPrefab(weaponModelAssetSet); if ((Object)(object)val == (Object)null) { return null; } GameObject obj = Object.Instantiate(val, parent, false); ((Object)obj).name = ((Object)val).name + " (HostedVisual)"; obj.transform.localPosition = Vector3.zero; obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = Vector3.one; StripGameplayComponents(obj); ApplyMaterials(obj, configId); SetLayerRecursively(obj, ((Component)parent).gameObject.layer); return obj; } catch (Exception e) { ReportOnce("model:" + configId, e); return null; } } public static bool TryGetMuzzle(string configId, out Vector3 localPosition, out Vector3 localForward) { //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) //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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) localPosition = Vector3.zero; localForward = Vector3.forward; try { WeaponLandmarks weaponLandmarks = WeaponLandmarkCatalog.ById(configId); if (weaponLandmarks == null) { return false; } localPosition = weaponLandmarks.MuzzlePosition; localForward = ((((Vector3)(ref weaponLandmarks.MuzzleForward)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref weaponLandmarks.MuzzleForward)).normalized : Vector3.forward); return true; } catch (Exception e) { ReportOnce("muzzle:" + configId, e); return false; } } public static bool TryGetModelBounds(string configId, out Bounds bounds) { //IL_0001: 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) bounds = default(Bounds); try { WeaponLandmarks weaponLandmarks = WeaponLandmarkCatalog.ById(configId); if (weaponLandmarks == null) { return false; } bounds = weaponLandmarks.ModelBounds; return true; } catch (Exception e) { ReportOnce("bounds:" + configId, e); return false; } } public static void PlayMuzzleFlash(GameObject modelRoot, string configId, Vector3 worldForward, float scale) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)modelRoot == (Object)null)) { WeaponLandmarks weaponLandmarks = WeaponLandmarkCatalog.ById(configId); if (weaponLandmarks == null) { ReportOnce("flash:nolandmarks:" + configId, "'" + configId + "' has no landmark entry, so a muzzle flash has nowhere to go."); return; } WeaponConfig weaponConfig = WeaponCatalog.ById(configId); string prefabName = ((weaponConfig != null && !string.IsNullOrWhiteSpace(weaponConfig.MuzzleFlashPrefabName)) ? weaponConfig.MuzzleFlashPrefabName : "Y4NGZ_MuzzleFlash_01"); float num = ((Plugin.WeaponsMuzzleFlashScale != null) ? Plugin.WeaponsMuzzleFlashScale.Value : 1f); WeaponMuzzleFlash.PlayHosted(modelRoot, weaponLandmarks, prefabName, worldForward, num * Mathf.Max(0.01f, scale)); } } catch (Exception e) { ReportOnce("flash:" + configId, e); } } public static AudioClip[] GetFireClips(string configId) { try { WeaponModelAssetSet weaponModelAssetSet = WeaponModelRuntimeAssets.ById(configId); if (weaponModelAssetSet == null || weaponModelAssetSet.FireClipNames == null || weaponModelAssetSet.FireClipNames.Length == 0) { return Array.Empty(); } List list = new List(weaponModelAssetSet.FireClipNames.Length); string[] fireClipNames = weaponModelAssetSet.FireClipNames; foreach (string assetName in fireClipNames) { AudioClip val = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, assetName); if ((Object)(object)val != (Object)null) { list.Add(val); } } return (list.Count > 0) ? list.ToArray() : Array.Empty(); } catch (Exception e) { ReportOnce("fireclips:" + configId, e); return Array.Empty(); } } public static bool TryGetReloadClips(string configId, out AudioClip tactical, out AudioClip empty) { tactical = null; empty = null; try { WeaponModelAssetSet weaponModelAssetSet = WeaponModelRuntimeAssets.ById(configId); if (weaponModelAssetSet == null) { return false; } tactical = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, weaponModelAssetSet.ReloadTacClipName); empty = WeaponModelRuntimeAssets.LoadClip(weaponModelAssetSet, weaponModelAssetSet.ReloadEmptyClipName); return (Object)(object)tactical != (Object)null || (Object)(object)empty != (Object)null; } catch (Exception e) { ReportOnce("reloadclips:" + configId, e); return false; } } public static void PlayImpact(Vector3 point, Vector3 normal, Collider hitCollider, string configId) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_002e: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)hitCollider == (Object)null)) { bool flag = (Object)(object)((Component)hitCollider).GetComponentInParent() != (Object)null; WeaponHit item = new WeaponHit { Point = point, Normal = normal, Collider = hitCollider, Distance = 0f, HitEnemy = flag, SurfaceIndex = (flag ? (-1) : WeaponSurfaceClassifier.ResolveSurfaceIndex(hitCollider)) }; WeaponConfig weaponConfig = WeaponCatalog.ById(configId); SingleHit.Clear(); SingleHit.Add(item); WeaponImpactEffects.PlayShotImpacts(SingleHit, (Plugin.WeaponsImpactScale != null) ? Plugin.WeaponsImpactScale.Value : 1f, weaponConfig?.AmmoType ?? WeaponAmmoType.HeavyCaliberRounds); SingleHit.Clear(); } } catch (Exception e) { ReportOnce("impact:" + configId, e); } } public static bool InitializeDroppedWeapon(GameObject spawnedInstance, int magazine, bool safetyOn) { try { if ((Object)(object)spawnedInstance == (Object)null) { return false; } Y4NGZWeaponBase component = spawnedInstance.GetComponent(); if ((Object)(object)component == (Object)null) { ReportOnce("drop:noweapon", "'" + ((Object)spawnedInstance).name + "' carries no Y4NGZ weapon component; nothing was initialised."); return false; } component.InitializeExternally(magazine, safetyOn); return true; } catch (Exception e) { ReportOnce("drop", e); return false; } } private static void StripGameplayComponents(GameObject instance) { Y4NGZWeaponBase[] componentsInChildren = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } NetworkObject[] componentsInChildren2 = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Collider[] componentsInChildren3 = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } Rigidbody[] componentsInChildren4 = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren4[i]); } } private static void ApplyMaterials(GameObject instance, string configId) { Material[] array = WeaponModelRuntimeAssets.LoadWeaponMaterials(configId); if (array == null || array.Length == 0) { return; } Renderer[] componentsInChildren = instance.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { val.sharedMaterials = array; continue; } bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] != (Object)null)) { flag = true; sharedMaterials[j] = array[Mathf.Min(j, array.Length - 1)]; } } if (flag) { val.sharedMaterials = sharedMaterials; } } } private static void SetLayerRecursively(GameObject root, int layer) { if (!((Object)(object)root == (Object)null)) { root.layer = layer; for (int i = 0; i < root.transform.childCount; i++) { SetLayerRecursively(((Component)root.transform.GetChild(i)).gameObject, layer); } } } private static void ReportOnce(string key, Exception e) { ReportOnce(key, (e != null) ? e.ToString() : ""); } private static void ReportOnce(string key, string detail) { if (Reported.Add(key ?? string.Empty)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeaponHosting] " + key + ": " + detail + " Logged once.")); } } } } internal static class WeaponImpactAudio { private const int MaxSources = 16; private const float SpatialBlend = 1f; private const float MaxDistanceMeters = 25f; private const float MinDistanceMeters = 1.5f; private const float AuthoredPitchVariation = 0.03f; private const float VanillaPitchVariation = 0.06f; private static readonly List Sources = new List(16); private static readonly List SourceStartedOrder = new List(16); private static GameObject _host; private static ulong _playOrder; private static AudioMixerGroup _mixerGroup; internal static void Prewarm() { WeaponImpactAudioRuntimeAssets.Prewarm(); EnsureHost(); EnsureSourcePool(); } internal static void PlaySurfaceHit(int surfaceIndex, Vector3 point) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) if (Plugin.WeaponsImpactAudioEnabled != null && !Plugin.WeaponsImpactAudioEnabled.Value) { return; } string text = WeaponSurfaceClassifier.SurfaceTag(surfaceIndex); WeaponImpactSoundFamily weaponImpactSoundFamily = WeaponImpactAudioModel.FamilyForSurfaceTag(text); AudioClip clip; bool flag = WeaponImpactAudioRuntimeAssets.TrySelectClip(weaponImpactSoundFamily, out clip); int num = ((!flag) ? (-1) : 0); if ((Object)(object)clip == (Object)null) { clip = WeaponSurfaceClassifier.HitSurfaceClip(surfaceIndex); if ((Object)(object)clip != (Object)null) { num = 1; } } if ((Object)(object)clip == (Object)null && weaponImpactSoundFamily != WeaponImpactSoundFamily.General && WeaponImpactAudioRuntimeAssets.TrySelectClip(WeaponImpactSoundFamily.General, out var clip2)) { clip = clip2; flag = true; num = 2; } if ((Object)(object)clip == (Object)null) { return; } int sourceIndex; bool stoleOldest; AudioSource val = RentSource(out sourceIndex, out stoleOldest); if (!((Object)(object)val == (Object)null)) { ((Component)val).transform.position = point; val.volume = Mathf.Clamp((Plugin.WeaponsImpactAudioVolume != null) ? Plugin.WeaponsImpactAudioVolume.Value : 0.75f, 0f, 2f); float num2 = (flag ? 0.03f : 0.06f); val.pitch = Random.Range(1f - num2, 1f + num2); AudioMixerGroup val2 = ResolveMixerGroup(); if ((Object)(object)val2 != (Object)null && (Object)(object)val.outputAudioMixerGroup != (Object)(object)val2) { val.outputAudioMixerGroup = val2; } val.Stop(); val.PlayOneShot(clip); SourceStartedOrder[sourceIndex] = ++_playOrder; if (WeaponVfxDiagnostics.Once("impact.audio")) { string arg = num switch { 2 => "authored:General", 1 => "vanilla:hitSurfaceSFX", 0 => "authored:" + weaponImpactSoundFamily, _ => "", }; WeaponVfxDiagnostics.Emit($"Impact audio fired (#118). surface={surfaceIndex} tag='{text}' " + $"family={weaponImpactSoundFamily} route={arg} clip='{((Object)clip).name}' " + string.Format("point={0} volume={1:F2} pitch={2:F3} ", ((Vector3)(ref point)).ToString("F2"), val.volume, val.pitch) + $"source={sourceIndex}/{16} stoleOldest={stoleOldest} " + "mixer='" + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "") + "' listener=" + (((Object)(object)Object.FindObjectOfType() != (Object)null) ? "present" : "MISSING") + " " + $"minDist={val.minDistance:F1} maxDist={val.maxDistance:F1}."); } } } private static AudioSource RentSource(out int sourceIndex, out bool stoleOldest) { sourceIndex = -1; stoleOldest = false; EnsureHost(); EnsureSourcePool(); if ((Object)(object)_host == (Object)null || Sources.Count == 0) { return null; } for (int i = 0; i < Sources.Count; i++) { AudioSource val = Sources[i]; if ((Object)(object)val == (Object)null) { val = CreateSource(i); Sources[i] = val; } if ((Object)(object)val != (Object)null && !val.isPlaying) { sourceIndex = i; return val; } } int num = 0; ulong num2 = SourceStartedOrder[0]; for (int j = 1; j < SourceStartedOrder.Count; j++) { if (SourceStartedOrder[j] < num2) { num2 = SourceStartedOrder[j]; num = j; } } sourceIndex = num; stoleOldest = true; return Sources[num]; } private static void EnsureSourcePool() { if (!((Object)(object)_host == (Object)null)) { while (Sources.Count < 16) { int count = Sources.Count; Sources.Add(CreateSource(count)); SourceStartedOrder.Add(0uL); } } } private static AudioSource CreateSource(int index) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_host == (Object)null) { return null; } GameObject val = new GameObject($"Y4NGZ_ImpactAudio_{index}"); val.transform.SetParent(_host.transform, false); AudioSource obj = val.AddComponent(); obj.playOnAwake = false; obj.loop = false; obj.spatialBlend = 1f; obj.rolloffMode = (AudioRolloffMode)1; obj.minDistance = 1.5f; obj.maxDistance = 25f; obj.dopplerLevel = 0f; return obj; } private static AudioMixerGroup ResolveMixerGroup() { if ((Object)(object)_mixerGroup != (Object)null) { return _mixerGroup; } GrabbableObject val = (((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.localPlayerController != (Object)null) ? StartOfRound.Instance.localPlayerController.currentlyHeldObjectServer : null); AudioSource val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : null); if ((Object)(object)val2 != (Object)null) { _mixerGroup = val2.outputAudioMixerGroup; } return _mixerGroup; } private static void EnsureHost() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)_host != (Object)null)) { _host = new GameObject("Y4NGZ_WeaponImpactAudio"); Object.DontDestroyOnLoad((Object)(object)_host); Sources.Clear(); SourceStartedOrder.Clear(); _playOrder = 0uL; } } internal static void StopAll() { for (int i = 0; i < Sources.Count; i++) { if ((Object)(object)Sources[i] != (Object)null) { Sources[i].Stop(); } if (i < SourceStartedOrder.Count) { SourceStartedOrder[i] = 0uL; } } _playOrder = 0uL; _mixerGroup = null; WeaponImpactAudioRuntimeAssets.ResetSelections(); } } internal enum WeaponImpactSoundFamily { Concrete, Ground, Tinplate, Metal, Water, Pottery, Snow, Soft, General, Wood } internal static class WeaponImpactAudioModel { internal static readonly WeaponImpactSoundFamily[] Families = new WeaponImpactSoundFamily[10] { WeaponImpactSoundFamily.Concrete, WeaponImpactSoundFamily.Ground, WeaponImpactSoundFamily.Tinplate, WeaponImpactSoundFamily.Metal, WeaponImpactSoundFamily.Water, WeaponImpactSoundFamily.Pottery, WeaponImpactSoundFamily.Snow, WeaponImpactSoundFamily.Soft, WeaponImpactSoundFamily.General, WeaponImpactSoundFamily.Wood }; internal static WeaponImpactSoundFamily FamilyForSurfaceTag(string surfaceTag) { string text = ((surfaceTag == null) ? string.Empty : surfaceTag.Trim()); if (text.Length == 0 || text.Equals("Untagged", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.General; } if (text.Equals("Concrete", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Concrete; } if (text.Equals("Gravel", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Ground; } if (text.Equals("Catwalk", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Tinplate; } if (text.Equals("Aluminum", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Metal; } if (text.Equals("Grass", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Ground; } if (text.Equals("Rock", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Concrete; } if (text.Equals("Puddle", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Water; } if (text.Equals("Tiles", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Pottery; } if (text.Equals("Snow", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Snow; } if (text.Equals("Carpet", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Soft; } if (text.Equals("Wood", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Wood; } if (text.Equals("Slime", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Water; } if (text.Equals("Tree", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.Wood; } if (text.Equals("AnomalyObject", StringComparison.OrdinalIgnoreCase)) { return WeaponImpactSoundFamily.General; } string text2 = text.ToLowerInvariant(); if (text2.Contains("catwalk") || text2.Contains("tinplate") || text2.Contains("tin plate") || text2.StartsWith("tin_", StringComparison.Ordinal) || text2.StartsWith("tin-", StringComparison.Ordinal) || text2 == "tin") { return WeaponImpactSoundFamily.Tinplate; } if (text2.Contains("pottery") || text2.Contains("tile") || text2.Contains("ceramic") || text2.Contains("porcelain")) { return WeaponImpactSoundFamily.Pottery; } if (text2.Contains("gravel") || text2.Contains("ground") || text2.Contains("grass") || text2.Contains("dirt") || text2.Contains("soil") || text2.Contains("sand") || text2.Contains("mud")) { return WeaponImpactSoundFamily.Ground; } if (text2.Contains("puddle") || text2.Contains("slime") || text2.Contains("water") || text2.Contains("liquid")) { return WeaponImpactSoundFamily.Water; } if (text2.Contains("snow") || text2.Contains("ice")) { return WeaponImpactSoundFamily.Snow; } if (text2.Contains("carpet") || text2.Contains("soft") || text2.Contains("fabric") || text2.Contains("cloth")) { return WeaponImpactSoundFamily.Soft; } if (text2.Contains("wood") || text2.Contains("tree") || text2.Contains("timber")) { return WeaponImpactSoundFamily.Wood; } if (text2.Contains("metal") || text2.Contains("alumin") || text2.Contains("steel") || text2.Contains("iron") || text2.Contains("grate")) { return WeaponImpactSoundFamily.Metal; } if (text2.Contains("concrete") || text2.Contains("rock") || text2.Contains("stone") || text2.Contains("brick")) { return WeaponImpactSoundFamily.Concrete; } return WeaponImpactSoundFamily.General; } internal static int VariantCount(WeaponImpactSoundFamily family) { switch (family) { case WeaponImpactSoundFamily.Pottery: case WeaponImpactSoundFamily.Soft: case WeaponImpactSoundFamily.Wood: return 4; default: return 5; } } internal static string AddressFor(WeaponImpactSoundFamily family, int zeroBasedVariant) { int num = VariantCount(family); if (zeroBasedVariant < 0 || zeroBasedVariant >= num) { throw new ArgumentOutOfRangeException("zeroBasedVariant"); } return $"Y4NGZ_ImpactAudio_{family}_{zeroBasedVariant + 1:00}"; } internal static int ChooseNonRepeatingIndex(int variantCount, int previousIndex, int entropy) { if (variantCount <= 0) { return -1; } if (variantCount == 1) { return 0; } if (previousIndex < 0 || previousIndex >= variantCount) { return PositiveModulo(entropy, variantCount); } int num = PositiveModulo(entropy, variantCount - 1); if (num < previousIndex) { return num; } return num + 1; } private static int PositiveModulo(int value, int divisor) { int num = value % divisor; if (num >= 0) { return num; } return num + divisor; } } internal static class WeaponImpactAudioRuntimeAssets { internal const string BundleName = "y4ngz-upgrades-impactaudio.lethalbundle"; internal const int RequiredClipCount = 47; private static readonly Dictionary FamilyCache = new Dictionary(); private static readonly Dictionary LastVariant = new Dictionary(); private static AssetBundle _bundle; private static bool _loadAttempted; private static string _bundleSource; internal static void Prewarm() { if (!EnsureBundleLoaded()) { return; } int num = 0; WeaponImpactSoundFamily[] families = WeaponImpactAudioModel.Families; foreach (WeaponImpactSoundFamily family in families) { num += FamilyFor(family).Length; } if (num == 47) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZImpactAudio] Prewarmed {num}/{47} authored clips " + "from " + (_bundleSource ?? ((Object)_bundle).name) + ".")); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)($"[Y4NGZImpactAudio] Prewarmed only {num}/{47} authored clips " + "from " + (_bundleSource ?? ((Object)_bundle).name) + "; missing families will use vanilla/general fallback.")); } } } internal static bool TrySelectClip(WeaponImpactSoundFamily family, out AudioClip clip) { clip = null; AudioClip[] array = FamilyFor(family); if (array.Length == 0) { return false; } int value; int previousIndex = (LastVariant.TryGetValue(family, out value) ? value : (-1)); int entropy = Random.Range(0, int.MaxValue); int num = WeaponImpactAudioModel.ChooseNonRepeatingIndex(array.Length, previousIndex, entropy); if (num < 0) { return false; } LastVariant[family] = num; clip = array[num]; return (Object)(object)clip != (Object)null; } internal static void ResetSelections() { LastVariant.Clear(); } private static AudioClip[] FamilyFor(WeaponImpactSoundFamily family) { if (FamilyCache.TryGetValue(family, out var value)) { return value; } if (!EnsureBundleLoaded()) { return Array.Empty(); } int num = WeaponImpactAudioModel.VariantCount(family); List list = new List(num); for (int i = 0; i < num; i++) { string text = WeaponImpactAudioModel.AddressFor(family, i); AudioClip val = _bundle.LoadAsset(text); if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZImpactAudio] Authored clip '" + text + "' is missing from y4ngz-upgrades-impactaudio.lethalbundle.")); } } else { val.LoadAudioData(); list.Add(val); } } AudioClip[] array = list.ToArray(); FamilyCache[family] = array; return array; } private static bool EnsureBundleLoaded() { if (_loadAttempted) { return (Object)(object)_bundle != (Object)null; } _loadAttempted = true; string text = WeaponImpactAudioModel.AddressFor(WeaponImpactSoundFamily.Concrete, 0); foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if (!((Object)(object)allLoadedAssetBundle == (Object)null) && !((Object)(object)allLoadedAssetBundle.LoadAsset(text) == (Object)null)) { _bundle = allLoadedAssetBundle; _bundleSource = "already-loaded:" + ((Object)allLoadedAssetBundle).name; break; } } if ((Object)(object)_bundle == (Object)null) { string text2 = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "y4ngz-upgrades-impactaudio.lethalbundle"); if (File.Exists(text2)) { _bundle = AssetBundle.LoadFromFile(text2); if ((Object)(object)_bundle != (Object)null) { _bundleSource = "LoadFromFile:" + ((Object)_bundle).name; } else { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZImpactAudio] Failed to load " + text2 + "; using vanilla impact clips.")); } } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZImpactAudio] Bundle not found at " + text2 + "; using vanilla impact clips.")); } } } return (Object)(object)_bundle != (Object)null; } } internal static class WeaponImpactEffects { private const int MaxLiveInstances = 32; private const int MaxPooledInstances = 32; private const float InstanceLifetime = 3f; private const float NormalOffsetMeters = 0.002f; private const float RollRangeDegrees = 15f; private static readonly string[] DefaultFamily = new string[2] { "Y4NGZ_HitImpact_Concrete_01", "Y4NGZ_HitImpact_Concrete_02" }; private static readonly string[] MetalFamily = new string[1] { "Y4NGZ_HitImpact_Metal_01" }; private const float MetalFamilyScale = 3f; private static readonly string[] WoodFamily = new string[2] { "Y4NGZ_HitImpact_Wood_01", "Y4NGZ_HitImpact_Wood_02" }; private const int MaxLivePerPrefab = 10; private static readonly VfxInstanceCache Cache = new VfxInstanceCache(32, 32); private static readonly Dictionary SurfaceColliderCache = new Dictionary(64); private const int SurfaceColliderCacheCap = 256; private static WeaponWorldImpactFamily FamilyKeyFor(int surfaceIndex) { if (surfaceIndex == -1) { return WeaponWorldImpactFamily.Default; } string text = WeaponSurfaceClassifier.SurfaceTag(surfaceIndex); if (string.IsNullOrEmpty(text)) { return WeaponWorldImpactFamily.Default; } switch (text) { case "Catwalk": case "Aluminum": return WeaponWorldImpactFamily.Metal; case "Wood": case "Tree": return WeaponWorldImpactFamily.Wood; default: { string text2 = text.ToLowerInvariant(); if (text2.Contains("metal") || text2.Contains("steel") || text2.Contains("alumin") || text2.Contains("catwalk") || text2.Contains("grate")) { return WeaponWorldImpactFamily.Metal; } if (text2.Contains("wood") || text2.Contains("plank") || text2.Contains("tree")) { return WeaponWorldImpactFamily.Wood; } return WeaponWorldImpactFamily.Default; } } } private static string[] BurstFamilyFor(WeaponWorldImpactFamily family) { return family switch { WeaponWorldImpactFamily.Metal => MetalFamily, WeaponWorldImpactFamily.Wood => WoodFamily, _ => DefaultFamily, }; } private static WeaponWorldImpactFamily WorldFamilyFor(WeaponHit hit) { WeaponWorldImpactFamily weaponWorldImpactFamily = FamilyKeyFor(hit.SurfaceIndex); if (weaponWorldImpactFamily != WeaponWorldImpactFamily.Metal && ImpactMaterialCatalog.IsMetalHazard(hit.Collider)) { return WeaponWorldImpactFamily.Metal; } return weaponWorldImpactFamily; } internal static void PlayShotImpacts(List hits, float scale = 1f, WeaponAmmoType ammo = WeaponAmmoType.SmallCaliberRounds) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (hits == null || hits.Count == 0) { return; } Cache.RetireExpired(); for (int i = 0; i < hits.Count; i++) { WeaponHit hit = hits[i]; if (hit.HitEnemy) { PlayCreatureImpact(hits, i, scale, ammo); } else if (IsImpactSurface(hit.Collider)) { WeaponWorldImpactFamily family = WorldFamilyFor(hit); SpawnBurst(hit, scale, BurstFamilyFor(family)); WeaponBulletHoleDecals.PlayWorldHit(hit, family); WeaponImpactAudio.PlaySurfaceHit(hit.SurfaceIndex, hit.Point); } } } private static bool IsImpactSurface(Collider collider) { if ((Object)(object)collider == (Object)null) { return false; } if (SurfaceColliderCache.TryGetValue(collider, out var value)) { return value; } value = (Object)(object)((Component)collider).GetComponentInParent() == (Object)null && (Object)(object)((Component)collider).GetComponentInParent() == (Object)null && (Object)(object)((Component)collider).GetComponentInParent() == (Object)null; if (SurfaceColliderCache.Count >= 256) { SurfaceColliderCache.Clear(); } SurfaceColliderCache[collider] = value; return value; } private static void PlayCreatureImpact(List hits, int index, float scale, WeaponAmmoType ammo) { WeaponHit hit = hits[index]; ImpactMaterial impactMaterial = ImpactMaterialCatalog.ResolveFromCollider(hit.Collider); if (impactMaterial == ImpactMaterial.Metal) { SpawnBurst(hit, scale, MetalFamily); } else if (ImpactMaterialCatalog.Bleeds(impactMaterial)) { EnemyAI enemy = ImpactMaterialCatalog.EnemyFor(hit.Collider); if (IsFirstContactOnCreature(hits, index, enemy, out var contacts)) { WeaponCreatureBlood.Play(hit, enemy, impactMaterial, contacts, ammo); } } } private static bool IsFirstContactOnCreature(List hits, int index, EnemyAI enemy, out int contacts) { contacts = 0; if ((Object)(object)enemy == (Object)null) { return false; } for (int i = 0; i < hits.Count; i++) { if (hits[i].HitEnemy && !((Object)(object)ImpactMaterialCatalog.EnemyFor(hits[i].Collider) != (Object)(object)enemy)) { if (i < index) { contacts = 0; return false; } contacts++; } } return true; } private static void SpawnBurst(WeaponHit hit, float scale, string[] family) { //IL_0076: 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_007b: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) string text = family[Random.Range(0, family.Length)]; GameObject val = WeaponVfxRuntimeAssets.LoadPrefab(text); if ((Object)(object)val == (Object)null) { if (WeaponVfxDiagnostics.Once("impact.noprefab")) { WeaponVfxDiagnostics.Emit("Impact burst aborted: prefab '" + text + "' did not resolve."); } return; } Cache.EnforcePerKeyCapacityForNewInstance(text, 10); Cache.EnforceCapacityForNewInstance(); Vector3 val2 = ((((Vector3)(ref hit.Normal)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref hit.Normal)).normalized : Vector3.up); Vector3 val3 = ((Mathf.Abs(Vector3.Dot(val2, Vector3.up)) > 0.95f) ? Vector3.forward : Vector3.up); Quaternion orientation = Quaternion.AngleAxis(Random.Range(-15f, 15f), val2) * Quaternion.LookRotation(val2, val3); Vector3 val4 = hit.Point + val2 * 0.002f; VfxInstanceCache.Entry entry = RentBurst(text, val, val4, orientation); GameObject instance = entry.Instance; float num = ((scale > 0f) ? scale : 1f) * ((family == MetalFamily) ? 3f : 1f); instance.transform.localScale = entry.BaseScale * num; instance.SetActive(true); ParticleSystem[] systems = entry.Systems; for (int i = 0; i < systems.Length; i++) { if (!((Object)(object)systems[i] == (Object)null)) { systems[i].Clear(false); systems[i].Play(false); } } string key = (hit.HitEnemy ? "impact.instance.creature" : "impact.instance"); if (WeaponVfxDiagnostics.Once(key)) { WeaponVfxDiagnostics.Emit("Impact burst fired. prefab='" + text + "' source=" + (WeaponVfxRuntimeAssets.SourceFor(text) ?? "") + " origin=" + ((Vector3)(ref val4)).ToString("F3") + " normal=" + ((Vector3)(ref val2)).ToString("F3") + " " + $"scale={scale:F2} resolvedScale={num:F2} " + "collider='" + (((Object)(object)hit.Collider != (Object)null) ? ((Object)hit.Collider).name : "") + "' " + $"surface={hit.SurfaceIndex}" + "('" + WeaponSurfaceClassifier.SurfaceTag(hit.SurfaceIndex) + "') " + $"hitEnemy={hit.HitEnemy} " + WeaponVfxDiagnostics.DescribeInstance(instance, val4)); WeaponVfxDiagnostics.SampleAliveOverTime(instance, key); } Cache.Track(entry, 3f); WeaponVfxHousekeeping.EnsureDriver(); } private static VfxInstanceCache.Entry RentBurst(string prefabName, GameObject prefab, Vector3 origin, Quaternion orientation) { //IL_0024: 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_001a: 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_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) if (Cache.TryRent(prefabName, out var entry)) { entry.Instance.transform.SetPositionAndRotation(origin, orientation); return entry; } GameObject val = Object.Instantiate(prefab, origin, orientation); ParticleSystem[] componentsInChildren = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { ClampCollisionCost(componentsInChildren[i]); } } return new VfxInstanceCache.Entry { Instance = val, Systems = componentsInChildren, PoolKey = prefabName, BaseScale = val.transform.localScale }; } private static void ClampCollisionCost(ParticleSystem system) { //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) CollisionModule collision = system.collision; if (((CollisionModule)(ref collision)).enabled) { ((CollisionModule)(ref collision)).quality = (ParticleSystemCollisionQuality)2; ((CollisionModule)(ref collision)).maxCollisionShapes = 32; } } internal static void RetireExpiredExternal() { if (Cache.LiveCount > 0) { Cache.RetireExpired(); } } internal static void StopAll() { Cache.StopAll(); SurfaceColliderCache.Clear(); } } internal enum WeaponLandmarkKind { Muzzle, EjectionPort, AimPoint, DominantGrip, SupportGrip } internal sealed class WeaponLandmarks { public string ConfigId; public Vector3 VisualLocalPosition = Vector3.zero; public Vector3 VisualLocalEuler = Vector3.zero; public float VisualLocalScale = 1f; public Vector3 MuzzlePosition = Vector3.zero; public Vector3 MuzzleForward = Vector3.forward; public Vector3 EjectionPortPosition = Vector3.zero; public Vector3 EjectionPortNormal = Vector3.right; public Vector3 EjectionVelocityDirection = Vector3.right; public Vector2 EjectionPortSize = Vector2.zero; public Vector3 AimPointPosition = Vector3.zero; public bool HasAimPoint; public Vector3 DominantGripPosition = Vector3.zero; public Vector3 DominantGripAxis = Vector3.down; public float DominantGripRakeDegrees; public bool HasSupportGrip; public Vector3 SupportGripPosition = Vector3.zero; public float MinimumGripSeparation = 0.12f; public bool UsesFixedVisualScale; public float FixedVisualScale = 1f; public bool DominantHandCarries; public Vector3 TriggerFacePosition = Vector3.zero; public bool HasTriggerFace; public string VisualRootName; public string PropAnimationRoot; public string PropMeshNode; public string[] ArticulatedDescendants = Array.Empty(); public string[] ThirdPersonHiddenDescendants = Array.Empty(); public Bounds ModelBounds; internal Vector3 PositionFor(WeaponLandmarkKind kind) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) return (Vector3)(kind switch { WeaponLandmarkKind.Muzzle => MuzzlePosition, WeaponLandmarkKind.EjectionPort => EjectionPortPosition, WeaponLandmarkKind.AimPoint => AimPointPosition, WeaponLandmarkKind.DominantGrip => DominantGripPosition, WeaponLandmarkKind.SupportGrip => SupportGripPosition, _ => Vector3.zero, }); } internal bool Has(WeaponLandmarkKind kind) { return kind switch { WeaponLandmarkKind.AimPoint => HasAimPoint, WeaponLandmarkKind.SupportGrip => HasSupportGrip, _ => true, }; } } internal static class WeaponLandmarkCatalog { internal const string MX16A4Id = "mx16a4"; internal const string HeavyShotgunId = "heavy_shotgun"; internal static readonly WeaponLandmarks HeavyShotgun = new WeaponLandmarks { ConfigId = "heavy_shotgun", VisualLocalPosition = new Vector3(-0.004141f, 0.022855f, -0.146531f), VisualLocalEuler = new Vector3(12.888f, 179.373f, 302.417f), VisualLocalScale = 1.5523f, MuzzlePosition = new Vector3(0f, 0.09878f, 0.827574f), MuzzleForward = Vector3.forward, HasAimPoint = false, DominantGripPosition = new Vector3(0.009498f, -0.032823f, -0.053388f), HasSupportGrip = true, SupportGripPosition = new Vector3(-0.016201f, 0.024059f, 0.32297f), DominantHandCarries = true, UsesFixedVisualScale = true, FixedVisualScale = 1.5523f, HasTriggerFace = false, VisualRootName = "Y4NGZ_HeavyShotgunVisual", PropMeshNode = "heavy_shotgun", ModelBounds = new Bounds(new Vector3(0.000632f, 0.029451f, 0.385018f), new Vector3(0.063219f, 0.22618f, 0.885112f)) }; internal const string Kar98KId = "kar98k"; internal const string X18Id = "x18"; internal static readonly WeaponLandmarks MX16A4 = new WeaponLandmarks { ConfigId = "mx16a4", MuzzlePosition = new Vector3(0f, 0f, 0.5963f), MuzzleForward = new Vector3(0f, 0f, 1f), HasAimPoint = false, DominantGripPosition = new Vector3(0f, -0.095f, -0.125f), DominantGripAxis = new Vector3(0f, -0.76f, -0.65f), DominantGripRakeDegrees = 40.5f, HasSupportGrip = true, SupportGripPosition = new Vector3(-0.032779f, -0.042416f, 0.202373f), DominantHandCarries = true, HasTriggerFace = false, VisualRootName = "Y4NGZ_MX16A4Visual", PropAnimationRoot = "Root", PropMeshNode = "M16A4", ArticulatedDescendants = new string[8] { "Bolt", "BoltRelease", "ChargingHandle", "DustCover", "FireSelector", "Mag", "MagRelease", "Trigger" }, ModelBounds = new Bounds(new Vector3(0.0008f, -0.0716f, 0.0848f), new Vector3(0.0632f, 0.2562f, 1.023f)) }; internal static readonly WeaponLandmarks Kar98K = new WeaponLandmarks { ConfigId = "kar98k", MuzzlePosition = new Vector3(0f, 0f, 0.712691f), MuzzleForward = Vector3.forward, AimPointPosition = new Vector3(0f, 0.0249f, 0.2359f), HasAimPoint = true, DominantGripPosition = new Vector3(0.023005f, -0.060203f, -0.207579f), DominantGripAxis = new Vector3(-0.083457f, 0.038273f, -0.995776f), DominantGripRakeDegrees = 87.8f, HasSupportGrip = true, SupportGripPosition = new Vector3(-0.015454f, -0.048316f, 0.183041f), HasTriggerFace = false, VisualRootName = "Y4NGZ_Kar98KVisual", PropAnimationRoot = "Root", PropMeshNode = "Kar98K", ArticulatedDescendants = new string[10] { "StaticBolt", "Bolt", "Trigger", "Cartridge", "Clip", "CartridgeClip0", "CartridgeClip1", "CartridgeClip2", "CartridgeClip3", "CartridgeClip4" }, ThirdPersonHiddenDescendants = new string[2] { "Clip", "Cartridge" }, ModelBounds = new Bounds(new Vector3(0.007754f, 0.000956f, 0.149525f), new Vector3(0.061328f, 0.348722f, 1.126332f)) }; internal static readonly WeaponLandmarks X18 = new WeaponLandmarks { ConfigId = "x18", MuzzlePosition = new Vector3(0f, 0f, 0.115489f), MuzzleForward = Vector3.forward, AimPointPosition = new Vector3(0f, 0.0145f, -0.0635f), HasAimPoint = true, DominantGripPosition = new Vector3(0.018037f, -0.083691f, -0.102224f), DominantGripAxis = new Vector3(-0.92288f, -0.348589f, 0.163643f), DominantGripRakeDegrees = 69.6f, HasSupportGrip = true, SupportGripPosition = new Vector3(-0.016639f, -0.091656f, -0.072359f), MinimumGripSeparation = 0.035f, UsesFixedVisualScale = true, FixedVisualScale = 1.15f, DominantHandCarries = true, HasTriggerFace = false, VisualRootName = "Y4NGZ_X18Visual", PropAnimationRoot = "Root", PropMeshNode = "X18", ArticulatedDescendants = new string[7] { "Barrel", "Mag", "Cartridge", "CartridgeBed", "Slider", "FireSelector", "Trigger" }, ModelBounds = new Bounds(new Vector3(-3.5E-05f, -0.056845f, 0.013398f), new Vector3(0.035888f, 0.143449f, 0.20418f)) }; internal const string RevolverId = "revolver"; internal static readonly WeaponLandmarks Revolver = new WeaponLandmarks { ConfigId = "revolver", VisualLocalPosition = new Vector3(0.001081f, 0.028867f, -0.125605f), VisualLocalEuler = new Vector3(8.747f, 185.104f, 303.844f), VisualLocalScale = 1.4427f, MuzzlePosition = new Vector3(0f, 0.092908f, 0.328723f), MuzzleForward = Vector3.forward, HasAimPoint = false, DominantGripPosition = new Vector3(0.017549f, -0.027088f, -0.047411f), DominantGripAxis = new Vector3(0f, -0.873481f, 0.486858f), DominantGripRakeDegrees = 29.1f, HasSupportGrip = true, SupportGripPosition = new Vector3(-0.015687f, -0.095114f, -0.042546f), MinimumGripSeparation = 0.035f, UsesFixedVisualScale = true, FixedVisualScale = 1.4427f, DominantHandCarries = true, HasTriggerFace = false, VisualRootName = "Y4NGZ_RevolverVisual", PropMeshNode = "revolver", ModelBounds = new Bounds(new Vector3(0f, 0.024032f, 0.138246f), new Vector3(0.050154f, 0.210014f, 0.380955f)) }; internal const string FlamethrowerId = "flame_thrower"; internal static readonly WeaponLandmarks Flamethrower = new WeaponLandmarks { ConfigId = "flame_thrower", MuzzlePosition = new Vector3(0f, 0.012308f, 1.015573f), MuzzleForward = Vector3.forward, HasAimPoint = false, DominantGripPosition = new Vector3(0.017445f, -0.04449f, -0.053664f), DominantGripAxis = new Vector3(-0.014718f, -0.977637f, -0.209785f), DominantGripRakeDegrees = 12.1f, HasSupportGrip = true, SupportGripPosition = new Vector3(-0.077458f, 0.069597f, 0.167627f), UsesFixedVisualScale = true, FixedVisualScale = 1.2326f, DominantHandCarries = true, HasTriggerFace = false, VisualRootName = "Y4NGZ_FlamethrowerVisual", PropMeshNode = "base", ModelBounds = new Bounds(new Vector3(-0.060399f, 0.009085f, 0.458513f), new Vector3(0.188041f, 0.257809f, 1.114675f)) }; internal static WeaponLandmarks ById(string id) { if (string.Equals(id, "revolver", StringComparison.Ordinal)) { return Revolver; } if (string.Equals(id, "flame_thrower", StringComparison.Ordinal)) { return Flamethrower; } if (string.Equals(id, "mx16a4", StringComparison.Ordinal)) { return MX16A4; } if (string.Equals(id, "kar98k", StringComparison.Ordinal)) { return Kar98K; } if (string.Equals(id, "x18", StringComparison.Ordinal)) { return X18; } if (string.Equals(id, "heavy_shotgun", StringComparison.Ordinal)) { return HeavyShotgun; } return null; } } internal static class WeaponLandmarkResolver { internal static Transform HostFor(GameObject instance, WeaponLandmarks landmarks) { if ((Object)(object)instance == (Object)null) { return null; } if (landmarks == null) { return instance.transform; } if (!string.IsNullOrEmpty(landmarks.VisualRootName)) { Transform val = FindDeep(instance.transform, landmarks.VisualRootName); if ((Object)(object)val != (Object)null) { return val; } } if (!string.IsNullOrEmpty(landmarks.PropMeshNode)) { Transform val2 = FindDeep(instance.transform, landmarks.PropMeshNode); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.parent != (Object)null) { return val2.parent; } } return instance.transform; } internal static bool ResolvedHostIsAuthoritative(GameObject instance, WeaponLandmarks landmarks) { if ((Object)(object)instance != (Object)null && landmarks != null && !string.IsNullOrEmpty(landmarks.VisualRootName)) { return (Object)(object)FindDeep(instance.transform, landmarks.VisualRootName) != (Object)null; } return false; } internal static bool TryResolve(GameObject instance, WeaponLandmarks landmarks, WeaponLandmarkKind kind, out Vector3 worldPosition, out Quaternion worldRotation) { //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) //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_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) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_005b: 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_0069: 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_0078: Unknown result type (might be due to invalid IL or missing references) worldPosition = Vector3.zero; worldRotation = Quaternion.identity; if (landmarks == null || !landmarks.Has(kind)) { return false; } Transform val = HostFor(instance, landmarks); if ((Object)(object)val == (Object)null) { return false; } worldPosition = val.TransformPoint(landmarks.PositionFor(kind)); worldRotation = Quaternion.LookRotation(SafeDirection(val, DirectionFor(landmarks, kind), val.forward), SafeDirection(val, UpFor(landmarks, kind), val.up)); return true; } internal static bool TryGetBore(GameObject instance, WeaponLandmarks landmarks, out Vector3 origin, out Vector3 direction) { //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) //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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) origin = Vector3.zero; direction = Vector3.forward; Transform val = HostFor(instance, landmarks); if ((Object)(object)val == (Object)null || landmarks == null) { return false; } origin = val.TransformPoint(landmarks.MuzzlePosition); direction = SafeDirection(val, landmarks.MuzzleForward, val.forward); return true; } internal static bool TryGetEjection(GameObject instance, WeaponLandmarks landmarks, float alongBore01, float vertical01, out Vector3 origin, out Vector3 direction) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0093: 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) //IL_009d: Unknown result type (might be due to invalid IL or missing references) origin = Vector3.zero; direction = Vector3.right; Transform val = HostFor(instance, landmarks); if ((Object)(object)val == (Object)null || landmarks == null) { return false; } Vector3 ejectionPortPosition = landmarks.EjectionPortPosition; ejectionPortPosition.z += (Mathf.Clamp01(alongBore01) - 0.5f) * landmarks.EjectionPortSize.x; ejectionPortPosition.y += (Mathf.Clamp01(vertical01) - 0.5f) * landmarks.EjectionPortSize.y; origin = val.TransformPoint(ejectionPortPosition); direction = SafeDirection(val, landmarks.EjectionVelocityDirection, val.right); return true; } internal static bool MatchesAuthoredGeometry(GameObject instance, WeaponLandmarks landmarks, float tolerance, out Vector3 measuredSize) { //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) //IL_003e: 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_0077: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) measuredSize = Vector3.zero; if ((Object)(object)instance == (Object)null || landmarks == null) { return false; } Transform val = HostFor(instance, landmarks); if ((Object)(object)val == (Object)null) { return false; } Renderer[] componentsInChildren = instance.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return false; } bool flag = false; Bounds val2 = default(Bounds); Renderer[] array = componentsInChildren; foreach (Renderer val3 in array) { Mesh val4 = MeshOf(val3); if ((Object)(object)val4 == (Object)null) { continue; } Bounds bounds = val4.bounds; Vector3 center = ((Bounds)(ref bounds)).center; Vector3 extents = ((Bounds)(ref bounds)).extents; for (int j = 0; j < 8; j++) { Vector3 val5 = center + new Vector3(((j & 1) == 0) ? (0f - extents.x) : extents.x, ((j & 2) == 0) ? (0f - extents.y) : extents.y, ((j & 4) == 0) ? (0f - extents.z) : extents.z); Vector3 val6 = val.InverseTransformPoint(((Component)val3).transform.TransformPoint(val5)); if (!flag) { ((Bounds)(ref val2))..ctor(val6, Vector3.zero); flag = true; } else { ((Bounds)(ref val2)).Encapsulate(val6); } } } if (!flag) { return false; } measuredSize = ((Bounds)(ref val2)).size; Vector3 size = ((Bounds)(ref landmarks.ModelBounds)).size; if (Mathf.Abs(measuredSize.x - size.x) <= tolerance && Mathf.Abs(measuredSize.y - size.y) <= tolerance) { return Mathf.Abs(measuredSize.z - size.z) <= tolerance; } return false; } private static Vector3 DirectionFor(WeaponLandmarks landmarks, WeaponLandmarkKind kind) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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) switch (kind) { case WeaponLandmarkKind.Muzzle: case WeaponLandmarkKind.AimPoint: return landmarks.MuzzleForward; case WeaponLandmarkKind.EjectionPort: return landmarks.EjectionVelocityDirection; case WeaponLandmarkKind.DominantGrip: case WeaponLandmarkKind.SupportGrip: return landmarks.DominantGripAxis; default: return Vector3.forward; } } private static Vector3 UpFor(WeaponLandmarks landmarks, WeaponLandmarkKind kind) { //IL_0009: 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) if (kind == WeaponLandmarkKind.DominantGrip || kind == WeaponLandmarkKind.SupportGrip) { return landmarks.MuzzleForward; } return Vector3.up; } private static Vector3 SafeDirection(Transform host, Vector3 local, Vector3 fallback) { //IL_0013: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref local)).sqrMagnitude < 1E-08f) { return fallback; } Vector3 val = host.TransformDirection(((Vector3)(ref local)).normalized); if (!(((Vector3)(ref val)).sqrMagnitude < 1E-08f)) { return ((Vector3)(ref val)).normalized; } return fallback; } private static Mesh MeshOf(Renderer renderer) { if ((Object)(object)renderer == (Object)null) { return null; } MeshFilter component = ((Component)renderer).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { return component.sharedMesh; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.sharedMesh; } private static Transform FindDeep(Transform root, string name) { if ((Object)(object)root == (Object)null) { return null; } if (string.Equals(((Object)root).name, name, StringComparison.Ordinal)) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindDeep(root.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } } internal sealed class WeaponModelAssetSet { public string WeaponId; public string BundleName; public string ModelAssetName; public string[] FireClipNames; public string[] FireMechanicalClipNames; public float[] FireMechanicalClipDelaySeconds; public string ReloadTacClipName; public string ReloadEmptyClipName; public string ReloadStageStartClipName; public string ReloadStageLoopClipName; public string ReloadStageEndClipName; } internal static class WeaponModelRuntimeAssets { private static readonly WeaponModelAssetSet[] Catalog = new WeaponModelAssetSet[3] { new WeaponModelAssetSet { WeaponId = "mx16a4", BundleName = "y4ngz-upgrades-mx16a4.lethalbundle", ModelAssetName = "Y4NGZ_MX16A4", FireClipNames = new string[4] { "Y4NGZ_MX16A4_Fire_0", "Y4NGZ_MX16A4_Fire_1", "Y4NGZ_MX16A4_Fire_2", "Y4NGZ_MX16A4_Fire_3" }, ReloadTacClipName = "Y4NGZ_MX16A4_Reload_Tac", ReloadEmptyClipName = "Y4NGZ_MX16A4_Reload_Empty" }, new WeaponModelAssetSet { WeaponId = "kar98k", BundleName = "y4ngz-upgrades-kar98k.lethalbundle", ModelAssetName = "Y4NGZ_Kar98K", FireClipNames = new string[4] { "Y4NGZ_Kar98K_Fire_0", "Y4NGZ_Kar98K_Fire_1", "Y4NGZ_Kar98K_Fire_2", "Y4NGZ_Kar98K_Fire_3" }, FireMechanicalClipNames = new string[2] { "Y4NGZ_Kar98K_Reload_Open", "Y4NGZ_Kar98K_Reload_Close" }, FireMechanicalClipDelaySeconds = new float[2] { 0f, 0.329133f }, ReloadStageStartClipName = "Y4NGZ_Kar98K_Reload_Open", ReloadStageLoopClipName = "Y4NGZ_Kar98K_Reload_Insert", ReloadStageEndClipName = "Y4NGZ_Kar98K_Reload_Close" }, new WeaponModelAssetSet { WeaponId = "x18", BundleName = "y4ngz-upgrades-x18.lethalbundle", ModelAssetName = "Y4NGZ_X18", FireClipNames = new string[4] { "Y4NGZ_X18_Fire_0", "Y4NGZ_X18_Fire_1", "Y4NGZ_X18_Fire_2", "Y4NGZ_X18_Fire_3" }, ReloadTacClipName = "Y4NGZ_X18_Reload_Tac_Full", ReloadEmptyClipName = "Y4NGZ_X18_Reload_Empty_Full", ReloadStageStartClipName = "Y4NGZ_X18_Reload_MagOut", ReloadStageLoopClipName = "Y4NGZ_X18_Reload_MagIn", ReloadStageEndClipName = "Y4NGZ_X18_Reload_Slide" } }; private static readonly Dictionary PrefabCache = new Dictionary(); private static readonly Dictionary ClipCache = new Dictionary(); private static readonly Dictionary MaterialCacheByWeapon = new Dictionary(); private static readonly Dictionary SourceByAsset = new Dictionary(); private static readonly Dictionary OwnBundles = new Dictionary(); private static readonly HashSet LoadAttempted = new HashSet(); internal static WeaponModelAssetSet ById(string weaponId) { if (string.IsNullOrEmpty(weaponId)) { return null; } WeaponModelAssetSet[] catalog = Catalog; foreach (WeaponModelAssetSet weaponModelAssetSet in catalog) { if (weaponModelAssetSet != null && string.Equals(weaponModelAssetSet.WeaponId, weaponId, StringComparison.Ordinal)) { return weaponModelAssetSet; } } return null; } internal static string SourceFor(string assetName) { if (assetName == null || !SourceByAsset.TryGetValue(assetName, out var value)) { return null; } return value; } internal static bool AssetsAvailable(string weaponId) { WeaponModelAssetSet weaponModelAssetSet = ById(weaponId); if (weaponModelAssetSet == null || string.IsNullOrWhiteSpace(weaponModelAssetSet.ModelAssetName)) { return false; } if (PrefabCache.TryGetValue(weaponModelAssetSet.ModelAssetName, out var value) && (Object)(object)value != (Object)null) { return true; } if (OwnBundles.TryGetValue(weaponModelAssetSet.BundleName ?? string.Empty, out var value2) && (Object)(object)value2 != (Object)null) { return true; } foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if ((Object)(object)allLoadedAssetBundle != (Object)null && allLoadedAssetBundle.Contains(weaponModelAssetSet.ModelAssetName)) { return true; } } if (string.IsNullOrWhiteSpace(weaponModelAssetSet.BundleName)) { return false; } return File.Exists(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, weaponModelAssetSet.BundleName)); } internal static GameObject LoadPrefab(WeaponModelAssetSet set) { if (set == null || string.IsNullOrWhiteSpace(set.ModelAssetName)) { return null; } if (PrefabCache.TryGetValue(set.ModelAssetName, out var value) && (Object)(object)value != (Object)null) { return value; } GameObject val = LoadFromAnyBundle(set.ModelAssetName, set.BundleName); if ((Object)(object)val != (Object)null) { PrefabCache[set.ModelAssetName] = val; return val; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeaponModel] '" + set.ModelAssetName + "' could not be loaded. Missing " + set.BundleName + "? The weapon will fall back to its placeholder box.")); } return null; } internal static Material[] LoadWeaponMaterials(string weaponId) { if (string.IsNullOrEmpty(weaponId)) { return null; } if (MaterialCacheByWeapon.TryGetValue(weaponId, out var value) && value != null) { return value; } WeaponModelAssetSet weaponModelAssetSet = ById(weaponId); GameObject val = LoadPrefab(weaponModelAssetSet); if ((Object)(object)val == (Object)null) { return null; } Renderer[] componentsInChildren = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } MaterialCacheByWeapon[weaponId] = sharedMaterials; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeaponModel] '" + weaponId + "' first-person materials resolved from '" + weaponModelAssetSet.ModelAssetName + "': " + string.Join(", ", Array.ConvertAll(sharedMaterials, (Material m) => (!((Object)(object)m != (Object)null)) ? "(null)" : ((Object)m).name)))); } return sharedMaterials; } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeaponModel] '" + weaponModelAssetSet.ModelAssetName + "' has no renderer with materials; the first-person prop keeps its authoring materials.")); } return null; } internal static AudioClip LoadClip(WeaponModelAssetSet set, string assetName) { if (set == null || string.IsNullOrWhiteSpace(assetName)) { return null; } if (ClipCache.TryGetValue(assetName, out var value) && (Object)(object)value != (Object)null) { return value; } AudioClip val = LoadFromAnyBundle(assetName, set.BundleName); if ((Object)(object)val != (Object)null) { ClipCache[assetName] = val; return val; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeaponModel] Audio '" + assetName + "' could not be loaded from " + set.BundleName + ". That slot falls back to the vanilla shotgun clip.")); } return null; } private static T LoadFromAnyBundle(string assetName, string bundleName) where T : Object { foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if (!((Object)(object)allLoadedAssetBundle == (Object)null)) { T val = allLoadedAssetBundle.LoadAsset(assetName); if ((Object)(object)val != (Object)null) { SourceByAsset[assetName] = "already-loaded:" + ((Object)allLoadedAssetBundle).name; return val; } } } AssetBundle val2 = EnsureBundleLoaded(bundleName); T obj = (((Object)(object)val2 != (Object)null) ? val2.LoadAsset(assetName) : default(T)); if ((Object)(object)obj != (Object)null) { SourceByAsset[assetName] = "LoadFromFile:" + ((Object)val2).name; } return obj; } private static AssetBundle EnsureBundleLoaded(string bundleName) { if (string.IsNullOrWhiteSpace(bundleName)) { return null; } if (OwnBundles.TryGetValue(bundleName, out var value) && (Object)(object)value != (Object)null) { return value; } if (!LoadAttempted.Add(bundleName)) { return null; } string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, bundleName); if (!File.Exists(text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeaponModel] Bundle not found at " + text + ".")); } return null; } AssetBundle val = AssetBundle.LoadFromFile(text); if ((Object)(object)val == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeaponModel] Failed to load bundle at " + text + ".")); } return null; } OwnBundles[bundleName] = val; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[Y4NGZWeaponModel] Loaded " + bundleName + " (" + ((Object)val).name + ").")); } return val; } } internal static class WeaponMuzzleFlash { private sealed class FlashState { public int[] AuthoredLayers; public bool LayersDirty; } private const int MaxLiveInstances = 24; private const float InstanceLifetime = 1.5f; private static readonly VfxInstanceCache Cache = new VfxInstanceCache(24, 24); private static bool _hostWarningLogged; internal static void Play(GameObject weaponInstance, WeaponLandmarks landmarks, string prefabName, Vector3 shotDirection = default(Vector3), float scale = 1f, IY4NGZFpWeapon fpWeapon = null, PlayerControllerB fpHeldBy = null) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)weaponInstance == (Object)null || landmarks == null) { if (WeaponVfxDiagnostics.Once("play.nullargs")) { WeaponVfxDiagnostics.Emit("Play aborted: weaponInstance=" + (((Object)(object)weaponInstance != (Object)null) ? ((Object)weaponInstance).name : "") + " landmarks=" + ((landmarks != null) ? landmarks.ConfigId : "") + "."); } return; } Cache.RetireExpired(); if (!WeaponVisualBore.TryResolve(weaponInstance, landmarks, fpWeapon, fpHeldBy, out var origin, out var direction, out var host, out var firstPerson, out var failure)) { if (failure == WeaponVisualBoreFailure.NonAuthoritativeHost) { if (!_hostWarningLogged) { _hostWarningLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeaponVfx] Muzzle flash suppressed: '" + ((Object)weaponInstance).name + "' has no child named '" + landmarks.VisualRootName + "', so the muzzle landmark would resolve to the wrong place. Logged once.")); } } } else if (WeaponVfxDiagnostics.Once("play.nobore")) { WeaponVfxDiagnostics.Emit("Play aborted: TryGetBore failed on '" + ((Object)weaponInstance).name + "'."); } } else { Spawn(prefabName, origin, direction, shotDirection, host, firstPerson, scale); } } internal static void PlayHosted(GameObject modelRoot, WeaponLandmarks landmarks, string prefabName, Vector3 shotDirection = default(Vector3), float scale = 1f) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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) if ((Object)(object)modelRoot == (Object)null || landmarks == null) { if (WeaponVfxDiagnostics.Once("playhosted.nullargs")) { WeaponVfxDiagnostics.Emit("PlayHosted aborted: modelRoot=" + (((Object)(object)modelRoot != (Object)null) ? ((Object)modelRoot).name : "") + " landmarks=" + ((landmarks != null) ? landmarks.ConfigId : "") + "."); } return; } Cache.RetireExpired(); Transform transform = modelRoot.transform; Vector3 origin = transform.TransformPoint(landmarks.MuzzlePosition); Vector3 val; if (!(((Vector3)(ref landmarks.MuzzleForward)).sqrMagnitude > 1E-06f)) { val = transform.forward; } else { Vector3 val2 = transform.TransformDirection(landmarks.MuzzleForward); val = ((Vector3)(ref val2)).normalized; } Vector3 direction = val; Spawn(prefabName, origin, direction, shotDirection, transform, firstPerson: false, scale); } private static void Spawn(string prefabName, Vector3 origin, Vector3 direction, Vector3 shotDirection, Transform host, bool firstPerson, float scale) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) GameObject val = WeaponVfxRuntimeAssets.LoadPrefab(prefabName); if ((Object)(object)val == (Object)null) { if (WeaponVfxDiagnostics.Once("play.noprefab")) { WeaponVfxDiagnostics.Emit("Play aborted: prefab '" + prefabName + "' did not resolve."); } return; } Cache.EnforceCapacityForNewInstance(); Vector3 val2 = ((((Vector3)(ref shotDirection)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref shotDirection)).normalized : direction); Quaternion val3 = Quaternion.LookRotation(val2) * Quaternion.Euler(0f, 0f, Random.Range(0f, 360f)); float num = Random.Range(0.85f, 1.15f); VfxInstanceCache.Entry entry = RentFlash(prefabName, val); GameObject instance = entry.Instance; instance.transform.SetParent((Transform)null, false); instance.transform.localScale = entry.BaseScale; instance.transform.SetPositionAndRotation(origin, val3); if ((Object)(object)host != (Object)null) { instance.transform.SetParent(host, true); } FlashState flashState = (FlashState)entry.State; if (firstPerson && (Object)(object)host != (Object)null) { SetLayerRecursively(instance, ((Component)host).gameObject.layer); flashState.LayersDirty = true; } else if (flashState.LayersDirty) { int cursor = 0; RestoreLayersRecursively(instance, flashState.AuthoredLayers, ref cursor); flashState.LayersDirty = false; } float num2 = ((scale > 0f) ? scale : 1f) * num; if (!Mathf.Approximately(num2, 1f)) { Transform transform = instance.transform; transform.localScale *= num2; } instance.SetActive(true); ParticleSystem[] systems = entry.Systems; for (int i = 0; i < systems.Length; i++) { if (!((Object)(object)systems[i] == (Object)null)) { systems[i].Clear(true); systems[i].Play(true); } } if (WeaponVfxDiagnostics.Once("play.instance")) { WeaponVfxDiagnostics.Emit("Muzzle flash fired. prefab='" + prefabName + "' source=" + (WeaponVfxRuntimeAssets.SourceFor(prefabName) ?? "") + " model=" + (firstPerson ? "fp-prop" : "world") + " origin=" + ((Vector3)(ref origin)).ToString("F3") + " " + string.Format("boreDir={0} facing={1} scale={2:F2} ", ((Vector3)(ref direction)).ToString("F3"), ((Vector3)(ref val2)).ToString("F3"), scale) + "host='" + (((Object)(object)host != (Object)null) ? ((Object)host).name : "") + "'" + WeaponVfxDiagnostics.DescribeBoreAlignment(host, direction) + " " + WeaponVfxDiagnostics.DescribeInstance(instance, origin)); WeaponVfxDiagnostics.SampleAliveOverTime(instance, "play.instance"); } if (WeaponVfxDiagnostics.Once("play.renderstate")) { WeaponVfxDiagnostics.Emit(WeaponVfxDiagnostics.DescribeCameraRenderState()); } Cache.Track(entry, 1.5f); WeaponVfxHousekeeping.EnsureDriver(); } private static VfxInstanceCache.Entry RentFlash(string prefabName, GameObject prefab) { //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) if (Cache.TryRent(prefabName, out var entry)) { return entry; } GameObject val = Object.Instantiate(prefab); List list = new List(); CaptureLayersRecursively(val, list); return new VfxInstanceCache.Entry { Instance = val, Systems = val.GetComponentsInChildren(true), PoolKey = prefabName, BaseScale = val.transform.localScale, State = new FlashState { AuthoredLayers = list.ToArray() } }; } private static void CaptureLayersRecursively(GameObject root, List layers) { if (!((Object)(object)root == (Object)null)) { layers.Add(root.layer); for (int i = 0; i < root.transform.childCount; i++) { CaptureLayersRecursively(((Component)root.transform.GetChild(i)).gameObject, layers); } } } private static void RestoreLayersRecursively(GameObject root, int[] layers, ref int cursor) { if (!((Object)(object)root == (Object)null) && layers != null && cursor < layers.Length) { root.layer = layers[cursor++]; for (int i = 0; i < root.transform.childCount; i++) { RestoreLayersRecursively(((Component)root.transform.GetChild(i)).gameObject, layers, ref cursor); } } } internal static void PlayIsolatedInFrontOfCamera(string prefabName, float distance = 1.5f) { //IL_005a: 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) //IL_006b: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) Camera val = WeaponVfxDiagnostics.ResolveViewCamera(); if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Y4NGZWeaponVfx] Isolation test skipped: no camera resolved."); } return; } GameObject val2 = WeaponVfxRuntimeAssets.LoadPrefab(prefabName); if ((Object)(object)val2 == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeaponVfx] Isolation test skipped: prefab '" + prefabName + "' did not resolve.")); } return; } Vector3 val3 = ((Component)val).transform.position + ((Component)val).transform.forward * distance; GameObject val4 = Object.Instantiate(val2, val3, ((Component)val).transform.rotation); val4.SetActive(true); PlayAllSystems(val4); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogMessage((object)("[Y4NGZWeaponVfx] ISOLATION TEST prefab='" + prefabName + "' source=" + (WeaponVfxRuntimeAssets.SourceFor(prefabName) ?? "") + " " + $"distance={distance:F2}m unparented " + WeaponVfxDiagnostics.DescribeInstance(val4, val3))); } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogMessage((object)("[Y4NGZWeaponVfx] " + WeaponVfxDiagnostics.DescribeCameraRenderState())); } WeaponVfxDiagnostics.SampleAliveOverTime(val4, "isolation:" + prefabName); Cache.Track(val4, null, 6f); } private static void SetLayerRecursively(GameObject root, int layer) { if (!((Object)(object)root == (Object)null)) { root.layer = layer; for (int i = 0; i < root.transform.childCount; i++) { SetLayerRecursively(((Component)root.transform.GetChild(i)).gameObject, layer); } } } private static ParticleSystem[] PlayAllSystems(GameObject instance) { ParticleSystem[] componentsInChildren = instance.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!((Object)(object)componentsInChildren[i] == (Object)null)) { componentsInChildren[i].Clear(true); componentsInChildren[i].Play(true); } } return componentsInChildren; } internal static void RetireExpiredExternal() { if (Cache.LiveCount > 0) { Cache.RetireExpired(); } } internal static void StopAll() { Cache.StopAll(); } } internal sealed class WeaponPropAnimation : MonoBehaviour { private const string LogPrefix = "[Y4NGZPropAnim]"; private const string RestState = "Rest"; private const string FireState = "Fire"; private const string LockedState = "FireLocked"; private const string ReloadEmptyState = "ReloadEmpty"; private static readonly int RestHash = Animator.StringToHash("Rest"); private static readonly int FireHash = Animator.StringToHash("Fire"); private static readonly int LockedHash = Animator.StringToHash("FireLocked"); private static readonly int ReloadEmptyHash = Animator.StringToHash("ReloadEmpty"); private static readonly int[] ReloadRoundHashes = new int[5] { 0, Animator.StringToHash("Reload1"), Animator.StringToHash("Reload2"), Animator.StringToHash("Reload3"), Animator.StringToHash("Reload4") }; private Animator _animator; private float _fireLength = 0.05f; private bool _hasLocked; private bool _hasReloadEmpty; private readonly bool[] _hasReloadRounds = new bool[5]; private Coroutine _lockRoutine; internal static WeaponPropAnimation Attach(Y4NGZWeaponBase weapon) { if ((Object)(object)weapon == (Object)null) { return null; } Animator componentInChildren = ((Component)weapon).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { if (WeaponVfxDiagnostics.Once("propanim.none." + weapon.ConfigId)) { WeaponVfxDiagnostics.Emit("[Y4NGZPropAnim] '" + weapon.ConfigId + "' mounted no Animator. Expected when the model bundle is missing and the placeholder box is showing; a bug otherwise."); } return null; } WeaponPropAnimation weaponPropAnimation = ((Component)weapon).gameObject.AddComponent(); weaponPropAnimation._animator = componentInChildren; componentInChildren.cullingMode = (AnimatorCullingMode)0; RuntimeAnimatorController runtimeAnimatorController = componentInChildren.runtimeAnimatorController; if ((Object)(object)runtimeAnimatorController != (Object)null) { AnimationClip[] animationClips = runtimeAnimatorController.animationClips; foreach (AnimationClip val in animationClips) { if ((Object)(object)val != (Object)null && ((Object)val).name.EndsWith("_Fire", StringComparison.Ordinal)) { weaponPropAnimation._fireLength = Mathf.Max(0.01f, val.length); break; } } } weaponPropAnimation._hasLocked = componentInChildren.HasState(0, LockedHash); weaponPropAnimation._hasReloadEmpty = componentInChildren.HasState(0, ReloadEmptyHash); for (int j = 1; j <= 4; j++) { weaponPropAnimation._hasReloadRounds[j] = componentInChildren.HasState(0, ReloadRoundHashes[j]); } if (WeaponVfxDiagnostics.Once("propanim.attach." + weapon.ConfigId)) { WeaponVfxDiagnostics.Emit("[Y4NGZPropAnim] '" + weapon.ConfigId + "' animator on '" + ((Object)((Component)componentInChildren).gameObject).name + "' controller='" + (((Object)(object)runtimeAnimatorController != (Object)null) ? ((Object)runtimeAnimatorController).name : "NULL") + "' " + $"clips={(((Object)(object)runtimeAnimatorController != (Object)null) ? runtimeAnimatorController.animationClips.Length : 0)} " + $"hasRest={componentInChildren.HasState(0, RestHash)} hasFire={componentInChildren.HasState(0, FireHash)} " + $"hasLocked={weaponPropAnimation._hasLocked} hasReloadEmpty={weaponPropAnimation._hasReloadEmpty} " + $"reloadRounds={weaponPropAnimation.CountReloadRoundStates()}/4 " + $"fireLength={weaponPropAnimation._fireLength:F3}s."); } return weaponPropAnimation; } internal void PlayFire(bool lockSlideBack) { if (!((Object)(object)_animator == (Object)null)) { CancelPendingLock(); _animator.Play(FireHash, 0, 0f); if (lockSlideBack && _hasLocked) { _lockRoutine = ((MonoBehaviour)this).StartCoroutine(LockAfterFire()); } } } internal void PlayReload(bool wasEmpty, int roundsDrawn) { if ((Object)(object)_animator == (Object)null) { return; } CancelPendingLock(); if (wasEmpty && _hasReloadEmpty) { _animator.Play(ReloadEmptyHash, 0, 0f); return; } int num = Mathf.Clamp(roundsDrawn, 1, 4); if (_hasReloadRounds[num]) { _animator.Play(ReloadRoundHashes[num], 0, 0f); } } internal void PlayRest() { if (!((Object)(object)_animator == (Object)null)) { CancelPendingLock(); _animator.Play(RestHash, 0, 0f); } } private IEnumerator LockAfterFire() { yield return (object)new WaitForSeconds(_fireLength); _lockRoutine = null; if ((Object)(object)_animator != (Object)null) { _animator.Play(LockedHash, 0, 0f); } } private void CancelPendingLock() { if (_lockRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_lockRoutine); _lockRoutine = null; } } private int CountReloadRoundStates() { int num = 0; for (int i = 1; i <= 4; i++) { if (_hasReloadRounds[i]) { num++; } } return num; } } internal static class WeaponRecoil { private static Camera _driverCamera; private static WeaponRecoilDriver _driver; internal static WeaponRecoilDriver ActiveDriver { get { if (!((Object)(object)_driver != (Object)null)) { return null; } return _driver; } } internal static void ApplyKick(PlayerControllerB player, WeaponConfig config) { if (!((Object)(object)player == (Object)null) && config != null && !((Object)(object)player != (Object)(object)GameNetworkManager.Instance?.localPlayerController)) { WeaponRecoilDriver weaponRecoilDriver = EnsureDriver(player); if (!((Object)(object)weaponRecoilDriver == (Object)null)) { float pitchDegrees = 0f - Mathf.Abs(config.RecoilPitchDegrees); float yawDegrees = Random.Range(-1f, 1f) * config.RecoilYawDegrees; weaponRecoilDriver.AddKick(pitchDegrees, yawDegrees, config.RecoilRecoverySpeed, Mathf.Clamp01(config.RecoilPermanentClimbFraction)); } } } internal static WeaponRecoilDriver EnsureDriver(PlayerControllerB player) { Camera val = player?.gameplayCamera; if ((Object)(object)val == (Object)null) { return null; } if ((Object)(object)_driver != (Object)null && (Object)(object)_driverCamera == (Object)(object)val) { return _driver; } _driverCamera = val; _driver = ((Component)val).GetComponent(); if ((Object)(object)_driver == (Object)null) { _driver = ((Component)val).gameObject.AddComponent(); } return _driver; } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] internal static class WeaponRecoilDriverBootstrap { [HarmonyPostfix] private static void PostPlayerUpdate(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance?.localPlayerController)) { WeaponRecoil.EnsureDriver(__instance); } } } internal sealed class WeaponRecoilDriver : MonoBehaviour { private enum JanitorState { Unknown, ConfigDisabled, CameraUnavailable, KickActive, SessionActive, ParkourActive, ParkourCooldown, SpecialInteractActive, SpecialInteractCooldown, WithinEpsilon, BeyondSafetyCap, Healing } private const float KickCompleteEpsilonDegrees = 0.01f; private const float ResidueEpsilonDegrees = 0.05f; private const float ResidueIndividualLogThresholdDegrees = 1f; private const float ResidueSafetyCapDegrees = 10f; private const float ResidueHealingSpeed = 8f; private const float ParkourCooldownSeconds = 0.75f; private const float SpecialInteractCooldownSeconds = 0.75f; private const float SuppressedHealSummaryIntervalSeconds = 60f; private static bool _cameraUpFieldResolved; private static FieldInfo _cameraUpField; private Vector2 _kick; private float _recoverySpeed = 8f; private bool _kickActive; private float _accumulatedClimb; private JanitorState _janitorState; private bool _currentHealLogged; private float _parkourCooldownUntil; private float _specialInteractCooldownUntil; private int _suppressedMicroHealCount; private float _suppressedMicroHealMaxResidue; private float _nextSuppressedHealSummaryAt; internal float PendingKickDegrees => ((Vector2)(ref _kick)).magnitude; internal float AccumulatedClimbDegrees => _accumulatedClimb; internal void AddKick(float pitchDegrees, float yawDegrees, float recoverySpeed, float permanentFraction) { if (ApplyLookDelta(pitchDegrees, yawDegrees)) { _kick.x += pitchDegrees * (1f - permanentFraction); _kick.y += yawDegrees; _accumulatedClimb += Mathf.Abs(pitchDegrees) * permanentFraction; _recoverySpeed = Mathf.Max(0.5f, recoverySpeed); _kickActive = true; } } private void LateUpdate() { //IL_0067: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!UpdateSpecialInteractSettle() && _kickActive) { if (((Vector2)(ref _kick)).sqrMagnitude < 0.0001f) { ApplyLookDelta(0f - _kick.x, 0f - _kick.y); _kick = Vector2.zero; _kickActive = false; _accumulatedClimb = 0f; } else { Vector2 val = Vector2.Lerp(_kick, Vector2.zero, 1f - Mathf.Exp((0f - _recoverySpeed) * Time.deltaTime)); ApplyLookDelta(val.x - _kick.x, val.y - _kick.y); _kick = val; } } TickResidueJanitor(); } private bool UpdateSpecialInteractSettle() { //IL_008e: 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) PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || (Object)(object)val.gameplayCamera == (Object)null || (Object)(object)((Component)val.gameplayCamera).transform != (Object)(object)((Component)this).transform) { return false; } if (!val.isClimbingLadder && !val.inSpecialInteractAnimation) { return false; } _specialInteractCooldownUntil = Time.unscaledTime + 0.75f; if (_kickActive) { ApplyLookDelta(0f - _kick.x, 0f - _kick.y); } _kick = Vector2.zero; _kickActive = false; _accumulatedClimb = 0f; return true; } private bool ApplyLookDelta(float pitchDelta, float yawDelta) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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) PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || (Object)(object)val.gameplayCamera == (Object)null || (Object)(object)((Component)val.gameplayCamera).transform != (Object)(object)((Component)this).transform) { return false; } ResolveCameraUpField(); if (_cameraUpField == null) { return false; } float num; try { num = (float)_cameraUpField.GetValue(val); } catch { return false; } float num2 = Mathf.Clamp(num + pitchDelta, -80f, 80f); try { _cameraUpField.SetValue(val, num2); } catch { return false; } Vector3 localEulerAngles = ((Component)this).transform.localEulerAngles; localEulerAngles.x = num2; ((Component)this).transform.localEulerAngles = localEulerAngles; if (!Mathf.Approximately(yawDelta, 0f)) { (((Object)(object)val.thisPlayerBody != (Object)null) ? val.thisPlayerBody : ((Component)val).transform).Rotate(0f, yawDelta, 0f, (Space)0); } return true; } private static void ResolveCameraUpField() { if (_cameraUpFieldResolved) { return; } _cameraUpFieldResolved = true; _cameraUpField = typeof(PlayerControllerB).GetField("cameraUp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (_cameraUpField == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Y4NGZWeapons.recoil] PlayerControllerB.cameraUp not found; recoil kicks disabled."); } } } private void TickResidueJanitor() { //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_000c: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) Vector3 localEulerAngles = ((Component)this).transform.localEulerAngles; float num = SignedAngle(localEulerAngles.y); float num2 = SignedAngle(localEulerAngles.z); FlushSuppressedMicroHealSummaryIfDue(); ConfigEntry weaponsCameraResidueJanitor = Plugin.WeaponsCameraResidueJanitor; if (weaponsCameraResidueJanitor != null && !weaponsCameraResidueJanitor.Value) { LogJanitorSkip(JanitorState.ConfigDisabled, "config_disabled", num, num2); return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || (Object)(object)val.gameplayCamera == (Object)null || (Object)(object)((Component)val.gameplayCamera).transform != (Object)(object)((Component)this).transform) { LogJanitorSkip(JanitorState.CameraUnavailable, "camera_unavailable", num, num2); return; } if (val.isClimbingLadder || val.inSpecialInteractAnimation) { _specialInteractCooldownUntil = Time.unscaledTime + 0.75f; LogJanitorSkip(JanitorState.SpecialInteractActive, "special_interact_active", num, num2); return; } if (Time.unscaledTime < _specialInteractCooldownUntil) { LogJanitorSkip(JanitorState.SpecialInteractCooldown, "special_interact_cooldown", num, num2); return; } if (SlideAnimationBridge.IsActive(val)) { _parkourCooldownUntil = Time.unscaledTime + 0.75f; LogJanitorSkip(JanitorState.ParkourActive, "parkour_active", num, num2); return; } if (Time.unscaledTime < _parkourCooldownUntil) { LogJanitorSkip(JanitorState.ParkourCooldown, "parkour_cooldown", num, num2); return; } if (_kickActive) { LogJanitorSkip(JanitorState.KickActive, "kick_active", num, num2); return; } InteractionAnimationHandle val2 = default(InteractionAnimationHandle); if (LCInteractionAnimationAPI.TryGetActiveInteraction(val, (InteractionAnimationPresentationKind)1, ref val2) || LCInteractionAnimationAPI.TryGetActiveInteraction(val, (InteractionAnimationPresentationKind)0, ref val2)) { LogJanitorSkip(JanitorState.SessionActive, "session_active", num, num2); return; } float num3 = Mathf.Max(Mathf.Abs(num), Mathf.Abs(num2)); if (num3 <= 0.05f) { if (_janitorState == JanitorState.Healing) { ((Component)this).transform.localEulerAngles = new Vector3(localEulerAngles.x, 0f, 0f); LogCurrentHealComplete(num, num2); _janitorState = JanitorState.WithinEpsilon; } else { LogJanitorSkip(JanitorState.WithinEpsilon, "within_epsilon", num, num2); } return; } if (num3 >= 10f) { LogJanitorSkip(JanitorState.BeyondSafetyCap, "beyond_safety_cap", num, num2); return; } if (_janitorState != JanitorState.Healing) { _currentHealLogged = num3 > 1f; if (_currentHealLogged) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.recoil] camera residue janitor healing started " + $"localY={num:0.0000} localZ={num2:0.0000}")); } } else { RecordSuppressedMicroHeal(num3); } _janitorState = JanitorState.Healing; } float num4 = 1f - Mathf.Exp(-8f * Time.deltaTime); float num5 = Mathf.Lerp(num, 0f, num4); float num6 = Mathf.Lerp(num2, 0f, num4); if (Mathf.Max(Mathf.Abs(num5), Mathf.Abs(num6)) <= 0.05f) { ((Component)this).transform.localEulerAngles = new Vector3(localEulerAngles.x, 0f, 0f); LogCurrentHealComplete(num5, num6); _janitorState = JanitorState.WithinEpsilon; } else { ((Component)this).transform.localEulerAngles = new Vector3(localEulerAngles.x, num5, num6); } } private void LogCurrentHealComplete(float yaw, float roll) { if (_currentHealLogged) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.recoil] camera residue janitor healing complete " + $"gate=within_epsilon localY={yaw:0.0000} localZ={roll:0.0000}")); } } _currentHealLogged = false; } private void RecordSuppressedMicroHeal(float startingResidue) { if (_suppressedMicroHealCount == 0) { _nextSuppressedHealSummaryAt = Time.unscaledTime + 60f; } _suppressedMicroHealCount++; _suppressedMicroHealMaxResidue = Mathf.Max(_suppressedMicroHealMaxResidue, startingResidue); } private void FlushSuppressedMicroHealSummaryIfDue() { if (_suppressedMicroHealCount != 0 && !(Time.unscaledTime < _nextSuppressedHealSummaryAt)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.recoil] camera residue janitor suppressed micro-heal summary " + $"count={_suppressedMicroHealCount} " + $"maxResidue={_suppressedMicroHealMaxResidue:0.0000}")); } _suppressedMicroHealCount = 0; _suppressedMicroHealMaxResidue = 0f; _nextSuppressedHealSummaryAt = 0f; } } private void LogJanitorSkip(JanitorState state, string reason, float yaw, float roll) { if (_janitorState != state) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons.recoil] camera residue janitor skip=" + reason + " " + $"localY={yaw:0.0000} localZ={roll:0.0000}")); } _currentHealLogged = false; _janitorState = state; } } private static float SignedAngle(float degrees) { return Mathf.DeltaAngle(0f, degrees); } private void OnDisable() { //IL_0028: 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) if (_kickActive) { ApplyLookDelta(0f - _kick.x, 0f - _kick.y); } _kick = Vector2.zero; _kickActive = false; _accumulatedClimb = 0f; _janitorState = JanitorState.Unknown; _currentHealLogged = false; _parkourCooldownUntil = 0f; _specialInteractCooldownUntil = 0f; _suppressedMicroHealCount = 0; _suppressedMicroHealMaxResidue = 0f; _nextSuppressedHealSummaryAt = 0f; } } internal static class WeaponRegistry { private static readonly Dictionary Prefabs = new Dictionary(); private static readonly Dictionary Items = new Dictionary(); private static readonly List PrefabHolders = new List(); private static bool _registered; private const string DisabledNameTag = " [disabled by Y4NGZ]"; internal static GameObject HeavyShotgunPrefab => WeaponRuntimeRegistry.PrefabFor("heavy_shotgun"); internal static Item HeavyShotgunItem => WeaponRuntimeRegistry.ItemFor("heavy_shotgun"); internal static int RegisteredCount => Prefabs.Count; internal static GameObject PrefabFor(string configId) { if (!Prefabs.TryGetValue(configId ?? string.Empty, out var value)) { return null; } return value; } internal static Item ItemFor(string configId) { if (!Items.TryGetValue(configId ?? string.Empty, out var value)) { return null; } return value; } internal static bool TryRegisterAll() { if (_registered) { WeaponSoundRegistry.TryApplyAll(); return true; } Item val = FindVanillaShotgunItem(); if ((Object)(object)val == (Object)null || (Object)(object)val.spawnPrefab == (Object)null) { return false; } try { NetworkManager singleton = NetworkManager.Singleton; foreach (WeaponConfig config in WeaponCatalog.All()) { if (!ArmoryContentConfig.IsWeaponEnabled(config.Id)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons] " + config.DisplayName + " is disabled in config; not registering it.")); } continue; } BuildAndRegister(config, val, delegate(GameObject prefab) { Prefabs[config.Id] = prefab; }, delegate(Item item) { Items[config.Id] = item; }); GameObject val2 = PrefabFor(config.Id); uint num = (((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent() != (Object)null) ? val2.GetComponent().GlobalObjectIdHash : 0u); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)($"[Y4NGZWeapons] Registered {config.DisplayName} clone (hash={num}, " + $"NetworkManager.IsListening={((singleton != null) ? new bool?(singleton.IsListening) : ((bool?)null))}). If IsListening=True the host already " + "started — a runtime-registered network prefab may not replicate to clients.")); } } _registered = true; WeaponSoundRegistry.TryApplyAll(); WeaponAccuracy.LogCosmeticSpreadWeapons(); return true; } catch (Exception arg) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)$"[Y4NGZWeapons] Weapon registration failed: {arg}"); } return false; } } private static void BuildAndRegister(WeaponConfig config, Item vanillaShotgun, Action storePrefab, Action storeItem) { GameObject val = CloneInactive(vanillaShotgun.spawnPrefab, "Y4NGZ_" + config.Id + "_Prefab"); AssignStableNetworkHash(val.GetComponent(), config.Id); val.AddComponent().ConfigId = config.Id; ShotgunItem component = val.GetComponent(); Item val2 = Object.Instantiate(vanillaShotgun); Sprite val3 = WeaponAssetLoader.LoadIconSprite(config.Id); if ((Object)(object)val3 != (Object)null) { val2.itemIcon = val3; } ((Object)val2).name = "Y4NGZ_" + config.Id + "_Item"; val2.itemName = config.DisplayName; val2.creditsWorth = config.CreditsWorth; val2.minValue = config.CreditsWorth; val2.maxValue = config.CreditsWorth; val2.spawnPrefab = val; ((Object)val2).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val2); if ((Object)(object)component != (Object)null) { ((GrabbableObject)component).itemProperties = val2; } ConfigureScanMetadata(val, config); if (config.FireMode == WeaponFireMode.ContinuousStream) { val2.holdButtonUse = true; val2.syncUseFunction = true; val2.syncInteractLRFunction = true; val2.saveItemVariable = true; val2.weight = config.Weight; val2.twoHanded = config.TwoHanded; val2.twoHandedAnimation = config.TwoHandedAnimation; val2.toolTips = new string[2] { "Fire : [LMB]", WeaponReloadInput.Tooltip("Reload fuel") }; val.AddComponent(); component.safetyOn = true; component.hasHitGroundWithSafetyOff = false; ((GrabbableObject)component).useCooldown = 0f; ((GrabbableObject)component).currentUseCooldown = 0f; } else if (config.Id == "grenade_launcher") { val2.holdButtonUse = false; val2.syncUseFunction = true; val2.syncInteractLRFunction = true; val2.saveItemVariable = true; val2.weight = config.Weight; val2.twoHanded = config.TwoHanded; val2.twoHandedAnimation = config.TwoHandedAnimation; val2.toolTips = new string[3] { "Fire grenade : [LMB]", WeaponReloadInput.Tooltip("Reload grenades"), "Turn safety off : [Q]" }; component.safetyOn = true; component.hasHitGroundWithSafetyOff = false; ((GrabbableObject)component).useCooldown = config.FireCooldownSeconds; ((GrabbableObject)component).currentUseCooldown = 0f; } WeaponVisuals.Apply(config.Id, val, component); DawnLibCompat.FixMixerGroups(val); DawnLibCompat.RegisterNetworkPrefab(val); string weaponId = config.Id; DawnLibCompat.RegisterItem(weaponId, val2, () => ArmoryContentConfig.IsWeaponPurchasable(weaponId), () => ArmoryContentConfig.WeaponShopPrice(weaponId, config.CreditsWorth), config.ShopDescription, () => ArmoryContentConfig.WeaponInteriorWeight(weaponId)); storePrefab(val); storeItem(val2); } private static void ConfigureScanMetadata(GameObject clone, WeaponConfig config) { if ((Object)(object)clone == (Object)null || config == null) { return; } ScanNodeProperties[] componentsInChildren = clone.GetComponentsInChildren(true); foreach (ScanNodeProperties val in componentsInChildren) { val.headerText = config.DisplayName; if (config.FireMode == WeaponFireMode.ContinuousStream) { val.subText = "Fuel tank weapon"; } else if (config.Id == "grenade_launcher") { val.subText = "Six-shot explosive launcher"; } } } private static GameObject CloneInactive(GameObject source, string name) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown GameObject val = new GameObject(name + "_InactiveHolder"); ((Object)val).hideFlags = (HideFlags)61; val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); GameObject obj = Object.Instantiate(source, val.transform); ((Object)obj).name = name; ((Object)obj).hideFlags = (HideFlags)0; obj.SetActive(true); PrefabHolders.Add(val); return obj; } private static Item FindVanillaShotgunItem() { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.allItemsList != (Object)null && instance.allItemsList.itemsList != null) { foreach (Item items in instance.allItemsList.itemsList) { if ((Object)(object)items != (Object)null && (Object)(object)items.spawnPrefab != (Object)null && (Object)(object)items.spawnPrefab.GetComponent() != (Object)null) { return items; } } } ShotgunItem[] array = Resources.FindObjectsOfTypeAll(); foreach (ShotgunItem val in array) { if (!((Object)(object)val == (Object)null) && (Object)(object)((GrabbableObject)val).itemProperties != (Object)null && (Object)(object)((GrabbableObject)val).itemProperties.spawnPrefab != (Object)null) { Scene scene = ((Component)val).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return ((GrabbableObject)val).itemProperties; } } } return null; } private static void AssignStableNetworkHash(NetworkObject networkObject, string id) { if ((Object)(object)networkObject == (Object)null) { return; } try { uint num; using (MD5 mD = MD5.Create()) { num = BitConverter.ToUInt32(mD.ComputeHash(Encoding.UTF8.GetBytes("com.y4ngz.betterarmory.Weapon." + id)), 0); } (typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic))?.SetValue(networkObject, num); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Failed to assign network hash for " + id + ": " + ex.Message)); } } } internal static void DisableConflictingItems() { if (Plugin.WeaponsDisableConflictingItems != null && !Plugin.WeaponsDisableConflictingItems.Value) { return; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.allItemsList == (Object)null || instance.allItemsList.itemsList == null) { return; } foreach (WeaponConfig item in WeaponCatalog.AllRegistered()) { foreach (Item items in instance.allItemsList.itemsList) { if (!((Object)(object)items == (Object)null) && !string.IsNullOrEmpty(items.itemName) && !items.itemName.EndsWith(" [disabled by Y4NGZ]", StringComparison.Ordinal) && string.Equals(items.itemName.Trim(), item.DisplayName, StringComparison.OrdinalIgnoreCase) && !((Object)(object)items == (Object)(object)WeaponRuntimeRegistry.ItemFor(item.Id)) && (!((Object)(object)items.spawnPrefab != (Object)null) || (!((Object)(object)items.spawnPrefab.GetComponent() != (Object)null) && !((Object)(object)items.spawnPrefab.GetComponent() != (Object)null)))) { DisableForeignItem(instance, items, item); } } } } private static void DisableForeignItem(StartOfRound round, Item item, WeaponConfig config) { int num = 0; if (round.levels != null) { SelectableLevel[] levels = round.levels; foreach (SelectableLevel val in levels) { if (!((Object)(object)val == (Object)null) && val.spawnableScrap != null) { num += val.spawnableScrap.RemoveAll((SpawnableItemWithRarity entry) => entry != null && (Object)(object)entry.spawnableItem == (Object)(object)item); } } } bool flag = false; Terminal val2 = Object.FindObjectOfType(); if ((Object)(object)val2 != (Object)null && val2.buyableItemsList != null) { Item[] buyableItemsList = val2.buyableItemsList; for (int i = 0; i < buyableItemsList.Length; i++) { if ((Object)(object)buyableItemsList[i] == (Object)(object)item) { flag = true; break; } } } string itemName = item.itemName; item.itemName = itemName + " [disabled by Y4NGZ]"; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Foreign item '" + itemName + "' (asset '" + ((Object)item).name + "', prefab '" + (((Object)(object)item.spawnPrefab != (Object)null) ? ((Object)item.spawnPrefab).name : "null") + "') collides with our " + $"{config.DisplayName} — renamed to '{item.itemName}', removed {num} scrap-pool " + "entr" + ((num == 1) ? "y" : "ies") + (flag ? "; NOTE: it is also a terminal shop item (left buyable — index-coupled)" : string.Empty) + ".")); } } internal static void DebugSpawnHeavyShotgunAtLocalPlayer() { WeaponRuntimeRegistry.DebugSpawnAtLocalPlayer(WeaponCatalog.HeavyShotgun); } internal static void DebugSpawnWeaponAtLocalPlayer(WeaponConfig config) { //IL_00b4: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) if (config == null) { return; } if (config.Native) { NativeWeaponRegistry.DebugSpawnAtLocalPlayer(config); return; } GameObject val = (TryRegisterAll() ? PrefabFor(config.Id) : null); if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Debug spawn skipped: " + config.DisplayName + " not registered yet.")); } return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Y4NGZWeapons] Debug spawn requires being the host."); } return; } PlayerControllerB val2 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); Vector3 val3 = (((Object)(object)val2 != (Object)null) ? (((Component)val2).transform.position + ((Component)val2).transform.forward * 1.4f + Vector3.up * 0.6f) : Vector3.up); GameObject val4 = Object.Instantiate(val, val3, Quaternion.identity); val4.SetActive(true); NetworkObject component = val4.GetComponent(); if ((Object)(object)component == (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)"[Y4NGZWeapons] Debug spawn failed: clone has no NetworkObject."); } Object.Destroy((Object)(object)val4); return; } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)($"[Y4NGZWeapons] Debug spawn: IsServer={singleton.IsServer} " + $"IsListening={singleton.IsListening} hash={component.GlobalObjectIdHash} at {val3}")); } try { component.Spawn(false); } catch (Exception arg) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogError((object)("[Y4NGZWeapons] NetworkObject.Spawn() threw — the clone is likely " + $"not on the NetworkManager's registered prefab list (registration timing). {arg}")); } Object.Destroy((Object)(object)val4); return; } ShotgunItem component2 = val4.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.shellsLoaded = config.MagazineSize; } int num = ((Plugin.WeaponsDevGrantShells != null) ? Plugin.WeaponsDevGrantShells.Value : 0); if (config.AmmoType == WeaponAmmoType.Fuel && num > 0) { num = Math.Max(num, 200); } if (num > 0 && AmmoReserve.Get(config.AmmoType) <= 0) { AmmoReserve.Set(config.AmmoType, num); ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogInfo((object)$"[Y4NGZWeapons] Dev-granted {num} rounds ({config.AmmoType}) to the reserve."); } } Plugin.ReloadWeaponVisualConfig(); WeaponVisuals.RetuneInstance(val4); ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogInfo((object)("[Y4NGZWeapons] Debug-spawned a " + config.DisplayName + " near the local player.")); } } } internal static class WeaponReloadInput { internal const string DefaultBindingPath = "/r"; private const string FallbackKeyLabel = "R"; private static bool _dispatching; private static InputAction Action => Plugin.Keybinds?.ReloadWeapon; internal static bool AcceptRightInteractReload { get { if (!_dispatching) { return Action == null; } return true; } } internal static string KeyLabel { get { //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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) try { InputAction action = Action; if (action == null || action.bindings.Count == 0) { return "R"; } InputBinding val = action.bindings[0]; string effectivePath = ((InputBinding)(ref val)).effectivePath; if (string.IsNullOrEmpty(effectivePath)) { return "R"; } int num = effectivePath.LastIndexOf('/'); string text = ((num >= 0 && num < effectivePath.Length - 1) ? effectivePath.Substring(num + 1) : effectivePath); return string.IsNullOrEmpty(text) ? "R" : text.ToUpperInvariant(); } catch (Exception) { return "R"; } } } internal static string Tooltip(string verb) { return verb + " : [" + KeyLabel + "]"; } internal static void ApplyReloadTooltips(string[] tips) { if (tips == null) { return; } for (int i = 0; i < tips.Length; i++) { string text = tips[i]; if (!string.IsNullOrEmpty(text) && text.StartsWith("Reload", StringComparison.Ordinal)) { int num = text.IndexOf(" : ", StringComparison.Ordinal); if (num > 0) { tips[i] = Tooltip(text.Substring(0, num)); } } } } internal static void OnReloadPerformed(CallbackContext context) { try { if (!((CallbackContext)(ref context)).performed) { return; } PlayerControllerB val = StartOfRound.Instance?.localPlayerController ?? GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsOwner || !val.isPlayerControlled || (((NetworkBehaviour)val).IsServer && !val.isHostPlayerObject) || !val.equippedUsableItemQE || val.isGrabbingObjectAnimation || val.isTypingChat || val.inTerminalMenu || val.inSpecialInteractAnimation || val.throwingObject || val.timeSinceSwitchingSlots < 0.2f) { return; } GrabbableObject currentlyHeldObjectServer = val.currentlyHeldObjectServer; if ((Object)(object)currentlyHeldObjectServer == (Object)null || ((Component)currentlyHeldObjectServer).GetComponent() == null) { return; } val.timeSinceSwitchingSlots = 0f; _dispatching = true; try { currentlyHeldObjectServer.ItemInteractLeftRightOnClient(true); } finally { _dispatching = false; } } catch (Exception arg) { _dispatching = false; ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons] Reload keybind dispatch threw: {arg}"); } } } } internal static class WeaponRuntimeRegistry { internal static bool TryRegisterAll() { bool num = WeaponRegistry.TryRegisterAll(); bool flag = NativeWeaponRegistry.TryRegisterAll(); return num && flag; } internal static GameObject PrefabFor(string configId) { WeaponConfig weaponConfig = ExactConfig(configId); if (weaponConfig == null) { return null; } if (!weaponConfig.Native) { return WeaponRegistry.PrefabFor(weaponConfig.Id); } return NativeWeaponRegistry.PrefabFor(weaponConfig.Id); } internal static Item ItemFor(string configId) { WeaponConfig weaponConfig = ExactConfig(configId); if (weaponConfig == null) { return null; } if (!weaponConfig.Native) { return WeaponRegistry.ItemFor(weaponConfig.Id); } return NativeWeaponRegistry.ItemFor(weaponConfig.Id); } internal static void DebugSpawnAtLocalPlayer(WeaponConfig config) { if (config != null) { if (config.Native) { NativeWeaponRegistry.DebugSpawnAtLocalPlayer(config); } else { WeaponRegistry.DebugSpawnWeaponAtLocalPlayer(config); } } } private static WeaponConfig ExactConfig(string configId) { if (string.IsNullOrEmpty(configId)) { return null; } WeaponConfig weaponConfig = WeaponCatalog.ById(configId); if (weaponConfig == null || !string.Equals(weaponConfig.Id, configId, StringComparison.Ordinal)) { return null; } return weaponConfig; } } internal static class WeaponSoundRegistry { private sealed class WeaponSoundSet { public string ConfigId; public string Label; public string[] FireFiles = Array.Empty(); public string NoAmmoFile; public string ReloadStartFile; public string ReloadFinishFile; public string ReloadStageLoopFile; public string DropFile; public AudioClip[] FireClips; public AudioClip NoAmmoClip; public AudioClip ReloadStartClip; public AudioClip ReloadFinishClip; public AudioClip ReloadStageLoopClip; public AudioClip DropClip; public bool HasAnyClip { get { if ((FireClips == null || FireClips.Length == 0) && !((Object)(object)NoAmmoClip != (Object)null) && !((Object)(object)ReloadStartClip != (Object)null) && !((Object)(object)ReloadFinishClip != (Object)null) && !((Object)(object)ReloadStageLoopClip != (Object)null)) { return (Object)(object)DropClip != (Object)null; } return true; } } } private static readonly WeaponSoundSet[] Sets = new WeaponSoundSet[5] { new WeaponSoundSet { ConfigId = "heavy_shotgun", Label = "Heavy Shotgun", FireFiles = new string[2] { "shotgun_fire_ufx_1.ogg", "shotgun_fire_ufx_2.ogg" }, NoAmmoFile = "shotgun_no_ammo.ogg", ReloadStartFile = "shotgun_reloading_slug_in_ufx_2.ogg", ReloadFinishFile = "shotgun_racking_ufx_3.ogg", DropFile = "firearm_drop_ufx_1.ogg" }, new WeaponSoundSet { ConfigId = "revolver", Label = "Revolver", FireFiles = new string[1] { "revolver_fire_ufx_1.ogg" }, NoAmmoFile = "pistol_universal_empty_barrel_ufx_1.ogg", ReloadStartFile = "revolver_reload_barrel_out.ogg", ReloadFinishFile = "revolver_reload_barrel_in.ogg", ReloadStageLoopFile = "revolver_reload_round_in.ogg", DropFile = "firearm_drop_ufx_5.ogg" }, new WeaponSoundSet { ConfigId = "mx16a4", Label = "MX16A4", DropFile = "firearm_drop_ufx_1.ogg" }, new WeaponSoundSet { ConfigId = "kar98k", Label = "Kar98K", DropFile = "firearm_drop_ufx_1.ogg" }, new WeaponSoundSet { ConfigId = "x18", Label = "X18", DropFile = "firearm_drop_ufx_5.ogg" } }; private static readonly Dictionary ClipCache = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet MissingWarned = new HashSet(StringComparer.OrdinalIgnoreCase); private static bool _loadStarted; private static int _decodedRevision; private static int _sweptRevision = -1; internal static void TryApplyAll() { try { ApplyToRegisteredItems(); TryBeginLoad(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Weapon sound apply failed safely; keeping vanilla shotgun audio: " + ex.Message)); } } } internal static void ApplyToInstance(ShotgunItem shotgun) { try { if ((Object)(object)shotgun == (Object)null) { return; } Y4NGZWeaponItem component = ((Component)shotgun).GetComponent(); if ((Object)(object)component == (Object)null) { return; } WeaponSoundSet weaponSoundSet = SetFor(component.ConfigId); if (weaponSoundSet != null && weaponSoundSet.HasAnyClip) { ApplyClips(shotgun, weaponSoundSet); if ((Object)(object)weaponSoundSet.DropClip != (Object)null && (Object)(object)((GrabbableObject)shotgun).itemProperties != (Object)null) { ((GrabbableObject)shotgun).itemProperties.dropSFX = weaponSoundSet.DropClip; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Weapon sound instance apply failed safely: " + ex.Message)); } } } internal static void ApplyToInstance(Y4NGZWeaponBase weapon) { try { if ((Object)(object)weapon == (Object)null) { return; } WeaponSoundSet weaponSoundSet = SetFor(weapon.ConfigId); if (weaponSoundSet != null && weaponSoundSet.HasAnyClip) { ApplyClips(weapon, weaponSoundSet); if ((Object)(object)weaponSoundSet.DropClip != (Object)null && (Object)(object)((GrabbableObject)weapon).itemProperties != (Object)null) { ((GrabbableObject)weapon).itemProperties.dropSFX = weaponSoundSet.DropClip; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Native weapon sound instance apply failed safely: " + ex.Message)); } } } private static WeaponSoundSet SetFor(string configId) { if (string.IsNullOrWhiteSpace(configId)) { return null; } WeaponSoundSet[] sets = Sets; foreach (WeaponSoundSet weaponSoundSet in sets) { if (string.Equals(weaponSoundSet.ConfigId, configId, StringComparison.OrdinalIgnoreCase)) { return weaponSoundSet; } } return null; } private static void ApplyToRegisteredItems() { WeaponSoundSet[] sets = Sets; foreach (WeaponSoundSet weaponSoundSet in sets) { if (!weaponSoundSet.HasAnyClip) { continue; } try { Item val = WeaponRuntimeRegistry.ItemFor(weaponSoundSet.ConfigId); if ((Object)(object)val != (Object)null && (Object)(object)weaponSoundSet.DropClip != (Object)null) { val.dropSFX = weaponSoundSet.DropClip; } GameObject val2 = WeaponRuntimeRegistry.PrefabFor(weaponSoundSet.ConfigId); if ((Object)(object)val2 != (Object)null) { ApplyClips(val2.GetComponent(), weaponSoundSet); ApplyClips(val2.GetComponent(), weaponSoundSet); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] " + weaponSoundSet.Label + " sound apply to the registered template failed: " + ex.Message)); } } } if (_sweptRevision == _decodedRevision) { return; } try { Y4NGZWeaponItem[] array = Resources.FindObjectsOfTypeAll(); foreach (Y4NGZWeaponItem y4NGZWeaponItem in array) { if (!((Object)(object)y4NGZWeaponItem == (Object)null)) { WeaponSoundSet weaponSoundSet2 = SetFor(y4NGZWeaponItem.ConfigId); if (weaponSoundSet2 != null && weaponSoundSet2.HasAnyClip) { ApplyClips(y4NGZWeaponItem.Shotgun, weaponSoundSet2); } } } Y4NGZWeaponBase[] array2 = Resources.FindObjectsOfTypeAll(); foreach (Y4NGZWeaponBase y4NGZWeaponBase in array2) { if ((Object)(object)y4NGZWeaponBase == (Object)null) { continue; } WeaponSoundSet weaponSoundSet3 = SetFor(y4NGZWeaponBase.ConfigId); if (weaponSoundSet3 != null && weaponSoundSet3.HasAnyClip) { ApplyClips(y4NGZWeaponBase, weaponSoundSet3); if ((Object)(object)weaponSoundSet3.DropClip != (Object)null && (Object)(object)((GrabbableObject)y4NGZWeaponBase).itemProperties != (Object)null) { ((GrabbableObject)y4NGZWeaponBase).itemProperties.dropSFX = weaponSoundSet3.DropClip; } } } _sweptRevision = _decodedRevision; } catch (Exception ex2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons] Weapon sound sweep over spawned instances failed safely: " + ex2.Message)); } } } private static void ApplyClips(ShotgunItem shotgun, WeaponSoundSet set) { if (!((Object)(object)shotgun == (Object)null) && set != null) { if (set.FireClips != null && set.FireClips.Length != 0) { shotgun.gunShootSFX = set.FireClips; } if ((Object)(object)set.NoAmmoClip != (Object)null) { shotgun.noAmmoSFX = set.NoAmmoClip; } if ((Object)(object)set.ReloadStartClip != (Object)null) { shotgun.gunReloadSFX = set.ReloadStartClip; } if ((Object)(object)set.ReloadFinishClip != (Object)null) { shotgun.gunReloadFinishSFX = set.ReloadFinishClip; } } } private static void ApplyClips(Y4NGZWeaponBase weapon, WeaponSoundSet set) { if (!((Object)(object)weapon == (Object)null) && set != null) { if (set.FireClips != null && set.FireClips.Length != 0) { weapon.FireClips = set.FireClips; weapon.ApplyAuthoredGainToFireClips = false; } if ((Object)(object)set.NoAmmoClip != (Object)null) { weapon.DryFireClip = set.NoAmmoClip; } if ((Object)(object)set.ReloadStartClip != (Object)null) { weapon.ReloadStartClip = set.ReloadStartClip; } if ((Object)(object)set.ReloadFinishClip != (Object)null) { weapon.ReloadFinishClip = set.ReloadFinishClip; } if ((Object)(object)set.ReloadStageLoopClip != (Object)null) { weapon.ReloadStageStartClip = set.ReloadStartClip; weapon.ReloadStageLoopClip = set.ReloadStageLoopClip; weapon.ReloadStageEndClip = set.ReloadFinishClip; } } } private static void TryBeginLoad() { try { if (_loadStarted) { return; } string text = WeaponAssetLoader.AssetDirectory(); if (string.IsNullOrWhiteSpace(text)) { _loadStarted = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Y4NGZWeapons] WeaponAssets directory is unavailable; weapons keep vanilla shotgun audio."); } return; } _loadStarted = true; if (ArmoryPersistentRunner.Run(LoadAllSounds(text)) == null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Y4NGZWeapons] Could not start the weapon sound load; keeping vanilla shotgun audio."); } } } catch (Exception ex) { _loadStarted = true; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZWeapons] Weapon sound load could not start; keeping vanilla shotgun audio: " + ex.Message)); } } } private static IEnumerator LoadAllSounds(string directory) { WeaponSoundSet[] sets = Sets; foreach (WeaponSoundSet set in sets) { List fireClips = new List(); string[] fireFiles = set.FireFiles; foreach (string fileName in fireFiles) { yield return LoadClip(directory, fileName, set.Label, delegate(AudioClip clip) { if ((Object)(object)clip != (Object)null) { fireClips.Add(clip); } }); } if (fireClips.Count > 0) { set.FireClips = fireClips.ToArray(); } yield return LoadClip(directory, set.NoAmmoFile, set.Label, delegate(AudioClip clip) { set.NoAmmoClip = clip; }); yield return LoadClip(directory, set.ReloadStartFile, set.Label, delegate(AudioClip clip) { set.ReloadStartClip = clip; }); yield return LoadClip(directory, set.ReloadFinishFile, set.Label, delegate(AudioClip clip) { set.ReloadFinishClip = clip; }); yield return LoadClip(directory, set.ReloadStageLoopFile, set.Label, delegate(AudioClip clip) { set.ReloadStageLoopClip = clip; }); yield return LoadClip(directory, set.DropFile, set.Label, delegate(AudioClip clip) { set.DropClip = clip; }); ManualLogSource log = Plugin.Log; if (log != null) { string[] array = new string[6]; string label = set.Label; AudioClip[] fireClips2 = set.FireClips; array[0] = $"[Y4NGZWeapons] {label} audio: fire={((fireClips2 != null) ? fireClips2.Length : 0)}, "; array[1] = $"dryFire={(((Object)(object)set.NoAmmoClip != (Object)null) ? 1 : 0)}, reloadStart={(((Object)(object)set.ReloadStartClip != (Object)null) ? 1 : 0)}, "; array[2] = $"reloadFinish={(((Object)(object)set.ReloadFinishClip != (Object)null) ? 1 : 0)}, "; array[3] = $"reloadPerRound={(((Object)(object)set.ReloadStageLoopClip != (Object)null) ? 1 : 0)}, "; array[4] = $"drop={(((Object)(object)set.DropClip != (Object)null) ? 1 : 0)}. "; array[5] = "Empty slots keep the vanilla shotgun clip."; log.LogInfo((object)string.Concat(array)); } } ApplyToRegisteredItems(); } private static IEnumerator LoadClip(string directory, string fileName, string label, Action assign) { if (string.IsNullOrWhiteSpace(fileName)) { yield break; } if (ClipCache.TryGetValue(fileName, out var value) && (Object)(object)value != (Object)null) { assign(value); yield break; } string text = Path.Combine(directory, fileName); if (!File.Exists(text)) { WarnMissingOnce(label, fileName, text); yield break; } UnityWebRequest request = null; UnityWebRequestAsyncOperation val; try { request = UnityWebRequestMultimedia.GetAudioClip(new Uri(text).AbsoluteUri, (AudioType)14); val = request.SendWebRequest(); } catch (Exception ex) { UnityWebRequest obj = request; if (obj != null) { obj.Dispose(); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] " + label + " sound '" + fileName + "' request failed to start; keeping the vanilla clip: " + ex.Message)); } yield break; } yield return val; try { if ((int)request.result != 1) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons] " + label + " sound '" + fileName + "' failed to load; keeping the vanilla clip: " + request.error)); } yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZWeapons] " + label + " sound '" + fileName + "' decoded as null; keeping the vanilla clip.")); } } else { ((Object)content).name = "Y4NGZ_" + Path.GetFileNameWithoutExtension(fileName); ((Object)content).hideFlags = (HideFlags)61; ClipCache[fileName] = content; _decodedRevision++; assign(content); } } catch (Exception ex2) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)("[Y4NGZWeapons] " + label + " sound '" + fileName + "' processing failed; keeping the vanilla clip: " + ex2.Message)); } } finally { UnityWebRequest obj2 = request; if (obj2 != null) { obj2.Dispose(); } } } private static void WarnMissingOnce(string label, string fileName, string path) { if (MissingWarned.Add(fileName)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] " + label + " sound '" + fileName + "' is missing (" + path + "); that slot keeps the vanilla shotgun clip.")); } } } } internal static class WeaponSurfaceClassifier { internal const int UnknownSurface = -1; internal static int ResolveSurfaceIndex(Collider collider) { if ((Object)(object)collider == (Object)null) { return -1; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.footstepSurfaces == null) { return -1; } LogSurfaceTable(); GameObject gameObject = ((Component)collider).gameObject; if ((Object)(object)gameObject == (Object)null) { return -1; } string tag = gameObject.tag; if (string.IsNullOrEmpty(tag) || tag == "Untagged") { return -1; } FootstepSurface[] footstepSurfaces = instance.footstepSurfaces; for (int i = 0; i < footstepSurfaces.Length; i++) { if (footstepSurfaces[i] != null && footstepSurfaces[i].surfaceTag == tag) { return i; } } return -1; } internal static string SurfaceTag(int surfaceIndex) { FootstepSurface val = SurfaceAt(surfaceIndex); if (val == null || val.surfaceTag == null) { return string.Empty; } return val.surfaceTag; } internal static AudioClip HitSurfaceClip(int surfaceIndex) { return SurfaceAt(surfaceIndex)?.hitSurfaceSFX; } private static FootstepSurface SurfaceAt(int surfaceIndex) { if (surfaceIndex < 0) { return null; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.footstepSurfaces == null) { return null; } if (surfaceIndex >= instance.footstepSurfaces.Length) { return null; } return instance.footstepSurfaces[surfaceIndex]; } internal static void LogSurfaceTable() { if (!WeaponVfxDiagnostics.Once("impact.surfacetable")) { return; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.footstepSurfaces == null) { return; } FootstepSurface[] footstepSurfaces = instance.footstepSurfaces; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append($"Live footstepSurfaces table ({footstepSurfaces.Length} entries), #118 — "); stringBuilder.Append("index:tag[hitSurfaceSFX] — "); for (int i = 0; i < footstepSurfaces.Length; i++) { if (i > 0) { stringBuilder.Append(", "); } FootstepSurface val = footstepSurfaces[i]; if (val == null) { stringBuilder.Append($"{i}:"); continue; } stringBuilder.Append($"{i}:'{val.surfaceTag}'"); stringBuilder.Append(((Object)(object)val.hitSurfaceSFX != (Object)null) ? ("[" + ((Object)val.hitSurfaceSFX).name + "]") : "[NO CLIP]"); } WeaponVfxDiagnostics.Emit(stringBuilder.ToString()); } } [HarmonyPatch] internal static class WeaponThirdPersonAnimation { private sealed class TpWeaponProfile { public string ConfigId; public string PackId; public string InteractionId; public string ManifestFileName; public string PackDisplayName; public string ActiveBool; public string FireTrigger = string.Empty; public string ReloadTrigger; public string ReloadEmptyTrigger = string.Empty; public string ReloadRoundsTriggerPrefix = string.Empty; public string ContinuousFiringBool = string.Empty; public bool PackRegistered; public bool ManifestMissingPermanent; public bool MissingManifestLogged; public bool RegistrationFailureLogged; public bool PreloadFailureLogged; } private sealed class RemoteSession { public PlayerControllerB Player; public Component Weapon; public TpWeaponProfile Profile; public InteractionAnimationHandle Handle; public WeaponThirdPersonVisualCarrier VisualCarrier; public bool ContinuousFiring; public bool Reloading; } private sealed class ReplicatedContinuousState { public Component Weapon; public bool Firing; public bool Reloading; } private const float StartRetrySeconds = 0.5f; private const string DebugToolsAssemblyName = "Y4NGZDebugTools"; private const string DebugToolsGuiTypeName = "Y4NGZDebugTools.DebugGUI"; private const string DebugToolsThirdPersonFieldName = "ThirdPersonCam"; private static readonly TpWeaponProfile HeavyShotgunProfile = new TpWeaponProfile { ConfigId = "heavy_shotgun", PackId = "y4ngz.upgrades.heavyshotgun.thirdperson", InteractionId = "y4ngz.heavy_shotgun.thirdperson", ManifestFileName = "y4ngz-interactions-heavyshotgun-thirdperson.manifest.json", PackDisplayName = "Y4NGZ Heavy Shotgun Remote Third Person", ActiveBool = "Y4NGZ_HeavyShotgunTP_Active", FireTrigger = "Y4NGZ_HeavyShotgunTP_Fire", ReloadTrigger = "Y4NGZ_HeavyShotgunTP_Reload" }; private static readonly TpWeaponProfile RevolverProfile = new TpWeaponProfile { ConfigId = "revolver", PackId = "y4ngz.upgrades.revolver.thirdperson", InteractionId = "y4ngz.revolver.thirdperson", ManifestFileName = "y4ngz-interactions-revolver-thirdperson.manifest.json", PackDisplayName = "Y4NGZ Revolver Remote Third Person", ActiveBool = "Y4NGZ_RevolverTP_Active", FireTrigger = "Y4NGZ_RevolverTP_Fire", ReloadTrigger = "Y4NGZ_RevolverTP_Reload" }; private static readonly TpWeaponProfile FlamethrowerProfile = new TpWeaponProfile { ConfigId = "flame_thrower", PackId = "y4ngz.upgrades.flamethrower.thirdperson", InteractionId = "y4ngz.flamethrower.thirdperson", ManifestFileName = "y4ngz-interactions-flamethrower-thirdperson.manifest.json", PackDisplayName = "Y4NGZ Flamethrower Remote Third Person", ActiveBool = "Y4NGZ_FlamethrowerTP_Active", ReloadTrigger = "Y4NGZ_FlamethrowerTP_Reload", ContinuousFiringBool = "Y4NGZ_FlamethrowerTP_Firing" }; private static readonly TpWeaponProfile Kar98KProfile = new TpWeaponProfile { ConfigId = "kar98k", PackId = "y4ngz.upgrades.kar98k.thirdperson", InteractionId = "y4ngz.kar98k.thirdperson", ManifestFileName = "y4ngz-upgrades-kar98k-thirdperson.manifest.json", PackDisplayName = "Y4NGZ Kar98K Remote Third Person", ActiveBool = "Y4NGZ_Kar98KTP_Active", FireTrigger = "Y4NGZ_Kar98KTP_Fire", ReloadEmptyTrigger = "Y4NGZ_Kar98KTP_ReloadEmpty", ReloadRoundsTriggerPrefix = "Y4NGZ_Kar98KTP_Reload" }; private static readonly TpWeaponProfile X18Profile = new TpWeaponProfile { ConfigId = "x18", PackId = "y4ngz.upgrades.x18.thirdperson", InteractionId = "y4ngz.x18.thirdperson", ManifestFileName = "y4ngz-upgrades-x18-thirdperson.manifest.json", PackDisplayName = "Y4NGZ X18 Remote Third Person", ActiveBool = "Y4NGZ_X18TP_Active", FireTrigger = "Y4NGZ_X18TP_Fire", ReloadTrigger = "Y4NGZ_X18TP_Reload", ReloadEmptyTrigger = "Y4NGZ_X18TP_ReloadEmpty" }; private static readonly TpWeaponProfile MX16A4Profile = new TpWeaponProfile { ConfigId = "mx16a4", PackId = "y4ngz.upgrades.mx16a4.thirdperson", InteractionId = "y4ngz.mx16a4.thirdperson", ManifestFileName = "y4ngz-upgrades-mx16a4-thirdperson.manifest.json", PackDisplayName = "Y4NGZ MX16A4 Remote Third Person", ActiveBool = "Y4NGZ_MX16A4TP_Active", ReloadTrigger = "Y4NGZ_MX16A4TP_Reload", ReloadEmptyTrigger = "Y4NGZ_MX16A4TP_ReloadEmpty" }; private static readonly TpWeaponProfile[] Profiles = new TpWeaponProfile[6] { HeavyShotgunProfile, RevolverProfile, FlamethrowerProfile, Kar98KProfile, X18Profile, MX16A4Profile }; private static readonly Dictionary Sessions = new Dictionary(); private static readonly Dictionary NextStartAttempt = new Dictionary(); private static readonly Dictionary ContinuousStates = new Dictionary(); private static bool LocalThirdPersonModeKnown; private static bool LocalThirdPersonModeActive; private static bool DebugToolsProbed; private static FieldInfo DebugToolsThirdPersonField; [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] private static void StartOfRoundAwake_Postfix() { try { PreloadPacks(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] weapon pack preload failed safely: " + ex.Message)); } } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] private static void PlayerUpdate_Postfix(PlayerControllerB __instance) { try { if (IsRemotePlayer(__instance) || IsLocalPlayer(__instance)) { TickThirdPersonPlayer(__instance); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] third-person player update failed safely: " + ex.Message)); } } } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] [HarmonyPostfix] private static void ShootGun_Postfix(ShotgunItem __instance) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) try { Y4NGZWeaponItem weapon = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent() : null); PlayerControllerB player = (((Object)(object)__instance != (Object)null) ? ((GrabbableObject)__instance).playerHeldBy : null); TpWeaponProfile tpWeaponProfile = ProfileFor((Component)(object)weapon); if (tpWeaponProfile != null && !string.IsNullOrWhiteSpace(tpWeaponProfile.FireTrigger) && ShouldPresentPlayer(player, tpWeaponProfile) && TryGetActiveSession(player, (Component)(object)weapon, out var session)) { LCInteractionAnimationAPI.TryFireInteractionTrigger(session.Handle, tpWeaponProfile.FireTrigger); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] remote fire gesture failed safely: " + ex.Message)); } } } [HarmonyPatch(typeof(ShotgunItem), "ReloadGunEffectsClientRpc")] [HarmonyPostfix] private static void ReloadGunEffectsClientRpc_Postfix(ShotgunItem __instance, bool start) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) try { if (start) { Y4NGZWeaponItem weapon = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent() : null); PlayerControllerB player = (((Object)(object)__instance != (Object)null) ? ((GrabbableObject)__instance).playerHeldBy : null); TpWeaponProfile tpWeaponProfile = ProfileFor((Component)(object)weapon); if (tpWeaponProfile != null && tpWeaponProfile != FlamethrowerProfile && ShouldPresentPlayer(player, tpWeaponProfile) && TryGetActiveSession(player, (Component)(object)weapon, out var session)) { LCInteractionAnimationAPI.TryFireInteractionTrigger(session.Handle, tpWeaponProfile.ReloadTrigger); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] remote reload gesture failed safely: " + ex.Message)); } } } internal static void OnNativeWeaponFired(Y4NGZWeaponBase weapon, PlayerControllerB player) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) try { TpWeaponProfile tpWeaponProfile = ProfileFor((Component)(object)weapon); if (IsNativeThirdPersonProfile(tpWeaponProfile) && !string.IsNullOrWhiteSpace(tpWeaponProfile.FireTrigger) && ShouldPresentPlayer(player, tpWeaponProfile) && TryGetActiveSession(player, (Component)(object)weapon, out var session)) { LCInteractionAnimationAPI.TryFireInteractionTrigger(session.Handle, tpWeaponProfile.FireTrigger); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] native fire gesture failed safely: " + ex.Message)); } } } internal static void OnNativeReloadStarted(Y4NGZWeaponBase weapon, PlayerControllerB player, bool wasEmpty, int roundsDrawn) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) try { TpWeaponProfile tpWeaponProfile = ProfileFor((Component)(object)weapon); if (IsNativeThirdPersonProfile(tpWeaponProfile) && ShouldPresentPlayer(player, tpWeaponProfile)) { string text = ((wasEmpty && !string.IsNullOrWhiteSpace(tpWeaponProfile.ReloadEmptyTrigger)) ? tpWeaponProfile.ReloadEmptyTrigger : (string.IsNullOrWhiteSpace(tpWeaponProfile.ReloadRoundsTriggerPrefix) ? tpWeaponProfile.ReloadTrigger : (tpWeaponProfile.ReloadRoundsTriggerPrefix + Mathf.Clamp(roundsDrawn, 1, 4)))); if (!string.IsNullOrWhiteSpace(text) && TryGetActiveSession(player, (Component)(object)weapon, out var session)) { LCInteractionAnimationAPI.TryFireInteractionTrigger(session.Handle, text); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] native reload gesture failed safely: " + ex.Message)); } } } [HarmonyPatch(typeof(FlamethrowerStreamDriver), "ApplyReplicatedState")] [HarmonyPostfix] private static void FlamethrowerReplicatedState_Postfix(FlamethrowerStreamDriver __instance, bool firing, bool reloading, int fuel) { try { ShotgunItem val = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent() : null); Y4NGZWeaponItem weapon = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent() : null); PlayerControllerB val2 = (((Object)(object)val != (Object)null) ? ((GrabbableObject)val).playerHeldBy : null); if (ProfileFor((Component)(object)weapon) == FlamethrowerProfile && ShouldPresentPlayer(val2, FlamethrowerProfile)) { bool firing2 = firing && fuel > 0 && !reloading; ContinuousStates[val2] = new ReplicatedContinuousState { Weapon = (Component)(object)weapon, Firing = firing2, Reloading = reloading }; if (TryGetActiveSession(val2, (Component)(object)weapon, out var session)) { ApplyContinuousState(session, firing2, reloading); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] Flamethrower replicated gesture failed safely: " + ex.Message)); } } } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static void EndOfGame_Postfix() { StopAll((InteractionAnimationStopReason)0); } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] [HarmonyPostfix] private static void Disconnect_Postfix() { StopAll((InteractionAnimationStopReason)2); } internal static void PreloadPacks() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogMessage((object)("[Y4NGZWeapons.TP] build knows " + Profiles.Length + " third-person profiles: " + string.Join(", ", Array.ConvertAll(Profiles, (TpWeaponProfile p) => p.ConfigId)) + ".")); } TpWeaponProfile[] profiles = Profiles; string text = default(string); foreach (TpWeaponProfile tpWeaponProfile in profiles) { if (!EnsurePackRegistered(tpWeaponProfile)) { continue; } if (LCInteractionAnimationAPI.TryPreloadInteractionAssets(tpWeaponProfile.PackId, tpWeaponProfile.InteractionId, ref text)) { tpWeaponProfile.PreloadFailureLogged = false; } else if (!tpWeaponProfile.PreloadFailureLogged) { tpWeaponProfile.PreloadFailureLogged = true; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons.TP] " + tpWeaponProfile.ConfigId + " preload rejected: " + text)); } } } } private static void TickThirdPersonPlayer(PlayerControllerB player) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Expected O, but got Unknown //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) ResolveHeldProfile(player, out var weapon, out var profile); ReportLocalThirdPersonMode(player, profile); bool flag = player.isPlayerControlled && !player.isPlayerDead && (Object)(object)weapon != (Object)null && profile != null && ShouldPresentPlayer(player, profile); if (flag && profile != FlamethrowerProfile) { ContinuousStates.Remove(player); } if (Sessions.TryGetValue(player, out var value)) { bool flag2 = ((InteractionAnimationHandle)(ref value.Handle)).IsValid && LCInteractionAnimationAPI.IsInteractionActive(value.Handle); bool flag3 = flag && (Object)(object)value.Player == (Object)(object)player && (Object)(object)value.Weapon == (Object)(object)weapon && value.Profile == profile; if (flag2 && flag3) { return; } if (flag2) { if (!string.IsNullOrWhiteSpace(value.Profile.ContinuousFiringBool)) { LCInteractionAnimationAPI.TrySetInteractionBool(value.Handle, value.Profile.ContinuousFiringBool, false); } LCInteractionAnimationAPI.TrySetInteractionBool(value.Handle, value.Profile.ActiveBool, false); LCInteractionAnimationAPI.TryStopInteraction(value.Handle, (InteractionAnimationStopReason)2); } value.VisualCarrier?.Release(); Sessions.Remove(player); } if (!flag) { NextStartAttempt.Remove(player); ContinuousStates.Remove(player); } else { InteractionAnimationHandle val = default(InteractionAnimationHandle); if (LCInteractionAnimationAPI.TryGetActiveInteraction(player, (InteractionAnimationPresentationKind)1, ref val) || (NextStartAttempt.TryGetValue(player, out var value2) && Time.unscaledTime < value2)) { return; } NextStartAttempt[player] = Time.unscaledTime + 0.5f; if (!EnsurePackRegistered(profile)) { return; } InteractionAnimationHandle val2 = default(InteractionAnimationHandle); string arg = default(string); if (!LCInteractionAnimationAPI.TryStartInteraction(new InteractionAnimationRequest { Player = player, PackId = profile.PackId, InteractionId = profile.InteractionId }, ref val2, ref arg)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[Y4NGZWeapons.TP] " + profile.ConfigId + " presentation deferred for " + $"player {player.playerClientId}: {arg}")); } return; } LCInteractionAnimationAPI.TrySetInteractionBool(val2, profile.ActiveBool, true); value = new RemoteSession { Player = player, Weapon = weapon, Profile = profile, Handle = val2 }; if (profile == Kar98KProfile || profile == MX16A4Profile || profile == X18Profile || profile == HeavyShotgunProfile || profile == RevolverProfile || profile == FlamethrowerProfile) { value.VisualCarrier = WeaponThirdPersonVisualCarrier.Attach(player.currentlyHeldObjectServer, player, WeaponLandmarkCatalog.ById(profile.ConfigId)); } Sessions[player] = value; NextStartAttempt.Remove(player); if (profile == FlamethrowerProfile && ContinuousStates.TryGetValue(player, out var value3) && (Object)(object)value3.Weapon == (Object)(object)weapon) { ApplyContinuousState(value, value3.Firing, value3.Reloading); } } } internal static void StopForHeldItemStow(PlayerControllerB player) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && Sessions.TryGetValue(player, out var value)) { if (((InteractionAnimationHandle)(ref value.Handle)).IsValid) { LCInteractionAnimationAPI.TryStopInteraction(value.Handle, (InteractionAnimationStopReason)2); } value.VisualCarrier?.Release(); Sessions.Remove(player); NextStartAttempt.Remove(player); ContinuousStates.Remove(player); } } private static void ApplyContinuousState(RemoteSession session, bool firing, bool reloading) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (session != null && session.Profile == FlamethrowerProfile && ((InteractionAnimationHandle)(ref session.Handle)).IsValid && LCInteractionAnimationAPI.IsInteractionActive(session.Handle)) { if (session.ContinuousFiring != firing) { LCInteractionAnimationAPI.TrySetInteractionBool(session.Handle, session.Profile.ContinuousFiringBool, firing); session.ContinuousFiring = firing; } if (reloading && !session.Reloading) { LCInteractionAnimationAPI.TryFireInteractionTrigger(session.Handle, session.Profile.ReloadTrigger); } session.Reloading = reloading; } } private static bool TryGetActiveSession(PlayerControllerB player, Component weapon, out RemoteSession session) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) session = null; if ((Object)(object)player == (Object)null || (Object)(object)weapon == (Object)null) { return false; } TickThirdPersonPlayer(player); if (!Sessions.TryGetValue(player, out var value)) { return false; } if ((Object)(object)value.Player != (Object)(object)player || (Object)(object)value.Weapon != (Object)(object)weapon) { return false; } if (!((InteractionAnimationHandle)(ref value.Handle)).IsValid || !LCInteractionAnimationAPI.IsInteractionActive(value.Handle)) { value.VisualCarrier?.Release(); Sessions.Remove(player); return false; } session = value; return true; } private static void ResolveHeldProfile(PlayerControllerB player, out Component weapon, out TpWeaponProfile profile) { weapon = null; profile = null; if ((Object)(object)player?.currentlyHeldObjectServer == (Object)null) { return; } weapon = (Component)(object)((Component)player.currentlyHeldObjectServer).GetComponent(); profile = ProfileFor(weapon); if (profile == null) { weapon = (Component)(object)((Component)player.currentlyHeldObjectServer).GetComponent(); profile = ProfileFor(weapon); if (profile == null) { weapon = null; } } } private static TpWeaponProfile ProfileFor(Component weapon) { string b = null; if (weapon is Y4NGZWeaponItem y4NGZWeaponItem) { b = y4NGZWeaponItem.ConfigId; } else if (weapon is Y4NGZWeaponBase y4NGZWeaponBase) { b = y4NGZWeaponBase.ConfigId; } TpWeaponProfile[] profiles = Profiles; foreach (TpWeaponProfile tpWeaponProfile in profiles) { if (string.Equals(tpWeaponProfile.ConfigId, b, StringComparison.Ordinal)) { return tpWeaponProfile; } } return null; } private static bool IsRemotePlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return false; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController ?? StartOfRound.Instance?.localPlayerController; if ((Object)(object)player == (Object)(object)val) { return false; } if (!((Object)(object)val != (Object)null) && ((NetworkBehaviour)player).IsOwner) { return !player.isPlayerControlled; } return true; } private static bool IsLocalPlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return false; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController ?? StartOfRound.Instance?.localPlayerController; return (Object)(object)player == (Object)(object)val; } internal static bool ShouldUseLocalThirdPerson(PlayerControllerB player, string configId) { if ((!string.Equals(configId, "heavy_shotgun", StringComparison.Ordinal) && !string.Equals(configId, "kar98k", StringComparison.Ordinal) && !string.Equals(configId, "x18", StringComparison.Ordinal) && !string.Equals(configId, "mx16a4", StringComparison.Ordinal) && !string.Equals(configId, "revolver", StringComparison.Ordinal) && !string.Equals(configId, "flame_thrower", StringComparison.Ordinal)) || !IsLocalPlayer(player) || player.isPlayerDead) { return false; } bool active; return TryReadDebugToolsThirdPerson(out active) && active; } private static bool TryReadDebugToolsThirdPerson(out bool active) { active = false; if (!DebugToolsProbed) { DebugToolsProbed = true; try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "Y4NGZDebugTools", StringComparison.Ordinal)) { DebugToolsThirdPersonField = assembly.GetType("Y4NGZDebugTools.DebugGUI", throwOnError: false)?.GetField("ThirdPersonCam", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); break; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] debug-tools third-person probe failed safely: " + ex.Message)); } } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogMessage((object)("[Y4NGZWeapons.TP] debug-tools third-person toggle " + ((DebugToolsThirdPersonField != null) ? "resolved; it is authoritative for local third person." : "not present; local third-person presentation stays disabled."))); } } if (DebugToolsThirdPersonField == null) { return false; } try { object value = DebugToolsThirdPersonField.GetValue(null); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } active = (byte)((uint)num & (flag ? 1u : 0u)) != 0; return true; } catch { DebugToolsThirdPersonField = null; return false; } } private static bool ShouldPresentPlayer(PlayerControllerB player, TpWeaponProfile profile) { if (!IsRemotePlayer(player)) { if (IsNativeThirdPersonProfile(profile)) { return ShouldUseLocalThirdPerson(player, profile.ConfigId); } return false; } return true; } private static bool IsNativeThirdPersonProfile(TpWeaponProfile profile) { if (profile != HeavyShotgunProfile && profile != Kar98KProfile && profile != X18Profile && profile != MX16A4Profile && profile != RevolverProfile) { return profile == FlamethrowerProfile; } return true; } private static void ReportLocalThirdPersonMode(PlayerControllerB player, TpWeaponProfile profile) { //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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_00db: Unknown result type (might be due to invalid IL or missing references) if (!IsLocalPlayer(player)) { return; } bool flag = IsNativeThirdPersonProfile(profile) && ShouldUseLocalThirdPerson(player, profile.ConfigId); if ((!IsNativeThirdPersonProfile(profile) && !LocalThirdPersonModeActive) || (LocalThirdPersonModeKnown && LocalThirdPersonModeActive == flag)) { return; } LocalThirdPersonModeKnown = true; LocalThirdPersonModeActive = flag; Vector3 val = Vector3.zero; try { if ((Object)(object)player.gameplayCamera != (Object)null) { val = ((Component)player).transform.InverseTransformPoint(((Component)player.gameplayCamera).transform.position); } } catch { } ManualLogSource log = Plugin.Log; if (log != null) { log.LogMessage((object)("[Y4NGZWeapons.TP] local " + (profile?.ConfigId ?? "native weapon") + " camera presentation changed: mode=" + (flag ? "thirdperson" : "firstperson") + " " + string.Format("cameraLocal={0} owner={1}.", val, flag ? "TP body/world" : "FP arms"))); } } private static void StopAll(InteractionAnimationStopReason reason) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) foreach (RemoteSession value in Sessions.Values) { if (value != null && ((InteractionAnimationHandle)(ref value.Handle)).IsValid) { LCInteractionAnimationAPI.TryStopInteraction(value.Handle, reason); } value?.VisualCarrier?.Release(); } Sessions.Clear(); NextStartAttempt.Clear(); ContinuousStates.Clear(); LocalThirdPersonModeKnown = false; LocalThirdPersonModeActive = false; } private static bool EnsurePackRegistered(TpWeaponProfile profile) { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown if (profile == null) { return false; } if (profile.PackRegistered) { return true; } if (profile.ManifestMissingPermanent) { return false; } string text = Path.GetDirectoryName(typeof(Plugin).Assembly.Location) ?? string.Empty; string text2 = Path.Combine(text, profile.ManifestFileName); if (!File.Exists(text2)) { profile.ManifestMissingPermanent = true; if (!profile.MissingManifestLogged) { profile.MissingManifestLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] " + profile.ConfigId + " manifest not found: " + text2)); } } return false; } string manifestJson; try { manifestJson = File.ReadAllText(text2); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons.TP] " + profile.ConfigId + " manifest read failed: " + ex.Message)); } return false; } InteractionAnimationPackDefinition val = new InteractionAnimationPackDefinition(); val.PackId = profile.PackId; val.Version = "0.1.0"; val.AssetRootPath = text; val.Interactions = (InteractionAnimationDefinition[])(object)new InteractionAnimationDefinition[1] { new InteractionAnimationDefinition { InteractionId = profile.InteractionId, PresentationKind = (InteractionAnimationPresentationKind)1, ManifestJson = manifestJson } }; string text3 = default(string); if (!LCInteractionAnimationAPI.TryRegisterInteractionPack(val, ref text3)) { if (string.Equals(text3, "pack_already_registered", StringComparison.OrdinalIgnoreCase)) { profile.PackRegistered = true; return true; } if (!profile.RegistrationFailureLogged) { profile.RegistrationFailureLogged = true; ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZWeapons.TP] " + profile.ConfigId + " pack registration failed: " + text3)); } } return false; } profile.PackRegistered = true; profile.RegistrationFailureLogged = false; ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)("[Y4NGZWeapons.TP] registered " + profile.PackDisplayName + " pack.")); } return true; } } [DefaultExecutionOrder(10000)] internal sealed class WeaponThirdPersonVisualCarrier : MonoBehaviour { private const float CalibrationDelaySeconds = 0.14f; private const float CalibrationWarningSeconds = 2f; private const float PalmSeatAlongFingers = 0.04f; private const float PalmSeatIntoPalm = -0.01f; private const float MinimumScale = 0.78f; private const float MaximumScale = 1.22f; private const string LeftBodyHandPath = "spine/spine.001/spine.002/spine.003/shoulder.L/arm.L_upper/arm.L_lower/hand.L"; private const string RightBodyHandPath = "spine/spine.001/spine.002/spine.003/shoulder.R/arm.R_upper/arm.R_lower/hand.R"; private GrabbableObject _weapon; private PlayerControllerB _player; private WeaponLandmarks _landmarks; private Transform _visualRoot; private Transform _leftHand; private Transform _rightHand; private Transform[] _hiddenDescendants = Array.Empty(); private Vector3[] _hiddenOriginalScales = Array.Empty(); private Vector3 _originalLocalPosition; private Quaternion _originalLocalRotation; private Vector3 _originalLocalScale; private Transform _carrierHand; private Vector3 _carrierAnchorPosition; private Quaternion _carrierAnchorRotation; private Vector3 _carrierLocalScale; private float _calibrateAt; private float _calibrationDeadline; private bool _calibrationWarned; private bool _bound; private bool _calibrated; private bool _released; internal static WeaponThirdPersonVisualCarrier Attach(GrabbableObject weapon, PlayerControllerB player, WeaponLandmarks landmarks) { if ((Object)(object)weapon == (Object)null || (Object)(object)player == (Object)null || landmarks == null || !landmarks.HasSupportGrip || string.IsNullOrWhiteSpace(landmarks.VisualRootName)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] visual carrier declined: " + $"weapon={(Object)(object)weapon != (Object)null} player={(Object)(object)player != (Object)null} " + $"landmarks={landmarks != null} " + $"hasSupportGrip={landmarks?.HasSupportGrip ?? false} " + "visualRoot='" + landmarks?.VisualRootName + "'. The world model will be left on the ordinary held-item hierarchy.")); } return null; } WeaponThirdPersonVisualCarrier weaponThirdPersonVisualCarrier = ((Component)weapon).GetComponent(); if ((Object)(object)weaponThirdPersonVisualCarrier == (Object)null) { weaponThirdPersonVisualCarrier = ((Component)weapon).gameObject.AddComponent(); } weaponThirdPersonVisualCarrier.Bind(weapon, player, landmarks); return weaponThirdPersonVisualCarrier; } internal void Release() { if (!_released) { _released = true; RestoreVisualRoot(); Object.Destroy((Object)(object)this); } } private void Bind(GrabbableObject weapon, PlayerControllerB player, WeaponLandmarks landmarks) { //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) if (_bound) { RestoreVisualRoot(); } _weapon = weapon; _player = player; _landmarks = landmarks; _visualRoot = FindDeep(((Component)weapon).transform, landmarks.VisualRootName); Transform val = (((Object)(object)player.playerBodyAnimator != (Object)null) ? ((Component)player.playerBodyAnimator).transform : ((Component)player).transform); _leftHand = val.Find("spine/spine.001/spine.002/spine.003/shoulder.L/arm.L_upper/arm.L_lower/hand.L"); _rightHand = val.Find("spine/spine.001/spine.002/spine.003/shoulder.R/arm.R_upper/arm.R_lower/hand.R"); if ((Object)(object)_visualRoot == (Object)null || (Object)(object)_leftHand == (Object)null || (Object)(object)_rightHand == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] Kar98K visual carrier could not resolve " + $"visual={(Object)(object)_visualRoot != (Object)null} left={(Object)(object)_leftHand != (Object)null} " + $"right={(Object)(object)_rightHand != (Object)null}.")); } _bound = false; _released = true; Object.Destroy((Object)(object)this); } else { _carrierHand = (landmarks.DominantHandCarries ? _rightHand : _leftHand); BindHiddenDescendants(); _originalLocalPosition = _visualRoot.localPosition; _originalLocalRotation = _visualRoot.localRotation; _originalLocalScale = _visualRoot.localScale; _calibrateAt = Time.unscaledTime + 0.14f; _calibrationDeadline = _calibrateAt + 2f; _calibrationWarned = false; _calibrated = false; _released = false; _bound = true; } } private void LateUpdate() { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (!_bound || _released) { return; } if ((Object)(object)_weapon == (Object)null || (Object)(object)_player == (Object)null || (Object)(object)_visualRoot == (Object)null || !_weapon.isHeld || (Object)(object)_weapon.playerHeldBy != (Object)(object)_player) { Release(); return; } SuppressHiddenDescendants(); if (!_calibrated) { if (Time.unscaledTime < _calibrateAt) { return; } if (!TryCalibrate()) { if (!_calibrationWarned && Time.unscaledTime >= _calibrationDeadline) { _calibrationWarned = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] visual carrier bound but has not calibrated after " + $"{2f:F1}s — grip separations are still under " + $"{_landmarks.MinimumGripSeparation:F3}m. The world model is unplaced.")); } } return; } } _visualRoot.localScale = _carrierLocalScale; _visualRoot.SetPositionAndRotation(_carrierHand.TransformPoint(_carrierAnchorPosition), _carrierHand.rotation * _carrierAnchorRotation); } private void BindHiddenDescendants() { //IL_0118: Unknown result type (might be due to invalid IL or missing references) _hiddenDescendants = Array.Empty(); _hiddenOriginalScales = Array.Empty(); string[] array = _landmarks?.ThirdPersonHiddenDescendants; if (array == null || array.Length == 0) { return; } Transform val = (string.IsNullOrEmpty(_landmarks.PropAnimationRoot) ? _visualRoot : FindDeep(_visualRoot, _landmarks.PropAnimationRoot)); if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.TP] visual carrier could not resolve prop root '" + _landmarks.PropAnimationRoot + "'; third-person part suppression is off.")); } return; } List list = new List(array.Length); List list2 = new List(array.Length); string[] array2 = array; foreach (string text in array2) { Transform val2 = FindDeep(val, text); if ((Object)(object)val2 == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeapons.TP] visual carrier could not resolve '" + text + "' under '" + ((Object)val).name + "'; it will stay visible in third person.")); } } else { list.Add(val2); list2.Add(val2.localScale); } } _hiddenDescendants = list.ToArray(); _hiddenOriginalScales = list2.ToArray(); } private void SuppressHiddenDescendants() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _hiddenDescendants.Length; i++) { Transform val = _hiddenDescendants[i]; if ((Object)(object)val != (Object)null) { val.localScale = Vector3.zero; } } } private void RestoreHiddenDescendants() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _hiddenDescendants.Length && i < _hiddenOriginalScales.Length; i++) { Transform val = _hiddenDescendants[i]; if ((Object)(object)val != (Object)null) { val.localScale = _hiddenOriginalScales[i]; } } _hiddenDescendants = Array.Empty(); _hiddenOriginalScales = Array.Empty(); } private bool TryCalibrate() { //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) //IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_0093: 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) //IL_009a: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ComputePalmSeat(_rightHand, leftHand: false); Vector3 val2 = ComputePalmSeat(_leftHand, leftHand: true); Vector3 val3 = _landmarks.SupportGripPosition - _landmarks.DominantGripPosition; Vector3 val4 = val2 - val; float magnitude = ((Vector3)(ref val3)).magnitude; float magnitude2 = ((Vector3)(ref val4)).magnitude; float num = Mathf.Max(_landmarks.MinimumGripSeparation, 0.005f); if (magnitude < num || magnitude2 < num) { _calibrateAt = Time.unscaledTime + 0.1f; return false; } Vector3 val5 = val3 / magnitude; Vector3 val6 = val4 / magnitude2; Vector3 val7 = SafeProjectedUp(Vector3.up, val5, Vector3.right); Vector3 val8 = SafeProjectedUp(((Component)_player).transform.up, val6, _leftHand.up); Quaternion val9 = Quaternion.LookRotation(val5, val7); Quaternion val10 = Quaternion.LookRotation(val6, val8) * Quaternion.Inverse(val9); float num2 = (_landmarks.UsesFixedVisualScale ? _landmarks.FixedVisualScale : Mathf.Clamp(magnitude2 / magnitude, 0.78f, 1.22f)); _visualRoot.localScale = Vector3.one * num2; Vector3 val11 = val - val10 * (_landmarks.DominantGripPosition * num2); _visualRoot.SetPositionAndRotation(val11, val10); _carrierAnchorPosition = _carrierHand.InverseTransformPoint(_visualRoot.position); _carrierAnchorRotation = Quaternion.Inverse(_carrierHand.rotation) * _visualRoot.rotation; _carrierLocalScale = _visualRoot.localScale; _calibrated = true; float num3 = Vector3.Distance(val11 + val10 * (_landmarks.SupportGripPosition * num2), val2); ManualLogSource log = Plugin.Log; if (log != null) { string[] obj = new string[13] { "[Y4NGZWeapons.TP] ", _landmarks.ConfigId, " world visual calibrated to authored ", $"grips: handSpan={magnitude2:F3}m modelSpan={magnitude:F3}m ", $"minSpan={num:F3}m ", $"scale={num2:F3} rawScale={magnitude2 / magnitude:F3} ", $"fixedScale={_landmarks.UsesFixedVisualScale} ", $"supportResidual={num3:F4}m ", "rot=", null, null, null, null }; Vector3 eulerAngles = ((Quaternion)(ref val10)).eulerAngles; obj[9] = ((Vector3)(ref eulerAngles)).ToString("F1"); obj[10] = " carrier="; obj[11] = (_landmarks.DominantHandCarries ? "hand.R" : "hand.L"); obj[12] = "."; log.LogMessage((object)string.Concat(obj)); } return true; } private static Vector3 ComputePalmSeat(Transform hand, bool leftHand) { //IL_0009: 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_005d: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_008f: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hand == (Object)null) { return Vector3.zero; } string text = (leftHand ? ".L" : ".R"); Transform val = FindDeep(hand, "finger1" + text); Transform val2 = FindDeep(hand, "finger5" + text); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return hand.position; } Vector3 val3 = SafeDirection((val.position + val2.position) * 0.5f - hand.position, hand.forward); Vector3 val4 = SafeDirection(val2.position - val.position, hand.right); Vector3 val5; Vector3 normalized; if (!leftHand) { val5 = Vector3.Cross(val3, val4); normalized = ((Vector3)(ref val5)).normalized; } else { val5 = Vector3.Cross(val4, val3); normalized = ((Vector3)(ref val5)).normalized; } Vector3 val6 = normalized; if (((Vector3)(ref val6)).sqrMagnitude < 0.5f) { val6 = hand.up; } return hand.position + val3 * 0.04f + val6 * -0.01f; } private void RestoreVisualRoot() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (_bound) { RestoreHiddenDescendants(); if ((Object)(object)_visualRoot == (Object)null) { _bound = false; _calibrated = false; return; } _visualRoot.localPosition = _originalLocalPosition; _visualRoot.localRotation = _originalLocalRotation; _visualRoot.localScale = _originalLocalScale; _bound = false; _calibrated = false; } } private void OnDestroy() { if (!_released) { RestoreVisualRoot(); } } private static Transform FindDeep(Transform root, string name) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(name)) { return null; } if (string.Equals(((Object)root).name, name, StringComparison.Ordinal)) { return root; } foreach (Transform item in root) { Transform val = FindDeep(item, name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Vector3 SafeProjectedUp(Vector3 preferred, Vector3 forward, Vector3 fallback) { //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_0002: Unknown result type (might be due to invalid IL or missing references) //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) //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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.ProjectOnPlane(preferred, forward); if (((Vector3)(ref val)).sqrMagnitude < 1E-06f) { val = Vector3.ProjectOnPlane(fallback, forward); } if (((Vector3)(ref val)).sqrMagnitude < 1E-06f) { val = Vector3.Cross(forward, Vector3.right); } return ((Vector3)(ref val)).normalized; } private static Vector3 SafeDirection(Vector3 preferred, Vector3 fallback) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref preferred)).sqrMagnitude > 1E-06f) { return ((Vector3)(ref preferred)).normalized; } if (((Vector3)(ref fallback)).sqrMagnitude > 1E-06f) { return ((Vector3)(ref fallback)).normalized; } return Vector3.forward; } } internal static class WeaponVfxDiagnostics { private struct AimBucket { public int Samples; public double SumRange; public double SumAngle; public double SumRadial; public double SumDx; public double SumDy; public float MaxAngle; public float MaxAxisOffset; } private sealed class AliveSampler : MonoBehaviour { private static readonly float[] SampleTimes = new float[2] { 0.08f, 0.5f }; internal string Key; private float _spawnedAt; private int _next; private void Awake() { _spawnedAt = Time.time; } private void Update() { float num = Time.time - _spawnedAt; if (num < SampleTimes[_next]) { return; } ParticleSystem[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); int num2 = 0; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < componentsInChildren.Length; i++) { if (!((Object)(object)componentsInChildren[i] == (Object)null)) { int particleCount = componentsInChildren[i].particleCount; num2 += particleCount; if (particleCount > 0) { stringBuilder.Append((stringBuilder.Length > 0) ? ", " : "").Append(((Object)componentsInChildren[i]).name).Append('=') .Append(particleCount); } } } string text = ((_next == 0) ? " — ZERO live particles this early means the emission is dead, not the rendering." : string.Empty); Emit($"ALIVE key='{Key}' age={num:F2}s total={num2}" + ((stringBuilder.Length > 0) ? $" [{stringBuilder}]" : text)); _next++; if (_next >= SampleTimes.Length) { Object.Destroy((Object)(object)this); } } } internal const string LogPrefix = "[Y4NGZWeaponVfx]"; internal static bool Enabled; private static readonly HashSet Reported = new HashSet(); private static readonly StringBuilder Builder = new StringBuilder(1024); internal static bool AimProbeZeroSpread; private const float ViewportTolerance = 0.002f; private const float NearFarRatioLimit = 1.5f; private const float NearMaxMeters = 4f; private const float MidMaxMeters = 20f; private static readonly string[] AimBucketNames = new string[3] { "near", "mid", "far" }; private static readonly AimBucket[] AimBuckets = new AimBucket[3]; private static int RequiredSamplesPerBucket { get { if (!AimProbeZeroSpread) { return 8; } return 3; } } internal static bool Once(string key) { if (Enabled) { return Reported.Add(key); } return false; } internal static void Emit(string message) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogMessage((object)("[Y4NGZWeaponVfx] " + message)); } } internal static void Reset() { Reported.Clear(); for (int i = 0; i < AimBuckets.Length; i++) { AimBuckets[i] = default(AimBucket); } } internal static string DescribeInstance(GameObject instance, Vector3 requestedOrigin) { //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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)instance == (Object)null) { return "instance="; } Builder.Length = 0; StringBuilder stringBuilder = Builder.Append("instance='").Append(((Object)instance).name).Append('\'') .Append(" activeInHierarchy=") .Append(instance.activeInHierarchy) .Append(" layer=") .Append(instance.layer) .Append(" requestedOrigin=") .Append(((Vector3)(ref requestedOrigin)).ToString("F3")) .Append(" actualPos="); Vector3 val = instance.transform.position; StringBuilder stringBuilder2 = stringBuilder.Append(((Vector3)(ref val)).ToString("F3")).Append(" lossyScale="); val = instance.transform.lossyScale; stringBuilder2.Append(((Vector3)(ref val)).ToString("F3")); Transform parent = instance.transform.parent; Builder.Append(" parent=").Append(((Object)(object)parent != (Object)null) ? ((Object)parent).name : ""); AppendFraming(instance); AppendRenderers(instance); return Builder.ToString(); } private static void AppendFraming(GameObject instance) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0123: 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_005b: 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) Camera val = ResolveViewCamera(); if ((Object)(object)val == (Object)null) { Builder.Append(" camera="); return; } Vector3 position = instance.transform.position; Vector3 val2 = val.WorldToViewportPoint(position); bool value = val2.z > 0f && val2.x >= 0f && val2.x <= 1f && val2.y >= 0f && val2.y <= 1f; Builder.Append(" camera='").Append(((Object)val).name).Append('\'') .Append(" viewport=") .Append(((Vector3)(ref val2)).ToString("F3")) .Append(" inFrustum=") .Append(value) .Append(" distance=") .Append(Vector3.Distance(((Component)val).transform.position, position).ToString("F3")) .Append(" nearClip=") .Append(val.nearClipPlane.ToString("F3")) .Append(" behindNearClip=") .Append(val2.z < val.nearClipPlane) .Append(" cameraDrawsLayer=") .Append((val.cullingMask & (1 << instance.layer)) != 0); } private static void AppendRenderers(GameObject instance) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Invalid comparison between Unknown and I4 //IL_012c: Unknown result type (might be due to invalid IL or missing references) ParticleSystem[] componentsInChildren = instance.GetComponentsInChildren(true); ParticleSystemRenderer[] componentsInChildren2 = instance.GetComponentsInChildren(true); Builder.Append(" particleSystems=").Append(componentsInChildren.Length).Append(" renderers=") .Append(componentsInChildren2.Length); int num = 0; int num2 = 0; int num3 = 0; for (int i = 0; i < componentsInChildren2.Length; i++) { ParticleSystemRenderer val = componentsInChildren2[i]; if (!((Object)(object)val == (Object)null)) { Material sharedMaterial = ((Renderer)val).sharedMaterial; Shader val2 = (((Object)(object)sharedMaterial != (Object)null) ? sharedMaterial.shader : null); bool flag = (int)val.renderMode == 4; Mesh val3 = (flag ? val.mesh : null); bool flag2 = (Object)(object)val2 != (Object)null && val2.isSupported; if (flag && (Object)(object)val3 == (Object)null) { num++; } if ((Object)(object)sharedMaterial == (Object)null) { num2++; } if (!flag2) { num3++; } Builder.Append("\n [").Append(i).Append("] '") .Append(((Object)val).name) .Append('\'') .Append(" enabled=") .Append(((Renderer)val).enabled) .Append(" mode=") .Append(val.renderMode) .Append(" mesh=") .Append((!flag) ? "n/a" : (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : "")) .Append(" material=") .Append(((Object)(object)sharedMaterial != (Object)null) ? ((Object)sharedMaterial).name : "") .Append(" shader=") .Append(((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "") .Append(" shaderSupported=") .Append(flag2) .Append(" renderQueue=") .Append(((Object)(object)sharedMaterial != (Object)null) ? sharedMaterial.renderQueue : (-1)) .Append(" vertexStreams=") .Append(val.activeVertexStreamsCount); } } Builder.Append("\n SUMMARY meshModeWithNullMesh=").Append(num).Append(" nullMaterial=") .Append(num2) .Append(" unsupportedOrNullShader=") .Append(num3); } internal static string DescribeBoreAlignment(Transform host, Vector3 boreWorldDirection) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0071: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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) //IL_011d: Unknown result type (might be due to invalid IL or missing references) Camera val = ResolveViewCamera(); if ((Object)(object)val == (Object)null || (Object)(object)host == (Object)null) { return string.Empty; } Transform transform = ((Component)val).transform; Vector3 normalized = ((Vector3)(ref boreWorldDirection)).normalized; float num = Vector3.Angle(normalized, transform.forward); Transform parent = host.parent; Quaternion val2 = Quaternion.Inverse(((Object)(object)parent != (Object)null) ? parent.rotation : Quaternion.identity); Quaternion val3 = Quaternion.LookRotation(val2 * transform.forward, val2 * transform.up); Vector3 eulerAngles = ((Quaternion)(ref val3)).eulerAngles; return $" boreVsAim={num:F1}deg" + $" boreInCameraSpace=(right {Vector3.Dot(normalized, transform.right):F3}," + $" up {Vector3.Dot(normalized, transform.up):F3}," + $" fwd {Vector3.Dot(normalized, transform.forward):F3})" + $" suggestedVisualLocalEuler=({eulerAngles.x:F1},{eulerAngles.y:F1},{eulerAngles.z:F1})"; } internal static void SampleShotAim(Vector3 origin, Vector3 direction, bool hitSomething, Vector3 impactPoint, float traceDistance, Collider impactCollider, string weaponId, float spreadDegrees, PlayerControllerB firedBy) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) if (!Enabled) { return; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if ((Object)(object)val == (Object)null || (Object)(object)firedBy == (Object)null || (Object)(object)firedBy != (Object)(object)val) { return; } Camera gameplayCamera = val.gameplayCamera; if ((Object)(object)gameplayCamera == (Object)null) { return; } Transform transform = ((Component)gameplayCamera).transform; Vector3 position = transform.position; if (!hitSomething) { if (Once("aim.miss")) { Emit("AIM no impact — pellet 0 of weapon '" + weaponId + "' hit nothing within range. Fire at a wall to take a sample. Logged once."); } return; } Vector3 val2 = impactPoint - position; float magnitude = ((Vector3)(ref val2)).magnitude; if (magnitude < 0.0001f) { return; } Vector3 val3 = gameplayCamera.WorldToViewportPoint(impactPoint); if (!(val3.z <= 0f)) { float num = Vector3.Angle(transform.forward, val2); float num2 = val3.x - 0.5f; float num3 = val3.y - 0.5f; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); float num5 = Mathf.Max(Mathf.Abs(num2), Mathf.Abs(num3)); int num6 = ((!(magnitude < 4f)) ? ((magnitude <= 20f) ? 1 : 2) : 0); AimBuckets[num6].Samples++; AimBuckets[num6].SumRange += magnitude; AimBuckets[num6].SumAngle += num; AimBuckets[num6].SumRadial += num4; AimBuckets[num6].SumDx += num2; AimBuckets[num6].SumDy += num3; if (num > AimBuckets[num6].MaxAngle) { AimBuckets[num6].MaxAngle = num; } if (num5 > AimBuckets[num6].MaxAxisOffset) { AimBuckets[num6].MaxAxisOffset = num5; } string text = AimBucketNames[num6]; if (Once("aim." + text)) { Vector3 val4 = origin - position; Vector3 val5 = val4 - transform.forward * Vector3.Dot(val4, transform.forward); float num7 = Vector3.Angle(transform.forward, direction); Emit("AIM sample bucket=" + text + " weapon='" + weaponId + "' " + $"spread={spreadDegrees:F2}deg zeroSpreadProbe={AimProbeZeroSpread} " + $"range={magnitude:F2}m traceDistance={traceDistance:F2}m " + $"angleOffAxis={num:F3}deg rayVsCamera={num7:F3}deg " + $"viewport=({val3.x:F4},{val3.y:F4}) " + $"dViewport=({num2:F4},{num3:F4}) px@1080p=({num2 * 1920f:F1},{num3 * 1080f:F1}) " + "originOffsetFromCamera=" + ((Vector3)(ref val4)).ToString("F3") + " " + $"perpendicular={((Vector3)(ref val5)).magnitude:F3}m " + string.Format("fov={0:F1} hit='{1}'", gameplayCamera.fieldOfView, ((Object)(object)impactCollider != (Object)null) ? ((Object)impactCollider).name : "")); } int requiredSamplesPerBucket = RequiredSamplesPerBucket; if (AimBuckets[num6].Samples == requiredSamplesPerBucket && Once("aim.summary." + text)) { Emit(SummariseAimBucket(num6) + PendingBucketNote(requiredSamplesPerBucket)); } if (AimVerdictReady(requiredSamplesPerBucket) && Once("aim.verdict")) { Emit(ComposeAimVerdict(gameplayCamera, spreadDegrees, requiredSamplesPerBucket)); } } } private static string SummariseAimBucket(int index) { AimBucket aimBucket = AimBuckets[index]; if (aimBucket.Samples <= 0) { return "AIM SUMMARY bucket=" + AimBucketNames[index] + " samples=0"; } return $"AIM SUMMARY bucket={AimBucketNames[index]} samples={aimBucket.Samples} " + $"meanRange={aimBucket.SumRange / (double)aimBucket.Samples:F2}m " + $"meanAngleOffAxis={aimBucket.SumAngle / (double)aimBucket.Samples:F3}deg maxAngle={aimBucket.MaxAngle:F3}deg " + $"meanRadialViewport={aimBucket.SumRadial / (double)aimBucket.Samples:F5} " + $"worstAxisOffset={aimBucket.MaxAxisOffset:F5} " + "meanDx=" + (aimBucket.SumDx / (double)aimBucket.Samples).ToString("+0.00000;-0.00000") + " meanDy=" + (aimBucket.SumDy / (double)aimBucket.Samples).ToString("+0.00000;-0.00000"); } private static string PendingBucketNote(int required) { string text = string.Empty; for (int i = 0; i < AimBuckets.Length; i++) { if (AimBuckets[i].Samples < required) { text = text + ((text.Length > 0) ? ", " : string.Empty) + $"{AimBucketNames[i]} {AimBuckets[i].Samples}/{required}"; } } if (text.Length != 0) { return $" — verdict pending: {text}. (near <{4f:F0}m, mid {4f:F0}-{20f:F0}m, far >{20f:F0}m)"; } return " — all buckets ready, verdict follows."; } private static bool AimVerdictReady(int required) { for (int i = 0; i < AimBuckets.Length; i++) { if (AimBuckets[i].Samples < required) { return false; } } return true; } private static string ComposeAimVerdict(Camera camera, float spreadDegrees, int required) { bool aimProbeZeroSpread = AimProbeZeroSpread; float num = Mathf.Tan(camera.fieldOfView * 0.5f * (MathF.PI / 180f)); float num2 = ((num > 1E-06f) ? (Mathf.Tan(Mathf.Max(0f, spreadDegrees) * (MathF.PI / 180f)) / (2f * num)) : 0f); Builder.Length = 0; Builder.Append("AIM VERDICT mode=").Append(aimProbeZeroSpread ? "ZERO-SPREAD" : "SPREAD-ON").Append(" spread=") .Append(spreadDegrees.ToString("F2")) .Append("deg") .Append(" fov=") .Append(camera.fieldOfView.ToString("F1")) .Append(" samplesPerBucket>=") .Append(required); for (int i = 0; i < AimBuckets.Length; i++) { Builder.Append("\n ").Append(SummariseAimBucket(i)); } double num3 = MeanAngle(0); double num4 = MeanAngle(2); double num5 = ((num4 > 1E-06) ? (num3 / num4) : double.PositiveInfinity); float num6 = 0f; int num7 = 0; double num8 = 0.0; int num9 = 0; double num10 = 0.0; int num11 = 0; string value = "x"; bool flag = true; for (int j = 0; j < AimBuckets.Length; j++) { int num12 = Mathf.Max(1, AimBuckets[j].Samples); if (AimBuckets[j].MaxAxisOffset > num6) { num6 = AimBuckets[j].MaxAxisOffset; num7 = j; } double num13 = AimBuckets[j].SumRadial / (double)num12; if (num13 > num8) { num8 = num13; num9 = j; } double num14 = 0.0020000000949949026 + (aimProbeZeroSpread ? 0.0 : ((double)(num2 / Mathf.Sqrt((float)num12)))); double value2 = AimBuckets[j].SumDx / (double)num12; double value3 = AimBuckets[j].SumDy / (double)num12; if (Math.Abs(value2) > num14 || Math.Abs(value3) > num14) { flag = false; } if (Math.Abs(value2) > num10) { num10 = Math.Abs(value2); num11 = j; value = "x"; } if (Math.Abs(value3) > num10) { num10 = Math.Abs(value3); num11 = j; value = "y"; } } bool flag2 = num5 <= 1.5; bool flag3; if (aimProbeZeroSpread) { flag3 = num6 <= 0.002f; Builder.Append("\n (A) impact on the crosshair, worst |dViewport| axis <= ").Append(0.002f.ToString("F4")).Append(" : ") .Append(flag3 ? "PASS" : "FAIL") .Append(" worst=") .Append(num6.ToString("F5")) .Append(" (") .Append(AimBucketNames[num7]) .Append(", ") .Append((num6 * 1080f).ToString("F1")) .Append(" px @1080p)"); } else { float num15 = 0.75f * num2; flag3 = num8 <= (double)num15; Builder.Append("\n (A') spread-on, worst mean radial <= 0.75 x cone (").Append(num15.ToString("F5")).Append(") : ") .Append(flag3 ? "PASS" : "FAIL") .Append(" worst=") .Append(num8.ToString("F5")) .Append(" (") .Append(AimBucketNames[num9]) .Append(')'); } Builder.Append("\n (B) near angle <= ").Append(1.5f.ToString("F2")).Append("x far angle : ") .Append(flag2 ? "PASS" : "FAIL") .Append(" near=") .Append(num3.ToString("F3")) .Append("deg far=") .Append(num4.ToString("F3")) .Append("deg ratio=") .Append(double.IsInfinity(num5) ? "inf" : num5.ToString("F2")) .Append('x'); Builder.Append("\n (C) pattern centred on the crosshair, |mean d| per axis : ").Append(flag ? "PASS" : "FAIL").Append(" worst=") .Append(num10.ToString("F5")) .Append(" on ") .Append(value) .Append(" (") .Append(AimBucketNames[num11]) .Append(')'); bool flag4 = flag3 && flag2 && flag; Builder.Append("\n RESULT: ").Append(flag4 ? "PASS" : "FAIL").Append(" — ") .Append(flag4 ? "the shot ray converges on the crosshair at every range." : (flag2 ? "impacts are displaced from the crosshair; the error does NOT grow as range closes." : "parallel-offset ray: the impact is displaced by a fixed world-space offset, so the angular error grows as range closes.")); return Builder.ToString(); } private static double MeanAngle(int index) { if (AimBuckets[index].Samples <= 0) { return 0.0; } return AimBuckets[index].SumAngle / (double)AimBuckets[index].Samples; } internal static void SampleAliveOverTime(GameObject instance, string key) { if (!((Object)(object)instance == (Object)null)) { instance.AddComponent().Key = key; } } internal static string DescribeCameraRenderState() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) Camera val = ResolveViewCamera(); if ((Object)(object)val == (Object)null) { return "RENDERSTATE camera="; } Builder.Length = 0; Builder.Append("RENDERSTATE camera='").Append(((Object)val).name).Append('\'') .Append(" enabled=") .Append(((Behaviour)val).enabled) .Append(" cullingMask=0x") .Append(val.cullingMask.ToString("X")); HDAdditionalCameraData component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null) { Builder.Append(" hdData="); } else { Builder.Append(" customFrameSettings=").Append(component.customRenderingSettings); if (component.customRenderingSettings) { FrameSettings renderingPathCustomFrameSettings = component.renderingPathCustomFrameSettings; Builder.Append(" transparentObjects=").Append(((FrameSettings)(ref renderingPathCustomFrameSettings)).IsEnabled((FrameSettingsField)3)).Append(" transparentPrepass=") .Append(((FrameSettings)(ref renderingPathCustomFrameSettings)).IsEnabled((FrameSettingsField)8)) .Append(" transparentPostpass=") .Append(((FrameSettings)(ref renderingPathCustomFrameSettings)).IsEnabled((FrameSettingsField)9)); } } CustomPassVolume[] array = Object.FindObjectsOfType(); Builder.Append(" customPassVolumes=").Append(array.Length); foreach (CustomPassVolume val2 in array) { if ((Object)(object)val2 == (Object)null) { continue; } Builder.Append("\n customPass '").Append(((Object)val2).name).Append('\'') .Append(" enabled=") .Append(((Behaviour)val2).enabled && ((Component)val2).gameObject.activeInHierarchy) .Append(" global=") .Append(val2.isGlobal) .Append(" injectionPoint=") .Append(val2.injectionPoint) .Append(" passes=["); for (int j = 0; j < val2.customPasses.Count; j++) { if (j > 0) { Builder.Append(", "); } CustomPass val3 = val2.customPasses[j]; Builder.Append((val3 != null) ? (val3.name + "(" + (val3.enabled ? "on" : "off") + ")") : ""); } Builder.Append(']'); } Volume[] array2 = Object.FindObjectsOfType(); Builder.Append("\n volumes=").Append(array2.Length); foreach (Volume val4 in array2) { if ((Object)(object)val4 == (Object)null || (Object)(object)val4.profile == (Object)null) { continue; } Builder.Append("\n volume '").Append(((Object)val4).name).Append('\'') .Append(" enabled=") .Append(((Behaviour)val4).enabled && ((Component)val4).gameObject.activeInHierarchy) .Append(" global=") .Append(val4.isGlobal) .Append(" weight=") .Append(val4.weight.ToString("F2")) .Append(" priority=") .Append(val4.priority.ToString("F1")) .Append(" components=["); bool flag = true; foreach (VolumeComponent component2 in val4.profile.components) { if (!((Object)(object)component2 == (Object)null) && component2.active) { if (!flag) { Builder.Append(", "); } flag = false; Builder.Append(((object)component2).GetType().Name); } } Builder.Append(']'); } return Builder.ToString(); } internal static Camera ResolveViewCamera() { PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) { return val.gameplayCamera; } return Camera.main; } } internal static class WeaponVfxHousekeeping { private sealed class WeaponVfxHousekeepingBehaviour : MonoBehaviour { private void Update() { WeaponMuzzleFlash.RetireExpiredExternal(); WeaponImpactEffects.RetireExpiredExternal(); WeaponBulletHoleDecals.UpdateExternal(); } } private static WeaponVfxHousekeepingBehaviour _driver; internal static void EnsureDriver() { //IL_0013: 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_001e: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_driver != (Object)null)) { GameObject val = new GameObject("Y4NGZWeaponVfxHousekeeping"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; _driver = val.AddComponent(); } } } internal static class WeaponVfxRuntimeAssets { internal const string BundleName = "y4ngz-upgrades-weaponvfx.lethalbundle"; internal const string MuzzleFlash01 = "Y4NGZ_MuzzleFlash_01"; internal const string MuzzleFlash02 = "Y4NGZ_MuzzleFlash_02"; internal const string MuzzleFlash03 = "Y4NGZ_MuzzleFlash_03"; internal const string HitImpactConcrete01 = "Y4NGZ_HitImpact_Concrete_01"; internal const string HitImpactConcrete02 = "Y4NGZ_HitImpact_Concrete_02"; internal const string HitImpactMetal01 = "Y4NGZ_HitImpact_Metal_01"; internal const string HitImpactWood01 = "Y4NGZ_HitImpact_Wood_01"; internal const string HitImpactWood02 = "Y4NGZ_HitImpact_Wood_02"; internal const string BulletHoleDefault01 = "Y4NGZ_BulletHole_Default_01"; internal const string BulletHoleDefault02 = "Y4NGZ_BulletHole_Default_02"; internal const string BulletHoleDefault03 = "Y4NGZ_BulletHole_Default_03"; internal const string BulletHoleDefault04 = "Y4NGZ_BulletHole_Default_04"; internal const string BulletHoleDefault05 = "Y4NGZ_BulletHole_Default_05"; internal const string BulletHoleMetal01 = "Y4NGZ_BulletHole_Metal_01"; internal const string BulletHoleMetal02 = "Y4NGZ_BulletHole_Metal_02"; internal const string BulletHoleMetal03 = "Y4NGZ_BulletHole_Metal_03"; internal const string BulletHoleMetal04 = "Y4NGZ_BulletHole_Metal_04"; internal const string BulletHoleWood01 = "Y4NGZ_BulletHole_Wood_01"; internal const string BulletHoleWood02 = "Y4NGZ_BulletHole_Wood_02"; internal const string BulletHoleWood03 = "Y4NGZ_BulletHole_Wood_03"; internal const string BulletHoleWood04 = "Y4NGZ_BulletHole_Wood_04"; internal const string BulletHoleWood05 = "Y4NGZ_BulletHole_Wood_05"; private static readonly Dictionary PrefabCache = new Dictionary(); private static readonly Dictionary SourceByAsset = new Dictionary(); private static AssetBundle _bundle; private static bool _loadAttempted; private static float _nextMissingLogAt; internal static string SourceFor(string assetName) { if (assetName == null || !SourceByAsset.TryGetValue(assetName, out var value)) { return null; } return value; } internal static GameObject LoadPrefab(string assetName) { if (string.IsNullOrWhiteSpace(assetName)) { return null; } if (PrefabCache.TryGetValue(assetName, out var value) && (Object)(object)value != (Object)null) { return value; } GameObject val = LoadFromAnyBundle(assetName); if ((Object)(object)val != (Object)null) { PrefabCache[assetName] = val; return val; } if (Time.unscaledTime >= _nextMissingLogAt) { _nextMissingLogAt = Time.unscaledTime + 15f; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeaponVfx] '" + assetName + "' could not be loaded. Missing y4ngz-upgrades-weaponvfx.lethalbundle?")); } } return null; } private static GameObject LoadFromAnyBundle(string assetName) { foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if (!((Object)(object)allLoadedAssetBundle == (Object)null)) { GameObject val = allLoadedAssetBundle.LoadAsset(assetName); if ((Object)(object)val != (Object)null) { SourceByAsset[assetName] = "already-loaded:" + ((Object)allLoadedAssetBundle).name; return val; } } } EnsureBundleLoaded(); GameObject obj = (((Object)(object)_bundle != (Object)null) ? _bundle.LoadAsset(assetName) : null); if ((Object)(object)obj != (Object)null) { SourceByAsset[assetName] = "LoadFromFile:" + ((Object)_bundle).name; } return obj; } private static void EnsureBundleLoaded() { if (_loadAttempted) { return; } _loadAttempted = true; string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "y4ngz-upgrades-weaponvfx.lethalbundle"); if (!File.Exists(text)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeaponVfx] Bundle not found at " + text + ".")); } return; } _bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)_bundle == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZWeaponVfx] Failed to load bundle at " + text + ".")); } } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("[Y4NGZWeaponVfx] Loaded y4ngz-upgrades-weaponvfx.lethalbundle (" + ((Object)_bundle).name + ").")); } } } } internal enum WeaponVisualBoreFailure { None, MissingArguments, NonAuthoritativeHost, BoreUnresolved } internal static class WeaponVisualBore { internal static bool TryResolve(GameObject worldInstance, WeaponLandmarks landmarks, IY4NGZFpWeapon fpWeapon, PlayerControllerB fpHeldBy, out Vector3 origin, out Vector3 direction, out Transform host, out bool firstPerson, out WeaponVisualBoreFailure failure) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) origin = Vector3.zero; direction = Vector3.forward; host = null; firstPerson = false; failure = WeaponVisualBoreFailure.None; if ((Object)(object)worldInstance == (Object)null || landmarks == null) { failure = WeaponVisualBoreFailure.MissingArguments; return false; } firstPerson = WeaponFirstPersonAnimation.TryGetFirstPersonBore(fpWeapon, fpHeldBy, landmarks, out origin, out direction, out host); if (firstPerson) { return true; } if (!WeaponLandmarkResolver.ResolvedHostIsAuthoritative(worldInstance, landmarks)) { failure = WeaponVisualBoreFailure.NonAuthoritativeHost; return false; } if (!WeaponLandmarkResolver.TryGetBore(worldInstance, landmarks, out origin, out direction)) { failure = WeaponVisualBoreFailure.BoreUnresolved; return false; } host = WeaponLandmarkResolver.HostFor(worldInstance, landmarks); return true; } } internal static class WeaponVisuals { private sealed class VisualSpec { public string ConfigId; public string ChildName; public string FilePrefix; public string Label; public Func Pos; public Func Euler; public Func Scale; public Vector3 GripPos; public Vector3 GripEuler; public float WorldSizeFraction = 1f; public Mesh Mesh; public Material Material; public bool LoadAttempted; public float AutoScale = 1f; } internal const string VisualChildName = "Y4NGZ_HeavyShotgunVisual"; internal const string RevolverVisualChildName = "Y4NGZ_RevolverVisual"; internal const string FlamethrowerVisualChildName = "Y4NGZ_FlamethrowerVisual"; internal const string GrenadeLauncherVisualChildName = "Y4NGZ_GrenadeLauncherVisual"; internal static Vector3 HeavyShotgunPos = Vector3.zero; internal static Vector3 HeavyShotgunEuler = Vector3.zero; internal static float HeavyShotgunScale = 1f; internal static Vector3 RevolverPos = Vector3.zero; internal static Vector3 RevolverEuler = Vector3.zero; internal static float RevolverScale = 1f; private static readonly VisualSpec[] Specs = new VisualSpec[2] { new VisualSpec { ConfigId = "heavy_shotgun", ChildName = "Y4NGZ_HeavyShotgunVisual", FilePrefix = "heavy_shotgun", Label = "Heavy Shotgun", Pos = () => HeavyShotgunPos, Euler = () => HeavyShotgunEuler, Scale = () => HeavyShotgunScale, GripPos = new Vector3(0.0279f, -0.0221f, -0.0887f), GripEuler = new Vector3(7.4f, 169.4f, 301.8f) }, new VisualSpec { ConfigId = "revolver", ChildName = "Y4NGZ_RevolverVisual", FilePrefix = "revolver", Label = "Revolver", Pos = () => RevolverPos, Euler = () => RevolverEuler, Scale = () => RevolverScale, GripPos = new Vector3(0.0321f, -0.0113f, -0.0826f), GripEuler = new Vector3(0.6f, 169.9f, 303.4f), WorldSizeFraction = 0.4f } }; private static VisualSpec SpecFor(string configId) { VisualSpec[] specs = Specs; foreach (VisualSpec visualSpec in specs) { if (visualSpec.ConfigId == configId) { return visualSpec; } } return null; } private static string AssetDir() { return WeaponAssetLoader.AssetDirectory(); } private static void EnsureLoaded(VisualSpec spec) { if (spec == null || spec.LoadAttempted) { return; } spec.LoadAttempted = true; try { string text = AssetDir(); if (text != null) { spec.Mesh = WeaponAssetLoader.LoadMesh(Path.Combine(text, spec.FilePrefix + ".mesh"), spec.Label); spec.Material = WeaponAssetLoader.BuildMaterial(text, spec.FilePrefix, spec.Label); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons] Failed to load {spec.Label} visual assets: {arg}"); } } } internal static bool Apply(string configId, GameObject root, ShotgunItem shotgun) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown if (configId == "flame_thrower") { return ApplyFlamethrower(root, shotgun); } if (configId == "grenade_launcher") { return ApplyGrenadeLauncher(root, shotgun); } VisualSpec visualSpec = SpecFor(configId); EnsureLoaded(visualSpec); if (visualSpec == null || (Object)(object)root == (Object)null || (Object)(object)visualSpec.Mesh == (Object)null) { return false; } visualSpec.AutoScale = ComputeAutoScale(visualSpec.Mesh, root, shotgun, out var rootLossyScale, out var vanWorldLongest, out var ourMeshLongest, out var referenceBranch) * visualSpec.WorldSizeFraction; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZWeapons] {visualSpec.Label} auto-scale = {visualSpec.AutoScale:0.###} (x config scale), rootLossy={FormatVector(rootLossyScale)}, vanWorldLongest={vanWorldLongest:0.###}, ourMeshLongest={ourMeshLongest:0.###}, branch={referenceBranch}."); } RemoveVanillaRenderComponents(root, shotgun); if ((Object)(object)shotgun != (Object)null) { DeactivateRenderer((Renderer)(object)shotgun.shotgunShellLeft); DeactivateRenderer((Renderer)(object)shotgun.shotgunShellRight); DeactivateRenderer((Renderer)(object)shotgun.shotgunShellInHand); } Transform val = root.transform.Find(visualSpec.ChildName); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } GameObject val2 = new GameObject(visualSpec.ChildName); val2.transform.SetParent(root.transform, false); val2.layer = root.layer; val2.AddComponent().sharedMesh = visualSpec.Mesh; MeshRenderer val3 = val2.AddComponent(); ((Renderer)val3).sharedMaterial = visualSpec.Material; ApplyTransform(visualSpec, val2.transform); if ((Object)(object)shotgun != (Object)null) { ((GrabbableObject)shotgun).mainObjectRenderer = val3; } return true; } internal static bool ApplyHeavyShotgun(GameObject root, ShotgunItem shotgun) { return Apply("heavy_shotgun", root, shotgun); } internal static MeshRenderer TryMountNativeModel(string configId, GameObject visualRoot) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_004c: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) VisualSpec visualSpec = SpecFor(configId); EnsureLoaded(visualSpec); if (visualSpec == null || (Object)(object)visualRoot == (Object)null || (Object)(object)visualSpec.Mesh == (Object)null) { return null; } GameObject val = new GameObject(visualSpec.FilePrefix); val.transform.SetParent(visualRoot.transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; val.layer = visualRoot.layer; val.AddComponent().sharedMesh = visualSpec.Mesh; MeshRenderer val2 = val.AddComponent(); ((Renderer)val2).sharedMaterial = visualSpec.Material; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons] Mounted native " + visualSpec.Label + " from loose '" + visualSpec.FilePrefix + "' assets " + $"({visualSpec.Mesh.vertexCount} verts; landmark frame preserved).")); } return val2; } internal static void RetuneInstance(GameObject instance) { if ((Object)(object)instance == (Object)null) { return; } VisualSpec[] specs = Specs; foreach (VisualSpec visualSpec in specs) { Transform val = instance.transform.Find(visualSpec.ChildName); if ((Object)(object)val != (Object)null) { ApplyTransform(visualSpec, val); } } } internal static Renderer[] GetVisualRenderers(GameObject instance) { if ((Object)(object)instance == (Object)null) { return Array.Empty(); } Renderer[] nativeVisualRenderers = GetNativeVisualRenderers(instance); if (nativeVisualRenderers.Length != 0) { return nativeVisualRenderers; } Transform val = instance.transform.Find("Y4NGZ_FlamethrowerVisual"); if ((Object)(object)val != (Object)null) { return ((Component)val).GetComponentsInChildren(true); } Transform val2 = instance.transform.Find("Y4NGZ_GrenadeLauncherVisual"); if ((Object)(object)val2 != (Object)null) { return ((Component)val2).GetComponentsInChildren(true); } VisualSpec[] specs = Specs; foreach (VisualSpec visualSpec in specs) { Transform val3 = instance.transform.Find(visualSpec.ChildName); if ((Object)(object)val3 != (Object)null) { return ((Component)val3).GetComponentsInChildren(true); } } return Array.Empty(); } private static Renderer[] GetNativeVisualRenderers(GameObject instance) { Y4NGZWeaponBase component = instance.GetComponent(); WeaponLandmarks weaponLandmarks = (((Object)(object)component != (Object)null) ? component.Landmarks : null); if (weaponLandmarks == null || !WeaponLandmarkResolver.ResolvedHostIsAuthoritative(instance, weaponLandmarks)) { return Array.Empty(); } Transform val = WeaponLandmarkResolver.HostFor(instance, weaponLandmarks); if ((Object)(object)val == (Object)null) { return Array.Empty(); } List list = new List(); Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { if ((val2 is MeshRenderer || val2 is SkinnedMeshRenderer) && !IsUnderParticleEffect(((Component)val2).transform, val)) { list.Add(val2); } } if (list.Count <= 0) { return Array.Empty(); } return list.ToArray(); } private static bool IsUnderParticleEffect(Transform renderer, Transform root) { Transform val = renderer; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { if ((Object)(object)((Component)val).GetComponent() != (Object)null) { return true; } val = val.parent; } return false; } private static bool ApplyFlamethrower(GameObject root, ShotgunItem shotgun) { //IL_0060: 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_0065: 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_0069: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) GameObject val = FlamethrowerContentAssets.LoadPropPrefab(); if ((Object)(object)val == (Object)null || (Object)(object)root == (Object)null) { return false; } Renderer val2 = (Renderer)(object)(((Object)(object)shotgun != (Object)null) ? ((GrabbableObject)shotgun).mainObjectRenderer : null); if ((Object)(object)val2 == (Object)null) { val2 = FindLargestWorldRenderer(root, shotgun); } bool num = (Object)(object)val2 != (Object)null; Bounds val3 = (Bounds)(num ? val2.bounds : new Bounds(root.transform.position, Vector3.one)); Vector3 localPosition = (num ? root.transform.InverseTransformPoint(((Component)val2).transform.position) : Vector3.zero); Quaternion localRotation = (num ? (Quaternion.Inverse(root.transform.rotation) * ((Component)val2).transform.rotation) : Quaternion.identity); RemoveVanillaRenderComponents(root, shotgun); GameObject val4 = Object.Instantiate(val, root.transform, false); ((Object)val4).name = "Y4NGZ_FlamethrowerVisual"; FlamethrowerContentAssets.ApplyRuntimeWeaponMaterial(val4); int num2 = (num ? ((Component)val2).gameObject.layer : root.layer); SetLayerRecursive(val4.transform, num2); if (num) { val4.transform.localPosition = localPosition; val4.transform.localRotation = localRotation; } Bounds val5 = CombinedBounds(val4); float num3 = LongestAxis(((Bounds)(ref val5)).size); float num4 = LongestAxis(((Bounds)(ref val3)).size); float num5 = ((num3 > 0.0001f && num4 > 0.0001f) ? (num4 / num3) : 1f); val4.transform.localScale = Vector3.one * num5; Bounds val6 = CombinedBounds(val4); Transform transform = val4.transform; transform.position += ((Bounds)(ref val3)).center - ((Bounds)(ref val6)).center; if ((Object)(object)shotgun != (Object)null) { DeactivateRenderer((Renderer)(object)shotgun.shotgunShellLeft); DeactivateRenderer((Renderer)(object)shotgun.shotgunShellRight); DeactivateRenderer((Renderer)(object)shotgun.shotgunShellInHand); ((GrabbableObject)shotgun).mainObjectRenderer = val4.GetComponentInChildren(true); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Flamethrower] world prop mounted (autoScale={num5:0.###}, authoredLongest={num3:0.###}, " + $"vanillaLongest={num4:0.###}, rootLayer={root.layer}, visualLayer={num2}, " + "localPosition=" + FormatVector(val4.transform.localPosition) + ").")); } return true; } private static bool ApplyGrenadeLauncher(GameObject root, ShotgunItem shotgun) { //IL_0060: 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_0065: 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_0069: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) GameObject val = GrenadeLauncherContentAssets.LoadPropPrefab(); if ((Object)(object)val == (Object)null || (Object)(object)root == (Object)null) { return false; } Renderer val2 = (Renderer)(object)(((Object)(object)shotgun != (Object)null) ? ((GrabbableObject)shotgun).mainObjectRenderer : null); if ((Object)(object)val2 == (Object)null) { val2 = FindLargestWorldRenderer(root, shotgun); } bool num = (Object)(object)val2 != (Object)null; Bounds val3 = (Bounds)(num ? val2.bounds : new Bounds(root.transform.position, Vector3.one)); Vector3 localPosition = (num ? root.transform.InverseTransformPoint(((Component)val2).transform.position) : Vector3.zero); Quaternion localRotation = (num ? (Quaternion.Inverse(root.transform.rotation) * ((Component)val2).transform.rotation) : Quaternion.identity); RemoveVanillaRenderComponents(root, shotgun); GameObject val4 = Object.Instantiate(val, root.transform, false); ((Object)val4).name = "Y4NGZ_GrenadeLauncherVisual"; GrenadeLauncherContentAssets.ApplyRuntimeWeaponMaterial(val4); int num2 = (num ? ((Component)val2).gameObject.layer : root.layer); SetLayerRecursive(val4.transform, num2); if (num) { val4.transform.localPosition = localPosition; val4.transform.localRotation = localRotation; } Bounds val5 = CombinedBounds(val4); float num3 = LongestAxis(((Bounds)(ref val5)).size); float num4 = LongestAxis(((Bounds)(ref val3)).size); float num5 = ((num3 > 0.0001f && num4 > 0.0001f) ? (num4 / num3) : 1f); val4.transform.localScale = Vector3.one * num5; Bounds val6 = CombinedBounds(val4); Transform transform = val4.transform; transform.position += ((Bounds)(ref val3)).center - ((Bounds)(ref val6)).center; if ((Object)(object)shotgun != (Object)null) { DeactivateRenderer((Renderer)(object)shotgun.shotgunShellLeft); DeactivateRenderer((Renderer)(object)shotgun.shotgunShellRight); DeactivateRenderer((Renderer)(object)shotgun.shotgunShellInHand); ((GrabbableObject)shotgun).mainObjectRenderer = val4.GetComponentInChildren(true); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[GrenadeLauncher] world prop mounted (autoScale={num5:0.###}, authoredLongest={num3:0.###}, " + $"vanillaLongest={num4:0.###}, rootLayer={root.layer}, visualLayer={num2}, " + "localPosition=" + FormatVector(val4.transform.localPosition) + ").")); } return true; } private static Renderer FindLargestWorldRenderer(GameObject root, ShotgunItem shotgun) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0061: Unknown result type (might be due to invalid IL or missing references) Renderer result = null; float num = 0f; Renderer[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || IsShotgunShellRenderer((MeshRenderer)(object)((val is MeshRenderer) ? val : null), shotgun)) { continue; } Mesh rendererMesh = GetRendererMesh(val); if (!((Object)(object)rendererMesh == (Object)null)) { Bounds bounds = rendererMesh.bounds; float num2 = LongestAxis(Vector3.Scale(((Bounds)(ref bounds)).size, ((Component)val).transform.lossyScale)); if (num2 > num) { result = val; num = num2; } } } return result; } private static Bounds CombinedBounds(GameObject root) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = root.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return new Bounds(root.transform.position, Vector3.one); } Bounds bounds = componentsInChildren[0].bounds; for (int i = 1; i < componentsInChildren.Length; i++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[i].bounds); } return bounds; } private static void SetLayerRecursive(Transform root, int layer) { ((Component)root).gameObject.layer = layer; for (int i = 0; i < root.childCount; i++) { SetLayerRecursive(root.GetChild(i), layer); } } internal static Renderer[] GetHeavyShotgunVisualRenderers(GameObject instance) { return GetVisualRenderers(instance); } internal static Material GetMaterial(string configId) { VisualSpec visualSpec = SpecFor(configId); EnsureLoaded(visualSpec); return visualSpec?.Material; } internal static Material GetHeavyShotgunMaterial() { return GetMaterial("heavy_shotgun"); } private static void ApplyTransform(VisualSpec spec, Transform t) { //IL_0036: 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_0045: 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_0048: Unknown result type (might be due to invalid IL or missing references) //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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0083: 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_0098: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) float num = ((spec.Scale != null) ? spec.Scale() : 1f); float num2 = ((num <= 0f) ? 1f : num); float num3 = spec.AutoScale * num2; Quaternion val = Quaternion.Inverse(Quaternion.Euler(spec.GripEuler)); Vector3 val2 = val * -spec.GripPos * num3; Vector3 val3 = ((spec.Pos != null) ? spec.Pos() : Vector3.zero); Vector3 val4 = ((spec.Euler != null) ? spec.Euler() : Vector3.zero); t.localRotation = val * Quaternion.Euler(val4); t.localPosition = val2 + val3; t.localScale = Vector3.one * num3; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons] " + spec.Label + " visual seated: gripMount=" + FormatVector(((Quaternion)(ref val)).eulerAngles) + ", gripOffset=" + FormatVector(val2) + ", cfgPos=" + FormatVector(val3) + ", cfgEuler=" + FormatVector(val4) + ", " + $"worldScale={num3:0.####} -> localPos={FormatVector(t.localPosition)}, " + "localEuler=" + FormatVector(t.localEulerAngles) + ".")); } } private static float ComputeAutoScale(Mesh ourMesh, GameObject root, ShotgunItem shotgun, out Vector3 rootLossyScale, out float vanWorldLongest, out float ourMeshLongest, out string referenceBranch) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0034: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) rootLossyScale = (((Object)(object)root != (Object)null) ? root.transform.lossyScale : Vector3.one); vanWorldLongest = 0f; Bounds bounds = ourMesh.bounds; ourMeshLongest = LongestAxis(((Bounds)(ref bounds)).size); referenceBranch = "last-resort"; if (ourMeshLongest < 1E-05f) { return 1f; } float num = LongestAxis(rootLossyScale); if (num < 1E-05f) { return 1f; } Renderer val = (Renderer)(object)(((Object)(object)shotgun != (Object)null) ? ((GrabbableObject)shotgun).mainObjectRenderer : null); Mesh val2 = GetRendererMesh(val); if ((Object)(object)val2 != (Object)null) { referenceBranch = "mainObjectRenderer"; } if ((Object)(object)val2 == (Object)null && (Object)(object)root != (Object)null) { float num2 = 0f; Renderer[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Renderer val3 in componentsInChildren) { Mesh rendererMesh = GetRendererMesh(val3); if (!((Object)(object)rendererMesh == (Object)null)) { bounds = rendererMesh.bounds; float num3 = LongestAxis(Vector3.Scale(((Bounds)(ref bounds)).size, ((Component)val3).transform.lossyScale)); if (num3 > num2) { num2 = num3; val = val3; val2 = rendererMesh; referenceBranch = "fallback-largest"; } } } } if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { vanWorldLongest = 1.4f; return vanWorldLongest / (num * ourMeshLongest); } bounds = val2.bounds; vanWorldLongest = LongestAxis(Vector3.Scale(((Bounds)(ref bounds)).size, ((Component)val).transform.lossyScale)); if (vanWorldLongest > 1E-05f) { return vanWorldLongest / (num * ourMeshLongest); } referenceBranch = "last-resort"; vanWorldLongest = 1.4f; return vanWorldLongest / (num * ourMeshLongest); } private static Mesh GetRendererMesh(Renderer r) { if ((Object)(object)r == (Object)null) { return null; } MeshFilter component = ((Component)r).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { return component.sharedMesh; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null); if (val == null) { return null; } return val.sharedMesh; } private static float LongestAxis(Vector3 v) { //IL_0000: 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) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(v.x, Mathf.Max(v.y, v.z)); } private static string FormatVector(Vector3 v) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) return $"({v.x:0.###}, {v.y:0.###}, {v.z:0.###})"; } private static void RemoveVanillaRenderComponents(GameObject root, ShotgunItem shotgun) { if ((Object)(object)root == (Object)null) { return; } MeshRenderer[] componentsInChildren = root.GetComponentsInChildren(true); foreach (MeshRenderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !IsShotgunShellRenderer(val, shotgun)) { MeshFilter component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Object.Destroy((Object)(object)val); } } SkinnedMeshRenderer[] componentsInChildren2 = root.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(false); } } } private static bool IsShotgunShellRenderer(MeshRenderer renderer, ShotgunItem shotgun) { if ((Object)(object)shotgun != (Object)null) { if (!((Object)(object)renderer == (Object)(object)shotgun.shotgunShellLeft) && !((Object)(object)renderer == (Object)(object)shotgun.shotgunShellRight)) { return (Object)(object)renderer == (Object)(object)shotgun.shotgunShellInHand; } return true; } return false; } private static void DeactivateRenderer(Renderer r) { if ((Object)(object)r != (Object)null) { ((Component)r).gameObject.SetActive(false); } } } internal enum WeaponWorldImpactFamily { Default, Metal, Wood } internal struct WeaponHit { public Vector3 Point; public Vector3 Normal; public Collider Collider; public float Distance; public bool HitEnemy; public int SurfaceIndex; } internal static class Y4NGZWeaponBallistics { private struct EnemyPelletHit { public bool Hit; public Vector3 Point; public Vector3 Normal; public Collider Collider; public float Distance; } private const int EnemyMask = 524288; private const float MinimumImpactDistance = 0.05f; private const float EnemyCastBackoffMeters = 1f; internal static bool LegacyEnemySpherecast; private static readonly RaycastHit[] EnemyHits = (RaycastHit[])(object)new RaycastHit[16]; private static readonly List HitsThisShot = new List(16); private static readonly List HitEnemiesThisPellet = new List(8); private static int WorldMask { get { if (!((Object)(object)StartOfRound.Instance != (Object)null)) { return -1; } return StartOfRound.Instance.collidersAndRoomMaskAndDefault; } } internal static List ResolveShot(Y4NGZWeaponBase weapon, WeaponConfig config, Vector3 origin, Vector3 forward, uint seed, float effectiveSpreadDegrees, PlayerControllerB firedBy) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) HitsThisShot.Clear(); if (config == null) { return HitsThisShot; } int num = Mathf.Max(1, config.PelletCount); float num2 = Mathf.Max(1f, config.MaxRangeMeters); int worldMask = WorldMask; bool flag = (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsServer; float spreadDegrees = (WeaponVfxDiagnostics.AimProbeZeroSpread ? 0f : Mathf.Max(0f, effectiveSpreadDegrees)); RaycastHit val2 = default(RaycastHit); for (int i = 0; i < num; i++) { Vector3 val = ApplySpread(forward, spreadDegrees, seed, i); bool num3 = Physics.Raycast(origin, val, ref val2, num2, worldMask, (QueryTriggerInteraction)1); bool flag2 = num3 && ((RaycastHit)(ref val2)).distance >= 0.05f; if (num3 && !flag2 && WeaponVfxDiagnostics.Once("fire.passthrough")) { WeaponVfxDiagnostics.Emit("Pellet passed through '" + (((Object)(object)((RaycastHit)(ref val2)).collider != (Object)null) ? ((Object)((RaycastHit)(ref val2)).collider).name : "") + "' at " + $"{((RaycastHit)(ref val2)).distance:F3} m — inside the pass-through guard ({0.05f:F2} m), " + "so no impact was registered. Expected when the camera is clipping geometry."); } float reach = (flag2 ? ((RaycastHit)(ref val2)).distance : num2); EnemyPelletHit enemyPelletHit = (LegacyEnemySpherecast ? default(EnemyPelletHit) : ResolvePelletEnemies(weapon, config, origin, val, reach, flag, firedBy)); if (enemyPelletHit.Hit) { HitsThisShot.Add(new WeaponHit { Point = enemyPelletHit.Point, Normal = enemyPelletHit.Normal, Collider = enemyPelletHit.Collider, Distance = enemyPelletHit.Distance, HitEnemy = true, SurfaceIndex = -1 }); } else if (flag2) { HitsThisShot.Add(new WeaponHit { Point = ((RaycastHit)(ref val2)).point, Normal = ((RaycastHit)(ref val2)).normal, Collider = ((RaycastHit)(ref val2)).collider, Distance = ((RaycastHit)(ref val2)).distance, HitEnemy = false, SurfaceIndex = WeaponSurfaceClassifier.ResolveSurfaceIndex(((RaycastHit)(ref val2)).collider) }); } if (i == 0 && WeaponVfxDiagnostics.Enabled) { WeaponVfxDiagnostics.SampleShotAim(origin, val, flag2, ((RaycastHit)(ref val2)).point, ((RaycastHit)(ref val2)).distance, flag2 ? ((RaycastHit)(ref val2)).collider : null, config.Id, spreadDegrees, firedBy); } } ResolveLocalPlayerDamage(config, origin, forward, firedBy); if (LegacyEnemySpherecast && flag) { ResolveEnemyDamageLegacy(weapon, config, origin, forward, num2, firedBy); } return HitsThisShot; } private static Vector3 ApplySpread(Vector3 forward, float spreadDegrees, uint seed, int pelletIndex) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_000a: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_008d: 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) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (spreadDegrees <= 0f) { return ((Vector3)(ref forward)).normalized; } uint num = Hash(seed, (uint)pelletIndex); float num2 = (float)(num & 0xFFFF) / 65535f; float num3 = (float)((num >> 16) & 0xFFFF) / 65535f; float num4 = num2 * MathF.PI * 2f; float num5 = Mathf.Sqrt(num3) * spreadDegrees; Vector3 normalized = ((Vector3)(ref forward)).normalized; Vector3 val = Vector3.Normalize(Vector3.Cross((Mathf.Abs(Vector3.Dot(normalized, Vector3.up)) > 0.95f) ? Vector3.right : Vector3.up, normalized)); Vector3 val2 = Vector3.Cross(normalized, val); Vector3 val3 = val * Mathf.Cos(num4) + val2 * Mathf.Sin(num4); return Quaternion.AngleAxis(num5, val3) * normalized; } private static uint Hash(uint a, uint b) { int num = (int)a ^ ((int)b * -1640531527); int num2 = (num ^ (num >>> 15)) * 739982445; int num3 = (num2 ^ (num2 >>> 12)) * 695872825; return (uint)(num3 ^ (num3 >>> 15)); } private static void ResolveLocalPlayerDamage(WeaponConfig config, Vector3 origin, Vector3 forward, PlayerControllerB firedBy) { //IL_004b: 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_0052: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_006d: 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_007c: 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_00a8: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || val.isPlayerDead || (Object)(object)val.playerCollider == (Object)null || ((Object)(object)firedBy != (Object)null && (Object)(object)firedBy == (Object)(object)val)) { return; } Vector3 val2 = val.playerCollider.ClosestPoint(origin); Vector3 val3 = val2 - origin; float magnitude = ((Vector3)(ref val3)).magnitude; if (!(magnitude > config.MaxRangeMeters) && !(Vector3.Angle(forward, val3) > 30f) && !Physics.Linecast(origin, val2, WorldMask, (QueryTriggerInteraction)1)) { int num = DamageAtDistance(config, magnitude); if (num > 0) { val.DamagePlayer(num, true, true, (CauseOfDeath)7, 0, false, forward * 30f); ApplyShotFeedback(magnitude); } } } private static void ApplyShotFeedback(float distance) { if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.ShakeCamera((ScreenShakeType)(distance < 15f)); } if (distance < 5f && (Object)(object)SoundManager.Instance != (Object)null && SoundManager.Instance.timeSinceEarsStartedRinging > 16f) { SoundManager.Instance.earsRingingTimer = 0.8f; } } private static EnemyPelletHit ResolvePelletEnemies(Y4NGZWeaponBase weapon, WeaponConfig config, Vector3 origin, Vector3 direction, float reach, bool applyDamage, PlayerControllerB firedBy) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) EnemyPelletHit result = default(EnemyPelletHit); HitEnemiesThisPellet.Clear(); float num = Mathf.Max(0.01f, config.EnemyCastRadiusMeters); int num2 = Physics.SphereCastNonAlloc(new Ray(origin - direction * 1f, direction), num, EnemyHits, reach + 1f, 524288, (QueryTriggerInteraction)2); int worldMask = WorldMask; float num3 = float.MaxValue; int num4 = -1; EnemyAICollisionDetect val = null; for (int i = 0; i < num2; i++) { Transform transform = ((RaycastHit)(ref EnemyHits[i])).transform; if ((Object)(object)transform == (Object)null) { continue; } EnemyAICollisionDetect component = ((Component)transform).GetComponent(); if (!((Object)(object)component == (Object)null) && (!((Object)(object)weapon != (Object)null) || !((Object)(object)weapon.HeldByEnemy != (Object)null) || !((Object)(object)weapon.HeldByEnemy == (Object)(object)component.mainScript)) && ((RaycastHit)(ref EnemyHits[i])).distance != 0f && !Physics.Linecast(origin, ((RaycastHit)(ref EnemyHits[i])).point, worldMask, (QueryTriggerInteraction)1)) { float num5 = Vector3.Distance(origin, ((RaycastHit)(ref EnemyHits[i])).point); if (!(num5 >= num3)) { num3 = num5; num4 = i; val = component; } } } if (num4 < 0) { return result; } result.Hit = true; result.Point = ((RaycastHit)(ref EnemyHits[num4])).point; result.Normal = ((RaycastHit)(ref EnemyHits[num4])).normal; result.Collider = ((RaycastHit)(ref EnemyHits[num4])).collider; result.Distance = num3; IHittable val2 = default(IHittable); if (applyDamage && ((Component)((RaycastHit)(ref EnemyHits[num4])).transform).TryGetComponent(ref val2) && (!((Object)(object)val.mainScript != (Object)null) || !HitEnemiesThisPellet.Contains(val.mainScript))) { int num6 = ForceAtDistance(config, num3); if (num6 > 0 && val2.Hit(num6, direction, firedBy, true, -1) && (Object)(object)val.mainScript != (Object)null) { HitEnemiesThisPellet.Add(val.mainScript); } } if (result.Hit && WeaponVfxDiagnostics.Once("fire.enemycast")) { WeaponVfxDiagnostics.Emit($"Enemy cast (#116) radius={num:F2}m backoff={1f:F2}m " + $"reach={reach:F2}m candidates={num2} nearest={result.Distance:F2}m " + $"force={ForceAtDistance(config, result.Distance)} applyDamage={applyDamage} " + "collider='" + (((Object)(object)result.Collider != (Object)null) ? ((Object)result.Collider).name : "") + "'."); } return result; } private static void ResolveEnemyDamageLegacy(Y4NGZWeaponBase weapon, WeaponConfig config, Vector3 origin, Vector3 forward, float range, PlayerControllerB firedBy) { //IL_000a: 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_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_001b: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) HitEnemiesThisPellet.Clear(); int num = Physics.SphereCastNonAlloc(new Ray(origin - forward * 10f, forward), 5f, EnemyHits, Mathf.Min(range, 25f), 524288, (QueryTriggerInteraction)2); int worldMask = WorldMask; IHittable val = default(IHittable); for (int i = 0; i < num; i++) { Transform transform = ((RaycastHit)(ref EnemyHits[i])).transform; if ((Object)(object)transform == (Object)null) { continue; } EnemyAICollisionDetect component = ((Component)transform).GetComponent(); if (!((Object)(object)component == (Object)null) && (!((Object)(object)weapon != (Object)null) || !((Object)(object)weapon.HeldByEnemy != (Object)null) || !((Object)(object)weapon.HeldByEnemy == (Object)(object)component.mainScript)) && ((RaycastHit)(ref EnemyHits[i])).distance != 0f && !Physics.Linecast(origin, ((RaycastHit)(ref EnemyHits[i])).point, worldMask, (QueryTriggerInteraction)1) && ((Component)transform).TryGetComponent(ref val) && (!((Object)(object)component.mainScript != (Object)null) || !HitEnemiesThisPellet.Contains(component.mainScript))) { float distance = Vector3.Distance(origin, ((RaycastHit)(ref EnemyHits[i])).point); int num2 = ForceAtDistance(config, distance); if (num2 > 0 && val.Hit(num2, forward, firedBy, true, -1) && (Object)(object)component.mainScript != (Object)null) { HitEnemiesThisPellet.Add(component.mainScript); } } } } private static int DamageAtDistance(WeaponConfig config, float distance) { float num = Mathf.Clamp01(distance / Mathf.Max(1f, config.MaxRangeMeters)); return Mathf.RoundToInt(Mathf.Lerp((float)config.PlayerDamageClose, (float)config.PlayerDamageFar, num)); } private static int ForceAtDistance(WeaponConfig config, float distance) { float num = Mathf.Clamp01(distance / Mathf.Max(1f, config.MaxRangeMeters)); return Mathf.Max(0, Mathf.RoundToInt(Mathf.Lerp((float)config.EnemyDamageClose, (float)config.EnemyDamageFar, num))); } } internal class Y4NGZWeaponBase : GrabbableObject, IY4NGZFpWeapon { public string ConfigId = string.Empty; public int Magazine; public bool SafetyOn = true; public AudioClip FireClip; public AudioClip DryFireClip; public AudioClip ReloadStartClip; public AudioClip ReloadFinishClip; public AudioClip SafetyOnClip; public AudioClip SafetyOffClip; public AudioClip[] FireClips; public bool ApplyAuthoredGainToFireClips = true; public AudioClip[] FireMechanicalClips; public float[] FireMechanicalClipDelaySeconds; public AudioClip ReloadTacClip; public AudioClip ReloadEmptyClip; public AudioClip ReloadStageStartClip; public AudioClip ReloadStageLoopClip; public AudioClip ReloadStageEndClip; private int _fireClipCursor; public string MuzzleFlashPrefabName = "Y4NGZ_MuzzleFlash_01"; public float MuzzleFlashScale = 1f; private WeaponConfig _config; private float _nextFireTime; private bool _triggerHeld; private uint _nextShotId = 1u; private uint _lastAppliedShotId; private Coroutine _reloadRoutine; private Coroutine _reloadAudioRoutine; private PlayerControllerB _previousPlayerHeldBy; private AudioSource _audio; private bool _loadedFromSave; private bool _externallyInitialized; private WeaponPropAnimation _propAnimation; public bool IsReloading { get; private set; } internal EnemyAI HeldByEnemy { get; private set; } internal WeaponConfig Config => _config ?? (_config = WeaponCatalog.ById(ConfigId)); internal WeaponLandmarks Landmarks => WeaponLandmarkCatalog.ById(ConfigId); string IY4NGZFpWeapon.FpConfigId => ConfigId; GrabbableObject IY4NGZFpWeapon.FpGrabbable => (GrabbableObject)(object)this; ShotgunItem IY4NGZFpWeapon.FpLegacyShotgun => null; private bool HasStagedReloadAudio { get { if (!((Object)(object)ReloadStageStartClip != (Object)null) && !((Object)(object)ReloadStageLoopClip != (Object)null)) { return (Object)(object)ReloadStageEndClip != (Object)null; } return true; } } private bool HasAuthoredReloadAudio { get { if (!((Object)(object)ReloadTacClip != (Object)null) && !((Object)(object)ReloadEmptyClip != (Object)null)) { return HasStagedReloadAudio; } return true; } } public override void Start() { ((GrabbableObject)this).Start(); _config = WeaponCatalog.ById(ConfigId); _audio = ((Component)this).GetComponent(); if (!_externallyInitialized) { SafetyOn = _config != null && _config.StartsWithSafetyOn; } if (!_loadedFromSave && !_externallyInitialized && _config != null) { Magazine = _config.MagazineSize; } NativeWeaponRegistry.RetuneInstance(((Component)this).gameObject, _config); _propAnimation = WeaponPropAnimation.Attach(this); if (_config != null && WeaponVfxDiagnostics.Once("landmarks." + ConfigId)) { NativeWeaponRegistry.LogLandmarkState(((Component)this).gameObject, _config); } } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); Y4NGZWeaponNet.RegisterHandlers(); if (((NetworkBehaviour)this).IsServer) { PublishState(authoritative: true); } } public override void OnNetworkDespawn() { StopReload(); ((NetworkBehaviour)this).OnNetworkDespawn(); } public override void EquipItem() { ((GrabbableObject)this).EquipItem(); _previousPlayerHeldBy = base.playerHeldBy; if ((Object)(object)base.playerHeldBy != (Object)null) { base.playerHeldBy.equippedUsableItemQE = true; } TryDevGrantReserve(); WeaponSoundRegistry.ApplyToInstance(this); } private void TryDevGrantReserve() { if (!((NetworkBehaviour)this).IsOwner) { return; } WeaponConfig config = Config; if (config == null) { return; } int num = ((Plugin.WeaponsDevGrantShells != null) ? Plugin.WeaponsDevGrantShells.Value : 0); if (AmmoReserve.TryDevGrantOnce(config.AmmoType, num)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZNative] Dev-granted {num} rounds ({config.AmmoType}) on equip " + "(reserve was empty; once per ammo family per save).")); } } } public override void PocketItem() { ((GrabbableObject)this).PocketItem(); _triggerHeld = false; StopReload(); } public override void DiscardItem() { _triggerHeld = false; StopReload(); if ((Object)(object)_previousPlayerHeldBy != (Object)null) { _previousPlayerHeldBy.equippedUsableItemQE = false; } ((GrabbableObject)this).DiscardItem(); } public override void GrabItemFromEnemy(EnemyAI enemy) { ((GrabbableObject)this).GrabItemFromEnemy(enemy); HeldByEnemy = enemy; } public override void DiscardItemFromEnemy() { ((GrabbableObject)this).DiscardItemFromEnemy(); HeldByEnemy = null; } public override void SetControlTipsForItem() { string[] array = (((Object)(object)base.itemProperties != (Object)null) ? base.itemProperties.toolTips : null); if (array == null || array.Length == 0) { ((GrabbableObject)this).SetControlTipsForItem(); return; } WeaponReloadInput.ApplyReloadTooltips(array); int num = array.Length - 1; array[num] = (SafetyOn ? "Turn safety off : [Q]" : "Turn safety on : [Q]"); HUDManager instance = HUDManager.Instance; if (instance != null) { instance.ChangeControlTipMultiple(array, true, base.itemProperties); } } public override void ItemActivate(bool used, bool buttonDown = true) { ((GrabbableObject)this).ItemActivate(used, buttonDown); if (((NetworkBehaviour)this).IsOwner && Config != null && Config.FireMode == WeaponFireMode.FullAutoHitscan) { _triggerHeld = buttonDown; } if (!buttonDown || !((NetworkBehaviour)this).IsOwner || IsReloading) { if (WeaponVfxDiagnostics.Once("activate.gated")) { WeaponVfxDiagnostics.Emit($"ItemActivate returned early: buttonDown={buttonDown} isOwner={((NetworkBehaviour)this).IsOwner} " + $"isReloading={IsReloading}."); } return; } WeaponConfig config = Config; if (config == null) { if (WeaponVfxDiagnostics.Once("activate.noconfig")) { WeaponVfxDiagnostics.Emit("ItemActivate returned early: no config for '" + ConfigId + "'."); } } else if (Magazine <= 0) { if (WeaponVfxDiagnostics.Once("activate.empty")) { WeaponVfxDiagnostics.Emit("ItemActivate branch=RELOAD (magazine empty, reserve=" + $"{AmmoReserve.Get(config.AmmoType)} {config.AmmoType})."); } BeginReload(); } else if (SafetyOn) { if (WeaponVfxDiagnostics.Once("activate.safety")) { WeaponVfxDiagnostics.Emit("ItemActivate branch=SAFETY ON (dry fire; press Q to disengage)."); } PlayLocalClip(DryFireClip, 1f); } else if (!(Time.time < _nextFireTime)) { _nextFireTime = Time.time + config.ResolveFireInterval(); FireOnce(config); } } public override void Update() { ((GrabbableObject)this).Update(); if (!_triggerHeld) { return; } if (!((NetworkBehaviour)this).IsOwner || (Object)(object)base.playerHeldBy == (Object)null || base.isPocketed) { _triggerHeld = false; return; } WeaponConfig config = Config; if (config != null && !IsReloading && !SafetyOn && Magazine > 0 && !(Time.time < _nextFireTime)) { _nextFireTime = Time.time + config.ResolveFireInterval(); FireOnce(config); } } private void FireOnce(WeaponConfig config) { //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) if (!TryGetShotRay(out var origin, out var forward)) { if (WeaponVfxDiagnostics.Once("fire.noray")) { WeaponVfxDiagnostics.Emit("FireOnce aborted: TryGetShotRay failed (no holder camera and no holding enemy)."); } return; } float num = WeaponAccuracy.Sample(base.playerHeldBy, config); if (WeaponVfxDiagnostics.Once("fire.once")) { bool flag = (Object)(object)base.playerHeldBy != (Object)null && (Object)(object)base.playerHeldBy.gameplayCamera != (Object)null; WeaponRecoilDriver activeDriver = WeaponRecoil.ActiveDriver; WeaponVfxDiagnostics.Emit("FireOnce branch=FIRED origin=" + ((Vector3)(ref origin)).ToString("F3") + " forward=" + ((Vector3)(ref forward)).ToString("F3") + " rayAuthority=" + (flag ? "camera" : "enemy-bore") + " " + $"magazine={Magazine}/{config.MagazineSize} flashPrefab='{MuzzleFlashPrefabName}' " + $"spread={num:F3}deg (base={WeaponAccuracy.BaseHalfAngleDegrees(config):F3} " + $"shot={WeaponAccuracy.ShotBloomDegrees:F3} move={WeaponAccuracy.MoveBloomDegrees:F3} " + $"steadiness={WeaponAccuracy.AimSteadiness:F2} " + $"kick={(((Object)(object)activeDriver != (Object)null) ? activeDriver.PendingKickDegrees : 0f):F3} " + $"climb={(((Object)(object)activeDriver != (Object)null) ? activeDriver.AccumulatedClimbDegrees : 0f):F3})."); } Magazine--; if ((Object)(object)base.playerHeldBy != (Object)null && (Object)(object)base.playerHeldBy == (Object)(object)GameNetworkManager.Instance?.localPlayerController) { CrosshairSignals.RecordCommittedLocalShot(); } uint num2 = _nextShotId++; if (_nextShotId == 0) { _nextShotId = 1u; } _lastAppliedShotId = num2; ApplyShot(num2, origin, forward, num, base.playerHeldBy); Y4NGZWeaponNet.PublishShot(((NetworkBehaviour)this).NetworkObjectId, num2, origin, forward, num); PublishState(); WeaponAccuracy.OnShotFired(config); } private bool TryGetShotRay(out Vector3 origin, out Vector3 forward) { //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) //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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) origin = Vector3.zero; forward = Vector3.forward; PlayerControllerB playerHeldBy = base.playerHeldBy; Camera val = (((Object)(object)playerHeldBy != (Object)null) ? playerHeldBy.gameplayCamera : null); if ((Object)(object)val != (Object)null) { Transform transform = ((Component)val).transform; origin = transform.position; forward = transform.forward; return true; } if ((Object)(object)HeldByEnemy != (Object)null) { origin = ((Component)this).transform.position; forward = ((Component)this).transform.forward; return true; } return false; } private void ApplyShot(uint shotId, Vector3 origin, Vector3 forward, float spreadDegrees, PlayerControllerB firedBy) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) WeaponConfig config = Config; if (config != null) { IsReloading = false; WeaponThirdPersonAnimation.OnNativeWeaponFired(this, base.playerHeldBy); if (base.isHeld && (Object)(object)base.playerHeldBy != (Object)null) { SetBodyTrigger("ShootShotgun"); } WeaponFirstPersonAnimation.OnWeaponFired(this, base.playerHeldBy, Magazine <= 0); _propAnimation?.PlayFire(Magazine <= 0); PlayShotAudio(config); PlayFireMechanicalAudio(); WeaponMuzzleFlash.Play(((Component)this).gameObject, Landmarks, MuzzleFlashPrefabName, forward, ((Plugin.WeaponsMuzzleFlashScale != null) ? Plugin.WeaponsMuzzleFlashScale.Value : 1f) * Mathf.Max(0.01f, MuzzleFlashScale), this, base.playerHeldBy); uint seed = Y4NGZWeaponNet.DeriveSeed(((NetworkBehaviour)this).NetworkObjectId, shotId); WeaponImpactEffects.PlayShotImpacts(Y4NGZWeaponBallistics.ResolveShot(this, config, origin, forward, seed, spreadDegrees, firedBy), (Plugin.WeaponsImpactScale != null) ? Plugin.WeaponsImpactScale.Value : 1f, config.AmmoType); if (((NetworkBehaviour)this).IsOwner && (Object)(object)firedBy != (Object)null) { WeaponRecoil.ApplyKick(firedBy, config); } } } private void PlayShotAudio(WeaponConfig config) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_audio == (Object)null) { _audio = ((Component)this).GetComponent(); } bool authored; AudioClip val = PickFireClip(out authored); if ((Object)(object)_audio != (Object)null && (Object)(object)val != (Object)null) { _audio.pitch = Random.Range(0.94f, 1.06f); _audio.PlayOneShot(val, ClipVolume(authored)); WalkieTalkie.TransmitOneShotAudio(_audio, val, 0.85f); } RoundManager instance = RoundManager.Instance; if (instance != null) { instance.PlayAudibleNoise(((Component)this).transform.position, config.ShotNoiseRange, config.ShotNoiseLoudness, 0, base.isInElevator && (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.hangarDoorsClosed, 1840); } } private void PlayFireMechanicalAudio() { if (FireMechanicalClips == null || FireMechanicalClips.Length == 0) { return; } for (int i = 0; i < FireMechanicalClips.Length; i++) { AudioClip val = FireMechanicalClips[i]; if (!((Object)(object)val == (Object)null)) { float num = ((FireMechanicalClipDelaySeconds != null && i < FireMechanicalClipDelaySeconds.Length) ? Mathf.Max(0f, FireMechanicalClipDelaySeconds[i]) : 0f); if (num <= 0f) { PlayLocalClip(val, ClipVolume(authored: true)); } else { ((MonoBehaviour)this).StartCoroutine(PlayFireMechanicalClipAfterDelay(val, num)); } } } } private IEnumerator PlayFireMechanicalClipAfterDelay(AudioClip clip, float delaySeconds) { yield return (object)new WaitForSeconds(delaySeconds); PlayLocalClip(clip, ClipVolume(authored: true)); } internal void OnRemoteShot(uint shotId, Vector3 origin, Vector3 forward, float spreadDegrees) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)this).IsOwner || shotId != _lastAppliedShotId) { Magazine = Mathf.Max(0, Magazine - 1); ApplyShot(shotId, origin, forward, spreadDegrees, base.playerHeldBy); } } public override void ItemInteractLeftRight(bool right) { ((GrabbableObject)this).ItemInteractLeftRight(right); if ((Object)(object)base.playerHeldBy == (Object)null) { return; } if (!right) { ToggleSafety(); } else if (!((NetworkBehaviour)this).IsOwner || WeaponReloadInput.AcceptRightInteractReload) { int num = Config?.MagazineSize ?? 1; if (!IsReloading && Magazine < num) { BeginReload(); } } } private void ToggleSafety() { SafetyOn = !SafetyOn; SetBodyTrigger("SwitchGunSafety"); PlayLocalClip(SafetyOn ? SafetyOnClip : SafetyOffClip, 1f); if (((NetworkBehaviour)this).IsOwner) { HUDManager instance = HUDManager.Instance; int num = (((Object)(object)base.itemProperties != (Object)null && base.itemProperties.toolTips != null) ? base.itemProperties.toolTips.Length : 3); if ((Object)(object)instance != (Object)null && instance.controlTipLines != null && num < instance.controlTipLines.Length) { instance.ChangeControlTip(num, SafetyOn ? "Turn safety off : [Q]" : "Turn safety on : [Q]", false); } PublishState(); } } private void BeginReload() { if (!((NetworkBehaviour)this).IsOwner || IsReloading) { return; } WeaponConfig config = Config; if (config == null) { return; } int num = config.MagazineSize - Magazine; if (num <= 0) { return; } int num2 = ((!config.ReloadFillsMagazine) ? 1 : num); int num3 = AmmoReserve.Get(config.AmmoType); int num4 = Mathf.Min(num2, num3); if (num4 <= 0) { PlayLocalClip(DryFireClip, 1f); return; } int num5 = Magazine + num4; StopReload(); IsReloading = true; Y4NGZWeaponNet.PublishReload(((NetworkBehaviour)this).NetworkObjectId, starting: true, num5); _reloadRoutine = ((MonoBehaviour)this).StartCoroutine(ReloadRoutine(config, Magazine <= 0, num4)); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Y4NGZNative] {config.DisplayName} reload staged {num4} {config.AmmoType} " + $"(reserve currently {num3}); magazine target " + $"{num5}/{config.MagazineSize}.")); } } private IEnumerator ReloadRoutine(WeaponConfig config, bool wasEmpty, int roundsDrawn) { WeaponThirdPersonAnimation.OnNativeReloadStarted(this, base.playerHeldBy, wasEmpty, roundsDrawn); SetBodyBool("ReloadShotgun", value: true); WeaponFirstPersonAnimation.OnWeaponReloadStarted(this, base.playerHeldBy, wasEmpty, roundsDrawn); _propAnimation?.PlayReload(wasEmpty, roundsDrawn); if (config.HasStagedReload && HasStagedReloadAudio) { _reloadAudioRoutine = ((MonoBehaviour)this).StartCoroutine(PlayStagedReloadAudio(config, wasEmpty, roundsDrawn)); } else { bool authored; AudioClip clip = PickReloadClip(wasEmpty, out authored); PlayLocalClip(clip, ClipVolume(authored)); } if (config.HasStagedReload) { yield return (object)new WaitForSeconds(Mathf.Max(0f, config.ReloadStartSeconds)); if (wasEmpty && config.HasStagedEmptyReload) { float num = Mathf.Max(0f, config.ReloadEmptySeconds - config.ReloadStartSeconds - config.ReloadEndSeconds); yield return (object)new WaitForSeconds(num); CommitReloadRounds(config, roundsDrawn); } else { float perRound = Mathf.Max(0f, config.ReloadPerRoundSeconds); for (int i = 0; i < roundsDrawn; i++) { yield return (object)new WaitForSeconds(perRound); if (CommitReloadRounds(config, 1) <= 0) { break; } } } yield return (object)new WaitForSeconds(Mathf.Max(0f, config.ReloadEndSeconds)); } else { yield return (object)new WaitForSeconds(Mathf.Max(0.1f, config.ResolveReloadDuration(wasEmpty, roundsDrawn))); CommitReloadRounds(config, roundsDrawn); } IsReloading = false; _reloadRoutine = null; SetBodyBool("ReloadShotgun", value: false); if (!HasAuthoredReloadAudio) { PlayLocalClip(ReloadFinishClip, 1f); } _propAnimation?.PlayRest(); Y4NGZWeaponNet.PublishReload(((NetworkBehaviour)this).NetworkObjectId, starting: false, Magazine); PublishState(); AmmoCounterHud.RequestImmediateRefresh(); } private int CommitReloadRounds(WeaponConfig config, int requested) { if (config == null || requested <= 0) { return 0; } int num = Mathf.Min(requested, Mathf.Max(0, config.MagazineSize - Magazine)); if (num <= 0) { return 0; } if (!AmmoReserve.TryConsume(config.AmmoType, num)) { num = Mathf.Min(num, AmmoReserve.Get(config.AmmoType)); if (num <= 0 || !AmmoReserve.TryConsume(config.AmmoType, num)) { return 0; } } Magazine += num; PublishState(); AmmoCounterHud.RequestImmediateRefresh(); return num; } private void StopReload() { if (_reloadRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_reloadRoutine); _reloadRoutine = null; } if (_reloadAudioRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_reloadAudioRoutine); _reloadAudioRoutine = null; } bool isReloading = IsReloading; if (isReloading) { IsReloading = false; PlayerControllerB holder = base.playerHeldBy ?? _previousPlayerHeldBy; SetBodyBool("ReloadShotgun", value: false, holder); _propAnimation?.PlayRest(); } if (isReloading && ((NetworkBehaviour)this).IsOwner) { Y4NGZWeaponNet.PublishReload(((NetworkBehaviour)this).NetworkObjectId, starting: false, Magazine); PublishState(); AmmoCounterHud.RequestImmediateRefresh(); } } internal void OnRemoteReload(bool starting, int magazineAfter) { if (((NetworkBehaviour)this).IsOwner) { return; } IsReloading = starting; if (starting) { SetBodyBool("ReloadShotgun", value: true); WeaponConfig config = Config; int roundsDrawn = Mathf.Max(1, magazineAfter - Magazine); bool wasEmpty = Magazine <= 0; WeaponThirdPersonAnimation.OnNativeReloadStarted(this, base.playerHeldBy, wasEmpty, roundsDrawn); _propAnimation?.PlayReload(wasEmpty, roundsDrawn); if (config != null && config.HasStagedReload && HasStagedReloadAudio) { _reloadAudioRoutine = ((MonoBehaviour)this).StartCoroutine(PlayStagedReloadAudio(config, wasEmpty, roundsDrawn)); return; } bool authored; AudioClip clip = PickReloadClip(wasEmpty, out authored); PlayLocalClip(clip, ClipVolume(authored)); } else { Magazine = magazineAfter; SetBodyBool("ReloadShotgun", value: false); if (!HasAuthoredReloadAudio) { PlayLocalClip(ReloadFinishClip, 1f); } _propAnimation?.PlayRest(); } } private void SetBodyTrigger(string parameter, PlayerControllerB holder = null) { PlayerControllerB val = holder ?? base.playerHeldBy; if (!((Object)(object)val == (Object)null) && !IsBodyOwnedByAnimationApi(val)) { Animator playerBodyAnimator = val.playerBodyAnimator; if (playerBodyAnimator != null) { playerBodyAnimator.SetTrigger(parameter); } } } private void SetBodyBool(string parameter, bool value, PlayerControllerB holder = null) { PlayerControllerB val = holder ?? base.playerHeldBy; if (!((Object)(object)val == (Object)null) && (!value || !IsBodyOwnedByAnimationApi(val))) { Animator playerBodyAnimator = val.playerBodyAnimator; if (playerBodyAnimator != null) { playerBodyAnimator.SetBool(parameter, value); } } } private static bool IsBodyOwnedByAnimationApi(PlayerControllerB player) { if (Plugin.WeaponsNativeSuppressVanillaBodyTriggers != null && !Plugin.WeaponsNativeSuppressVanillaBodyTriggers.Value) { return false; } return WeaponFirstPersonAnimation.ApiOwnsPlayerBody(player); } internal void InitializeExternally(int magazine, bool safetyOn) { _externallyInitialized = true; WeaponConfig config = Config; Magazine = ((config != null) ? Mathf.Clamp(magazine, 0, Mathf.Max(0, config.MagazineSize)) : Mathf.Max(0, magazine)); SafetyOn = safetyOn; if (((NetworkBehaviour)this).IsSpawned && ((NetworkBehaviour)this).IsServer) { PublishState(authoritative: true); } } private void PublishState(bool authoritative = false) { if (((NetworkBehaviour)this).IsSpawned) { Y4NGZWeaponNet.PublishState(((NetworkBehaviour)this).NetworkObjectId, Magazine, SafetyOn, IsReloading, authoritative); } } internal void PublishAuthoritativeStateFromServer() { if (((NetworkBehaviour)this).IsServer) { PublishState(authoritative: true); } } internal void OnRemoteState(int magazine, bool safetyOn, bool reloading, bool authoritative) { if (!((NetworkBehaviour)this).IsOwner || authoritative) { Magazine = magazine; SafetyOn = safetyOn; if (!((NetworkBehaviour)this).IsOwner || !authoritative) { IsReloading = reloading; } if (authoritative) { AmmoCounterHud.RequestImmediateRefresh(); } } } public override int GetItemDataToSave() { return Magazine; } public override void LoadItemSaveData(int saveData) { ((GrabbableObject)this).LoadItemSaveData(saveData); _loadedFromSave = true; int num = Config?.MagazineSize ?? saveData; Magazine = Mathf.Clamp(saveData, 0, Mathf.Max(0, num)); SafetyOn = true; } private void PlayLocalClip(AudioClip clip, float volume) { if (!((Object)(object)clip == (Object)null)) { if ((Object)(object)_audio == (Object)null) { _audio = ((Component)this).GetComponent(); } AudioSource audio = _audio; if (audio != null) { audio.PlayOneShot(clip, volume); } } } private AudioClip PickFireClip(out bool authored) { authored = false; if (FireClips == null || FireClips.Length == 0) { return FireClip; } for (int i = 0; i < FireClips.Length; i++) { AudioClip val = FireClips[_fireClipCursor % FireClips.Length]; _fireClipCursor = (_fireClipCursor + 1) % FireClips.Length; if ((Object)(object)val != (Object)null) { authored = ApplyAuthoredGainToFireClips; return val; } } return FireClip; } private static float ClipVolume(bool authored) { if (!authored) { return 1f; } ConfigEntry weaponsAuthoredAudioGain = Plugin.WeaponsAuthoredAudioGain; if (weaponsAuthoredAudioGain == null) { return 1f; } return Mathf.Max(0f, weaponsAuthoredAudioGain.Value); } private IEnumerator PlayStagedReloadAudio(WeaponConfig config, bool wasEmpty, int roundsDrawn) { PlayLocalClip(ReloadStageStartClip, ClipVolume((Object)(object)ReloadStageStartClip != (Object)null)); yield return (object)new WaitForSeconds(Mathf.Max(0f, config.ReloadStartSeconds)); bool flag = wasEmpty && config.HasStagedEmptyReload; int inserts = (flag ? 1 : Mathf.Max(1, roundsDrawn)); float middleDuration = (flag ? Mathf.Max(0f, config.ReloadEmptySeconds - config.ReloadStartSeconds - config.ReloadEndSeconds) : Mathf.Max(0f, config.ReloadPerRoundSeconds)); for (int i = 0; i < inserts; i++) { PlayLocalClip(ReloadStageLoopClip, ClipVolume((Object)(object)ReloadStageLoopClip != (Object)null)); yield return (object)new WaitForSeconds(middleDuration); } PlayLocalClip(ReloadStageEndClip, ClipVolume((Object)(object)ReloadStageEndClip != (Object)null)); yield return (object)new WaitForSeconds(Mathf.Max(0f, config.ReloadEndSeconds)); _reloadAudioRoutine = null; } private AudioClip PickReloadClip(bool wasEmpty, out bool authored) { AudioClip val = (wasEmpty ? ReloadEmptyClip : ReloadTacClip); authored = (Object)(object)val != (Object)null; if (!authored) { return ReloadStartClip; } return val; } } internal sealed class Y4NGZWeaponItem : MonoBehaviour, IY4NGZFpWeapon { public string ConfigId = "heavy_shotgun"; private WeaponConfig _config; private ShotgunItem _shotgun; internal int PendingShellsAfterReload = -1; internal WeaponConfig Config => _config ?? (_config = WeaponCatalog.ById(ConfigId)); internal ShotgunItem Shotgun { get { if (!((Object)(object)_shotgun != (Object)null)) { return _shotgun = ((Component)this).GetComponent(); } return _shotgun; } } string IY4NGZFpWeapon.FpConfigId => ConfigId; GrabbableObject IY4NGZFpWeapon.FpGrabbable => (GrabbableObject)(object)Shotgun; ShotgunItem IY4NGZFpWeapon.FpLegacyShotgun => Shotgun; private void Awake() { _config = WeaponCatalog.ById(ConfigId); _shotgun = ((Component)this).GetComponent(); if ((Object)(object)_shotgun != (Object)null && _config != null) { _shotgun.shellsLoaded = Mathf.Max(_shotgun.shellsLoaded, _config.MagazineSize); } } internal void ApplyAuthoritativeMagazine(int magazine, bool safetyOn) { ShotgunItem shotgun = Shotgun; WeaponConfig config = Config; if (!((Object)(object)shotgun == (Object)null) && !shotgun.isReloading && (config == null || config.FireMode != WeaponFireMode.ContinuousStream)) { int num = config?.MagazineSize ?? magazine; shotgun.shellsLoaded = Mathf.Clamp(magazine, 0, Mathf.Max(0, num)); shotgun.safetyOn = safetyOn; } } internal void OnFired(PlayerControllerB firedBy) { WeaponConfig config = Config; if (config != null && config.FireMode != WeaponFireMode.ContinuousStream) { WeaponRecoil.ApplyKick(firedBy, config); WeaponFirstPersonAnimation.OnWeaponFired(this, firedBy); } } } internal static class Y4NGZWeaponNet { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnShotMessage; public static HandleNamedMessageDelegate <1>__OnStateMessage; public static HandleNamedMessageDelegate <2>__OnReloadMessage; } private const string ShotMessage = "Y4NGZ_Weapon_Shot_v2"; private const string StateMessage = "Y4NGZ_Weapon_State_v2"; private const string ReloadMessage = "Y4NGZ_Weapon_Reload_v1"; private const int ShotPayloadBytes = 40; private const int StatePayloadBytes = 15; private const int ReloadPayloadBytes = 13; private static bool _handlersRegistered; internal static void RegisterHandlers() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //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_0066: Expected O, but got Unknown //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_008c: Expected O, but got Unknown if (_handlersRegistered) { return; } NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val == null) { return; } try { object obj = <>O.<0>__OnShotMessage; if (obj == null) { HandleNamedMessageDelegate val2 = OnShotMessage; <>O.<0>__OnShotMessage = val2; obj = (object)val2; } val.RegisterNamedMessageHandler("Y4NGZ_Weapon_Shot_v2", (HandleNamedMessageDelegate)obj); object obj2 = <>O.<1>__OnStateMessage; if (obj2 == null) { HandleNamedMessageDelegate val3 = OnStateMessage; <>O.<1>__OnStateMessage = val3; obj2 = (object)val3; } val.RegisterNamedMessageHandler("Y4NGZ_Weapon_State_v2", (HandleNamedMessageDelegate)obj2); object obj3 = <>O.<2>__OnReloadMessage; if (obj3 == null) { HandleNamedMessageDelegate val4 = OnReloadMessage; <>O.<2>__OnReloadMessage = val4; obj3 = (object)val4; } val.RegisterNamedMessageHandler("Y4NGZ_Weapon_Reload_v1", (HandleNamedMessageDelegate)obj3); _handlersRegistered = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[Y4NGZNative] Weapon named-message handlers registered."); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZNative] Weapon message handler registration failed: " + ex.Message)); } } } internal static void Reset() { _handlersRegistered = false; } internal static void PublishShot(ulong weaponNetworkObjectId, uint shotId, Vector3 origin, Vector3 forward, float spreadDegrees) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val == null) { return; } FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(40, (Allocator)2, -1); try { ((FastBufferWriter)(ref writer)).WriteValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref shotId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref origin.x, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref origin.y, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref origin.z, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref forward.x, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref forward.y, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref forward.z, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref spreadDegrees, default(ForPrimitives)); Send(val, singleton, "Y4NGZ_Weapon_Shot_v2", writer); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Shot publish failed: " + ex.Message)); } } finally { ((FastBufferWriter)(ref writer)).Dispose(); } } private static void OnShotMessage(ulong senderClientId, FastBufferReader reader) { //IL_0010: 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_0027: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) try { ulong weaponNetworkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); uint shotId = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref shotId, default(ForPrimitives)); float ox = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref ox, default(ForPrimitives)); float oy = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref oy, default(ForPrimitives)); float oz = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref oz, default(ForPrimitives)); float fx = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref fx, default(ForPrimitives)); float fy = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref fy, default(ForPrimitives)); float fz = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref fz, default(ForPrimitives)); float spreadDegrees = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref spreadDegrees, default(ForPrimitives)); Vector3 origin = default(Vector3); ((Vector3)(ref origin))..ctor(ox, oy, oz); Vector3 forward = default(Vector3); ((Vector3)(ref forward))..ctor(fx, fy, fz); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsServer && senderClientId != singleton.LocalClientId) { Relay(singleton, "Y4NGZ_Weapon_Shot_v2", 40, delegate(FastBufferWriter writer) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0026: 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) //IL_003c: 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_0052: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00c0: Unknown result type (might be due to invalid IL or missing references) ((FastBufferWriter)(ref writer)).WriteValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref shotId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref ox, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref oy, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref oz, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref fx, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref fy, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref fz, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref spreadDegrees, default(ForPrimitives)); }, senderClientId); } Y4NGZWeaponBase y4NGZWeaponBase = Resolve(weaponNetworkObjectId); if ((Object)(object)y4NGZWeaponBase != (Object)null) { y4NGZWeaponBase.OnRemoteShot(shotId, origin, forward, spreadDegrees); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZNative] Malformed shot message from {senderClientId}: {ex.Message}"); } } } internal static void PublishState(ulong weaponNetworkObjectId, int magazine, bool safetyOn, bool reloading, bool authoritative = false) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0068: 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_0081: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val == null) { return; } if (authoritative && !singleton.IsServer) { authoritative = false; } FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(15, (Allocator)2, -1); try { ((FastBufferWriter)(ref writer)).WriteValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref magazine, default(ForPrimitives)); byte b = (safetyOn ? ((byte)1) : ((byte)0)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref b, default(ForPrimitives)); b = (reloading ? ((byte)1) : ((byte)0)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref b, default(ForPrimitives)); b = (authoritative ? ((byte)1) : ((byte)0)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref b, default(ForPrimitives)); Send(val, singleton, "Y4NGZ_Weapon_State_v2", writer); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] State publish failed: " + ex.Message)); } } finally { ((FastBufferWriter)(ref writer)).Dispose(); } } private static void OnStateMessage(ulong senderClientId, FastBufferReader reader) { //IL_0010: 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_0027: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) try { ulong weaponNetworkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); int magazine = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref magazine, default(ForPrimitives)); byte safety = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe(ref safety, default(ForPrimitives)); byte reloading = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe(ref reloading, default(ForPrimitives)); byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe(ref b, default(ForPrimitives)); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsServer && senderClientId != singleton.LocalClientId) { b = 0; Relay(singleton, "Y4NGZ_Weapon_State_v2", 15, delegate(FastBufferWriter writer) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0026: 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) //IL_003c: 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_0052: 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_0066: Unknown result type (might be due to invalid IL or missing references) ((FastBufferWriter)(ref writer)).WriteValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref magazine, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref safety, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref reloading, default(ForPrimitives)); byte b2 = 0; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref b2, default(ForPrimitives)); }, senderClientId); } bool flag = (Object)(object)singleton != (Object)null && singleton.IsServer && senderClientId == singleton.LocalClientId; Y4NGZWeaponBase y4NGZWeaponBase = Resolve(weaponNetworkObjectId); if ((Object)(object)y4NGZWeaponBase != (Object)null) { if (!flag) { y4NGZWeaponBase.OnRemoteState(magazine, safety != 0, reloading != 0, b != 0); } } else if (!flag && b != 0) { ResolveLegacy(weaponNetworkObjectId)?.ApplyAuthoritativeMagazine(magazine, safety != 0); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZNative] Malformed state message from {senderClientId}: {ex.Message}"); } } } internal static void PublishReload(ulong weaponNetworkObjectId, bool starting, int magazineAfter) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0047: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val == null) { return; } FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(13, (Allocator)2, -1); try { ((FastBufferWriter)(ref writer)).WriteValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); byte b = (starting ? ((byte)1) : ((byte)0)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref b, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref magazineAfter, default(ForPrimitives)); Send(val, singleton, "Y4NGZ_Weapon_Reload_v1", writer); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZNative] Reload publish failed: " + ex.Message)); } } finally { ((FastBufferWriter)(ref writer)).Dispose(); } } private static void OnReloadMessage(ulong senderClientId, FastBufferReader reader) { //IL_0010: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0042: Unknown result type (might be due to invalid IL or missing references) try { ulong weaponNetworkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); byte starting = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe(ref starting, default(ForPrimitives)); int magazineAfter = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref magazineAfter, default(ForPrimitives)); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsServer && senderClientId != singleton.LocalClientId) { Relay(singleton, "Y4NGZ_Weapon_Reload_v1", 13, delegate(FastBufferWriter writer) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0026: 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) //IL_003c: Unknown result type (might be due to invalid IL or missing references) ((FastBufferWriter)(ref writer)).WriteValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref starting, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref magazineAfter, default(ForPrimitives)); }, senderClientId); } Y4NGZWeaponBase y4NGZWeaponBase = Resolve(weaponNetworkObjectId); if ((Object)(object)y4NGZWeaponBase != (Object)null) { y4NGZWeaponBase.OnRemoteReload(starting != 0, magazineAfter); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZNative] Malformed reload message from {senderClientId}: {ex.Message}"); } } } private static void Send(CustomMessagingManager messaging, NetworkManager manager, string message, FastBufferWriter writer) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (manager.IsServer) { messaging.SendNamedMessageToAll(message, writer, (NetworkDelivery)3); } else { messaging.SendNamedMessage(message, 0uL, writer, (NetworkDelivery)3); } } private static void Relay(NetworkManager manager, string message, int payloadBytes, Action write, ulong excludeClientId) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) CustomMessagingManager customMessagingManager = manager.CustomMessagingManager; if (customMessagingManager == null) { return; } FastBufferWriter val = default(FastBufferWriter); foreach (ulong connectedClientsId in manager.ConnectedClientsIds) { if (connectedClientsId == excludeClientId || connectedClientsId == manager.LocalClientId) { continue; } ((FastBufferWriter)(ref val))..ctor(payloadBytes, (Allocator)2, -1); try { write(val); customMessagingManager.SendNamedMessage(message, connectedClientsId, val, (NetworkDelivery)3); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZNative] Relay to {connectedClientsId} failed: {ex.Message}"); } } finally { ((FastBufferWriter)(ref val)).Dispose(); } } } private static Y4NGZWeaponBase Resolve(ulong weaponNetworkObjectId) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.SpawnManager == null) { return null; } if (!singleton.SpawnManager.SpawnedObjects.TryGetValue(weaponNetworkObjectId, out var value)) { return null; } if (!((Object)(object)value != (Object)null)) { return null; } return ((Component)value).GetComponent(); } private static Y4NGZWeaponItem ResolveLegacy(ulong weaponNetworkObjectId) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.SpawnManager == null) { return null; } if (!singleton.SpawnManager.SpawnedObjects.TryGetValue(weaponNetworkObjectId, out var value)) { return null; } if (!((Object)(object)value != (Object)null)) { return null; } return ((Component)value).GetComponent(); } internal static uint DeriveSeed(ulong weaponNetworkObjectId, uint shotId) { uint num = 2166136261u; num = (num ^ (uint)(int)weaponNetworkObjectId) * 16777619; num = (num ^ (uint)(int)(weaponNetworkObjectId >> 32)) * 16777619; num = (num ^ shotId) * 16777619; if (num != 0) { return num; } return 1u; } } } namespace Y4NGZUpgrades.Weapons.Patches { [HarmonyPatch] internal static class AmmoPickupPatches { [HarmonyPatch(typeof(GrabbableObject), "GrabItemOnClient")] [HarmonyPostfix] private static void GrabItemOnClient_Postfix(GrabbableObject __instance) { try { if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner) { return; } AmmoPickupItem component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && !component.ConsumptionStarted) { PlayerControllerB val = __instance.playerHeldBy ?? StartOfRound.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsOwner) { component.ConsumptionStarted = true; ((MonoBehaviour)val).StartCoroutine(ConsumeAfterGrab(val, __instance, component)); } } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[Y4NGZAmmo] Consume-on-grab hook failed; pickup remains ordinary scrap: {arg}"); } } } private static IEnumerator ConsumeAfterGrab(PlayerControllerB player, GrabbableObject grabbable, AmmoPickupItem pickup) { yield return null; bool flag = false; try { if ((Object)(object)player == (Object)null || (Object)(object)grabbable == (Object)null || (Object)(object)pickup == (Object)null || !((NetworkBehaviour)player).IsOwner) { if ((Object)(object)pickup != (Object)null) { pickup.ConsumptionStarted = false; } yield break; } int num = FindHeldSlot(player, grabbable); if (num < 0) { pickup.ConsumptionStarted = false; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Y4NGZAmmo] Grab completed without a normal hotbar slot; pickup remains ordinary scrap."); } yield break; } AmmoPickupConfig config = pickup.Config; int num2 = config?.RoundsGranted ?? 0; if (config == null || num2 <= 0) { pickup.ConsumptionStarted = false; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[Y4NGZAmmo] Pickup has no positive rounds grant; it remains ordinary scrap."); } yield break; } num2 = Mathf.Max(num2, Mathf.RoundToInt((float)num2 * UpgradesBridge.GetAmmoMultiplier())); if (!AmmoReserve.TryAdd(config.AmmoType, num2, out var added)) { pickup.ConsumptionStarted = false; if (config.AmmoType == WeaponAmmoType.Grenades) { int num3 = AmmoReserve.MaximumFor(WeaponAmmoType.Grenades); HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip("GRENADE INVENTORY", $"Full ({num3}/{num3}).", true, false, "LC_Tip1"); } player.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true); } } else { flag = true; player.DestroyItemInSlotAndSync(num); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[Y4NGZAmmo] Collected {config.DisplayName}: +{added} {config.AmmoType}."); } } } catch (Exception arg) { if (!flag && (Object)(object)pickup != (Object)null) { pickup.ConsumptionStarted = false; } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)$"[Y4NGZAmmo] Pickup consumption failed safely; item remains scrap where possible: {arg}"); } } } private static int FindHeldSlot(PlayerControllerB player, GrabbableObject grabbable) { try { if (player?.ItemSlots == null || (Object)(object)grabbable == (Object)null) { return -1; } for (int i = 0; i < player.ItemSlots.Length; i++) { if ((Object)(object)player.ItemSlots[i] == (Object)(object)grabbable) { return i; } } if ((Object)(object)player.ItemOnlySlot == (Object)(object)grabbable) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Y4NGZAmmo] Ammo pickup entered utility slot 50 unexpectedly; not consuming it."); } } return -1; } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZAmmo] Held-slot lookup failed: " + ex.Message)); } return -1; } } } [HarmonyPatch] internal static class AmmoReloadPatches { [HarmonyPatch(typeof(ShotgunItem), "ReloadedGun")] [HarmonyPrefix] private static bool ReloadedGun_Prefix(ShotgunItem __instance, ref bool __result) { try { Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if (component.Config != null && component.Config.FireMode == WeaponFireMode.ContinuousStream) { __result = ((Component)__instance).GetComponent()?.TryBeginReload() ?? false; return false; } if (!((NetworkBehaviour)__instance).IsOwner) { __result = false; return false; } WeaponConfig config = component.Config; WeaponAmmoType weaponAmmoType = config?.AmmoType ?? WeaponAmmoType.ShotgunShells; int num = config?.MagazineSize ?? 2; int num2 = num - __instance.shellsLoaded; if (num2 <= 0) { __result = false; return false; } int num3 = ((config == null || !config.ReloadFillsMagazine) ? 1 : num2); int i; for (i = 0; i < num3; i++) { if (!AmmoReserve.TryConsume(weaponAmmoType, 1)) { break; } } if (i > 0) { Traverse.Create((object)__instance).Field("ammoSlotToUse").SetValue((object)(-1)); component.PendingShellsAfterReload = __instance.shellsLoaded + i; __result = true; WeaponFirstPersonAnimation.OnWeaponReloadStarted(component, ((GrabbableObject)__instance).playerHeldBy); GrenadeLauncherPatches.OnReloadStarted(__instance); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZWeapons] Reload drew {i} {weaponAmmoType} from reserve (now {AmmoReserve.Get(weaponAmmoType)}); magazine will hold {component.PendingShellsAfterReload}/{num}."); } } else { __result = false; } return false; } catch (Exception arg) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)$"[Y4NGZWeapons] ReloadedGun prefix threw: {arg}"); } return true; } } [HarmonyPatch(typeof(ShotgunItem), "ReloadedGun")] [HarmonyPostfix] private static void ReloadedGun_Postfix(ShotgunItem __instance, ref bool __result) { try { if (!ArmoryContentConfig.VanillaShotgunSharesShellReserve || (((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).GetComponent() != (Object)null) | __result) || !((NetworkBehaviour)__instance).IsOwner || __instance.shellsLoaded >= 2 || AmmoReserve.Get(WeaponAmmoType.ShotgunShells) <= 0) { return; } Traverse.Create((object)__instance).Field("ammoSlotToUse").SetValue((object)(-1)); if (AmmoReserve.TryConsume(WeaponAmmoType.ShotgunShells, 1)) { __result = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZWeapons] Vanilla shotgun reload drew 1 ShotgunShells reserve round " + $"(remaining {AmmoReserve.Get(WeaponAmmoType.ShotgunShells)}).")); } } } catch (Exception arg) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)$"[Y4NGZWeapons] Vanilla shotgun reserve fallback failed safely: {arg}"); } } } [HarmonyPatch(typeof(ShotgunItem), "ItemInteractLeftRight")] [HarmonyPrefix] private static bool ItemInteractLeftRight_Prefix(ShotgunItem __instance, bool right) { try { Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !right || (Object)(object)((GrabbableObject)__instance).playerHeldBy == (Object)null) { return true; } if (((NetworkBehaviour)__instance).IsOwner && !WeaponReloadInput.AcceptRightInteractReload) { return false; } if (component.Config != null && component.Config.FireMode == WeaponFireMode.ContinuousStream) { ((Component)__instance).GetComponent()?.TryBeginReload(); return false; } int num = ((component.Config != null) ? component.Config.MagazineSize : 2); if (!__instance.isReloading && __instance.shellsLoaded < num) { Traverse.Create((object)__instance).Method("StartReloadGun", Array.Empty()).GetValue(); } return false; } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons] ItemInteractLeftRight prefix threw: {arg}"); } return true; } } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] [HarmonyPrefix] private static bool ShootGun_Prefix(ShotgunItem __instance, Vector3 shotgunPosition, Vector3 shotgunForward, out int __state) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) __state = __instance.shellsLoaded; try { Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); if (component == null || component.Config?.FireMode != WeaponFireMode.LobbedProjectile) { return true; } GrenadeLauncherPatches.FireLocal(__instance, shotgunPosition, shotgunForward); return false; } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[GrenadeLauncher] custom fire prefix threw; suppressing vanilla hitscan: {arg}"); } return false; } } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] [HarmonyPostfix] private static void ShootGun_Postfix(ShotgunItem __instance, int __state) { try { Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { WeaponConfig config = component.Config; if (config == null || config.FireMode != WeaponFireMode.ContinuousStream) { __instance.shellsLoaded = Math.Max(0, __state - 1); } } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons] ShootGun magazine postfix threw: {arg}"); } } } [HarmonyPatch(typeof(ShotgunItem), "ReloadGunEffectsServerRpc")] [HarmonyPostfix] private static void ReloadGunEffectsServerRpc_Postfix(ShotgunItem __instance, bool start) { try { if (start) { return; } Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && component.PendingShellsAfterReload >= 0) { __instance.shellsLoaded = component.PendingShellsAfterReload; component.PendingShellsAfterReload = -1; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Y4NGZWeapons] Reload finished: magazine at {__instance.shellsLoaded}."); } } } catch (Exception arg) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)$"[Y4NGZWeapons] Reload-finish postfix threw: {arg}"); } } } [HarmonyPatch(typeof(PlayerControllerB), "DestroyItemInSlotAndSync")] [HarmonyPrefix] private static bool DestroyItemInSlotAndSync_Prefix(int __0) { return __0 >= 0; } } [HarmonyPatch] internal static class FlamethrowerPatches { [HarmonyPatch(typeof(ShotgunItem), "ItemActivate")] [HarmonyPrefix] private static bool ItemActivate_Prefix(ShotgunItem __instance, bool used, bool buttonDown) { try { FlamethrowerStreamDriver component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } component.SetLocalUse(buttonDown); return false; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Flamethrower] ItemActivate failed: " + ex)); } return false; } } [HarmonyPatch(typeof(ShotgunItem), "ItemInteractLeftRight")] [HarmonyPrefix] [HarmonyPriority(800)] private static bool ItemInteractLeftRight_Prefix(ShotgunItem __instance, bool right) { FlamethrowerStreamDriver component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if (right && (!((NetworkBehaviour)__instance).IsOwner || WeaponReloadInput.AcceptRightInteractReload)) { component.TryBeginReload(); } return false; } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] [HarmonyPrefix] [HarmonyPriority(800)] private static bool ShootGun_Prefix(ShotgunItem __instance) { return (Object)(object)((Component)__instance).GetComponent() == (Object)null; } [HarmonyPatch(typeof(ShotgunItem), "SetControlTipsForItem")] [HarmonyPrefix] private static bool SetControlTipsForItem_Prefix(ShotgunItem __instance) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { return true; } if ((Object)(object)HUDManager.Instance != (Object)null && (Object)(object)((GrabbableObject)__instance).itemProperties != (Object)null) { HUDManager.Instance.ChangeControlTipMultiple(((GrabbableObject)__instance).itemProperties.toolTips, true, ((GrabbableObject)__instance).itemProperties); } return false; } [HarmonyPatch(typeof(ShotgunItem), "SetSafetyControlTip")] [HarmonyPrefix] private static bool SetSafetyControlTip_Prefix(ShotgunItem __instance) { return (Object)(object)((Component)__instance).GetComponent() == (Object)null; } [HarmonyPatch(typeof(ShotgunItem), "PocketItem")] [HarmonyPrefix] private static void PocketItem_Prefix(ShotgunItem __instance) { ((Component)__instance).GetComponent()?.ForceLocalStop(); } [HarmonyPatch(typeof(ShotgunItem), "DiscardItem")] [HarmonyPrefix] private static void DiscardItem_Prefix(ShotgunItem __instance) { ((Component)__instance).GetComponent()?.ForceLocalStop(); } } [HarmonyPatch] internal static class GrenadeLauncherPatches { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnReceiveDetonation; } private const string DetonationMessage = "Y4NGZ_GrenadeLauncher_Detonate_v1"; private static readonly Dictionary NextShotByWeapon = new Dictionary(); private static bool _handlersRegistered; internal static void FireLocal(ShotgunItem shotgun, Vector3 shotgunPosition, Vector3 shotgunForward) { //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)shotgun == (Object)null) { return; } RegisterNetworkHandlers(); shotgun.isReloading = false; PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (((GrabbableObject)shotgun).isHeld && (Object)(object)((GrabbableObject)shotgun).playerHeldBy != (Object)null && (Object)(object)((GrabbableObject)shotgun).playerHeldBy == (Object)(object)val) { Animator playerBodyAnimator = ((GrabbableObject)shotgun).playerHeldBy.playerBodyAnimator; if (playerBodyAnimator != null) { playerBodyAnimator.SetTrigger("ShootShotgun"); } } if ((Object)(object)shotgun.gunShootAudio != (Object)null && shotgun.gunShootSFX != null && shotgun.gunShootSFX.Length != 0) { RoundManager.PlayRandomClip(shotgun.gunShootAudio, shotgun.gunShootSFX, true, 1f, 1840, 1000); WalkieTalkie.TransmitOneShotAudio(shotgun.gunShootAudio, shotgun.gunShootSFX[0], 1f); } if ((Object)(object)shotgun.gunShootParticle != (Object)null) { shotgun.gunShootParticle.Play(true); } TriggerWorldProp(shotgun, "Y4NGZ_GrenadeLauncherProp_Fire"); ulong networkObjectId = ((NetworkBehaviour)shotgun).NetworkObjectId; uint shotId = NextShotId(networkObjectId); bool authoritative = (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsServer; if ((Object)(object)GrenadeLauncherProjectile.Spawn(shotgunPosition, shotgunForward, networkObjectId, shotId, authoritative) != (Object)null && (Object)(object)((GrabbableObject)shotgun).playerHeldBy != (Object)null && (Object)(object)((GrabbableObject)shotgun).playerHeldBy == (Object)(object)val) { CrosshairSignals.RecordCommittedLocalShot(); } } internal static void OnReloadStarted(ShotgunItem shotgun) { if (IsGrenadeLauncher(shotgun)) { TriggerWorldProp(shotgun, "Y4NGZ_GrenadeLauncherProp_Reload"); } } internal static void PublishDetonation(ulong weaponNetworkObjectId, uint shotId, Vector3 position) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && !singleton.IsServer) { return; } GrenadeLauncherProjectile.DetonateSynced(weaponNetworkObjectId, shotId, position); if (((singleton != null) ? singleton.CustomMessagingManager : null) == null) { return; } int num = 24; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(num, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref shotId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref position.x, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref position.y, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref position.z, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessageToAll("Y4NGZ_GrenadeLauncher_Detonate_v1", val, (NetworkDelivery)3); } finally { ((FastBufferWriter)(ref val)).Dispose(); } } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] private static void ConnectClientToPlayerObject_Postfix() { RegisterNetworkHandlers(); } internal static void OnRoundStarted() { NextShotByWeapon.Clear(); GrenadeLauncherProjectile.DestroyAllActive(); RegisterNetworkHandlers(); } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static void EndOfGame_Postfix() { NextShotByWeapon.Clear(); GrenadeLauncherProjectile.DestroyAllActive(); } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] [HarmonyPostfix] private static void Disconnect_Postfix() { _handlersRegistered = false; NextShotByWeapon.Clear(); GrenadeLauncherProjectile.DestroyAllActive(); } [HarmonyPatch(typeof(ShotgunItem), "ReloadGunEffectsClientRpc")] [HarmonyPostfix] private static void ReloadGunEffectsClientRpc_Postfix(ShotgunItem __instance, bool start) { if (start && IsGrenadeLauncher(__instance) && !((NetworkBehaviour)__instance).IsOwner) { TriggerWorldProp(__instance, "Y4NGZ_GrenadeLauncherProp_Reload"); } } private static void RegisterNetworkHandlers() { //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_0046: Expected O, but got Unknown if (_handlersRegistered) { return; } NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) == null) { return; } try { CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; object obj = <>O.<0>__OnReceiveDetonation; if (obj == null) { HandleNamedMessageDelegate val = OnReceiveDetonation; <>O.<0>__OnReceiveDetonation = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("Y4NGZ_GrenadeLauncher_Detonate_v1", (HandleNamedMessageDelegate)obj); _handlersRegistered = true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GrenadeLauncher] detonation handler registration failed: " + ex.Message)); } } } private static void OnReceiveDetonation(ulong senderClientId, FastBufferReader reader) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0063: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)NetworkManager.Singleton != (Object)null) || !NetworkManager.Singleton.IsServer) { ulong weaponNetworkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref weaponNetworkObjectId, default(ForPrimitives)); uint shotId = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref shotId, default(ForPrimitives)); float num = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); float num3 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num3, default(ForPrimitives)); GrenadeLauncherProjectile.DetonateSynced(weaponNetworkObjectId, shotId, new Vector3(num, num2, num3)); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GrenadeLauncher] malformed detonation sync: " + ex.Message)); } } } private static uint NextShotId(ulong weaponNetworkObjectId) { NextShotByWeapon.TryGetValue(weaponNetworkObjectId, out var value); value = ((value == uint.MaxValue) ? 1u : (value + 1)); NextShotByWeapon[weaponNetworkObjectId] = value; return value; } private static bool IsGrenadeLauncher(ShotgunItem shotgun) { Y4NGZWeaponItem obj = (((Object)(object)shotgun != (Object)null) ? ((Component)shotgun).GetComponent() : null); if (obj == null) { return false; } return obj.Config?.FireMode == WeaponFireMode.LobbedProjectile; } private static void TriggerWorldProp(ShotgunItem shotgun, string trigger) { if (!((Object)(object)shotgun == (Object)null) && !string.IsNullOrEmpty(trigger)) { Transform val = ((Component)shotgun).transform.Find("Y4NGZ_GrenadeLauncherVisual"); Animator val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : null); if ((Object)(object)val2 != (Object)null) { val2.SetTrigger(trigger); } } } } internal static class GrenadeThrowPatches { private sealed class LocalThrow { internal PlayerControllerB Player; internal uint ThrowId; internal float DeadlineAt; internal Coroutine Routine; internal HeldItemStowHandle Stow; internal List DisabledActions; internal InteractionAnimationHandle InteractionHandle; internal bool Released; internal bool Cleaned; } private readonly struct ServerThrowTicket { internal readonly uint ThrowId; internal readonly float ExpiresAt; internal ServerThrowTicket(uint throwId, float expiresAt) { ThrowId = throwId; ExpiresAt = expiresAt; } } [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnStartRequest; public static HandleNamedMessageDelegate <1>__OnStartBroadcast; public static HandleNamedMessageDelegate <2>__OnReleaseRequest; public static HandleNamedMessageDelegate <3>__OnReleaseBroadcast; public static HandleNamedMessageDelegate <4>__OnDetonationBroadcast; } private const string StartRequestMessage = "Y4NGZ_HandGrenade_StartRequest_v1"; private const string StartMessage = "Y4NGZ_HandGrenade_Start_v1"; private const string ReleaseRequestMessage = "Y4NGZ_HandGrenade_ReleaseRequest_v1"; private const string ReleaseMessage = "Y4NGZ_HandGrenade_Release_v1"; private const string DetonationMessage = "Y4NGZ_HandGrenade_Detonate_v1"; private const string PackId = "y4ngz.upgrades.grenade.fp"; private const string InteractionId = "y4ngz.grenade.throw"; private const string ManifestFileName = "y4ngz-upgrades-grenade-livebody.manifest.json"; private const float StowSeconds = 0.28f; private const string StowReason = "grenade-throw"; private const float StowTimeoutSeconds = 6f; private const float ReleaseAfterAnimationStart = 1.325f; private const float RestoreAfterRelease = 0.8f; private const float ThrowDeadlineMargin = 1.5f; private const float TicketLifetimeSeconds = 4f; private const float MaxReleasePositionError = 3f; private const string VanillaThrowState = "PullGrenadePin"; private const string VanillaThrowFullPath = "UpperBodyEmotes.PullGrenadePin"; private const int UpperBodyEmotesLayer = 3; private const float VanillaThrowSeconds = 1.16f; private static readonly int VanillaThrowHash = Animator.StringToHash("PullGrenadePin"); private static readonly int VanillaThrowFullPathHash = Animator.StringToHash("UpperBodyEmotes.PullGrenadePin"); private static readonly Dictionary ServerTickets = new Dictionary(); private static readonly Dictionary RemotePresentations = new Dictionary(); private static readonly string[] SuppressedActionNames = new string[6] { "ActivateItem", "ItemSecondaryUse", "ItemTertiaryUse", "SwitchItem", "UseUtilitySlot", "DiscardHeldObject" }; private static LocalThrow _activeThrow; private static bool _keyWasDown; private static bool _localThrowActive; private static bool _handlersRegistered; private static bool _packRegistered; private static bool _missingManifestLogged; private static float _nextRegistrationAttemptAt; private static uint _nextThrowId = 1u; [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] private static void ConnectClientToPlayerObject_Postfix() { ArmoryPersistentRunner.Ensure(); RegisterNetworkHandlers(); EnsurePackRegistered(); } internal static void OnRoundStarted() { ArmoryPersistentRunner.Ensure(); ForceCleanup("round-start", janitorForced: true); _keyWasDown = false; _localThrowActive = false; _nextThrowId = 1u; ServerTickets.Clear(); RemotePresentations.Clear(); HandGrenadeProjectile.DestroyAllActive(); RegisterNetworkHandlers(); EnsurePackRegistered(); } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static void EndOfGame_Postfix() { ForceCleanup("round-end", janitorForced: true); ServerTickets.Clear(); RemotePresentations.Clear(); HandGrenadeProjectile.DestroyAllActive(); } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] [HarmonyPostfix] private static void Disconnect_Postfix() { ForceCleanup("disconnect", janitorForced: true); _handlersRegistered = false; _packRegistered = false; _missingManifestLogged = false; _nextRegistrationAttemptAt = 0f; _localThrowActive = false; ServerTickets.Clear(); RemotePresentations.Clear(); HandGrenadeProjectile.DestroyAllActive(); } [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] private static void PlayerUpdate_Postfix(PlayerControllerB __instance) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerControlled || (Object)(object)__instance != (Object)(object)GameNetworkManager.Instance?.localPlayerController) { return; } Keyboard current = Keyboard.current; if (current != null) { Key? val = null; bool flag = (val.HasValue ? ((ButtonControl)current[val.Value]).isPressed : ((ButtonControl)current.bKey).isPressed); bool num = flag && !_keyWasDown; _keyWasDown = flag; if (num && !_localThrowActive) { TryBeginLocalThrow(__instance); } } } private static void TryBeginLocalThrow(PlayerControllerB player) { if ((Object)(object)player == (Object)null || player.isPlayerDead || player.isTypingChat || player.inTerminalMenu || player.inSpecialInteractAnimation || player.isGrabbingObjectAnimation || player.activatingItem || player.throwingObject || player.isClimbingLadder || ((Object)(object)player.quickMenuManager != (Object)null && player.quickMenuManager.isMenuOpen) || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase) { return; } if (!AmmoReserve.TryConsume(WeaponAmmoType.Grenades, 1)) { HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip("GRENADE INVENTORY", "No grenades available.", true, false, "LC_Tip1"); } return; } LocalThrow localThrow = (_activeThrow = new LocalThrow { Player = player, ThrowId = NextThrowId(), DeadlineAt = Time.time + 0.28f + 1.325f + 0.8f + 1.5f }); _localThrowActive = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Grenade] throw {localThrow.ThrowId} begin for {DescribePlayer(player)}; " + "held item '" + DescribeHeldItem(player) + "'.")); } localThrow.Routine = ArmoryPersistentRunner.Run(LocalThrowRoutine(localThrow)); if (localThrow.Routine == null && !localThrow.Cleaned) { Cleanup(localThrow, "runner-unavailable", janitorForced: true); } } private static IEnumerator LocalThrowRoutine(LocalThrow state) { PlayerControllerB player = state.Player; state.Stow = HeldItemStowService.Begin(player, "grenade-throw", 6f, disableItemActions: true, force: true); bool isActive = state.Stow.IsActive; state.DisabledActions = (isActive ? null : DisableItemActions()); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"[Grenade] throw {state.ThrowId} input suppression: " + (isActive ? "held-item stow." : $"local action disable ({state.DisabledActions.Count} actions)."))); } try { SendStartRequest(((NetworkBehaviour)player).NetworkObjectId, state.ThrowId); yield return (object)new WaitForSeconds(0.28f); if (!TryContinueThrow(state, "pre-animation")) { yield break; } if (TryPlayRetargetedThrow(player, out var handle)) { state.InteractionHandle = handle; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[Grenade] throw {state.ThrowId} animation path: retargeted."); } } else { PlayVanillaThrow(player); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[Grenade] throw {state.ThrowId} animation path: vanilla PullGrenadePin."); } } PlayGrenadeSound(player, GrenadeContentAssets.LoadPinSound()); yield return (object)new WaitForSeconds(1.325f); if (TryContinueThrow(state, "pre-release")) { ResolveReleasePose(player, out var position, out var direction); ReleaseLocalGrenade(((NetworkBehaviour)player).NetworkObjectId, state.ThrowId, position, direction); state.Released = true; ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)string.Format("[Grenade] throw {0} released at {1}.", state.ThrowId, ((Vector3)(ref position)).ToString("F2"))); } yield return (object)new WaitForSeconds(0.8f); } } finally { Cleanup(state, state.Released ? "completed" : "aborted", janitorForced: false); } } internal static void TickLocalThrowJanitor() { LocalThrow activeThrow = _activeThrow; if (activeThrow == null) { return; } if (activeThrow.Cleaned) { if (_activeThrow == activeThrow) { _activeThrow = null; } return; } string text = null; PlayerControllerB player = activeThrow.Player; if ((Object)(object)player == (Object)null || player.isPlayerDead || !player.isPlayerControlled) { text = "player dead or gone"; } else if ((Object)(object)player != (Object)(object)GameNetworkManager.Instance?.localPlayerController) { text = "local player replaced"; } else if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase) { text = "ship phase"; } else if (Time.time >= activeThrow.DeadlineAt) { text = "deadline expired"; } if (text != null) { Cleanup(activeThrow, text, janitorForced: true); } } private static void ForceCleanup(string reason, bool janitorForced) { LocalThrow activeThrow = _activeThrow; if (activeThrow != null && !activeThrow.Cleaned) { Cleanup(activeThrow, reason, janitorForced); } _activeThrow = null; } private static void Cleanup(LocalThrow state, string reason, bool janitorForced) { //IL_0021: 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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (state == null || state.Cleaned) { return; } state.Cleaned = true; if (((InteractionAnimationHandle)(ref state.InteractionHandle)).IsValid) { LCInteractionAnimationAPI.TryStopInteraction(state.InteractionHandle, (InteractionAnimationStopReason)(state.Released ? 1 : 2)); state.InteractionHandle = InteractionAnimationHandle.Empty; } if (!state.Released) { AmmoReserve.TryAdd(WeaponAmmoType.Grenades, 1, out var _); } state.Stow.Dispose(); EnableActions(state.DisabledActions); state.DisabledActions = null; if (janitorForced) { ForceEnableSuppressedActions(); } _localThrowActive = false; if (_activeThrow == state) { _activeThrow = null; } if (janitorForced) { ArmoryPersistentRunner.Stop(state.Routine); ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)($"[Grenade] throw {state.ThrowId} force-cleaned by janitor ({reason}); " + "item input re-enabled.")); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[Grenade] throw {state.ThrowId} cleanup ({reason})."); } } state.Routine = null; } private static bool TryContinueThrow(LocalThrow state, string stage) { if (state.Cleaned) { return false; } PlayerControllerB player = state.Player; string text = null; if ((Object)(object)player == (Object)null || player.isPlayerDead || !player.isPlayerControlled) { text = "player dead or gone"; } else if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase) { text = "ship phase"; } if (text == null) { return true; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[Grenade] throw {state.ThrowId} aborted at {stage}: {text}."); } return false; } private static List DisableItemActions() { List list = new List(SuppressedActionNames.Length); IngamePlayerSettings instance = IngamePlayerSettings.Instance; object obj; if (instance == null) { obj = null; } else { PlayerInput playerInput = instance.playerInput; obj = ((playerInput != null) ? playerInput.actions : null); } InputActionAsset val = (InputActionAsset)obj; if ((Object)(object)val == (Object)null) { return list; } for (int i = 0; i < SuppressedActionNames.Length; i++) { InputAction val2 = val.FindAction(SuppressedActionNames[i], false); if (val2 != null && val2.enabled) { val2.Disable(); list.Add(val2); } } return list; } private static void EnableActions(List actions) { if (actions == null) { return; } for (int i = 0; i < actions.Count; i++) { InputAction obj = actions[i]; if (obj != null) { obj.Enable(); } } } private static void ForceEnableSuppressedActions() { IngamePlayerSettings instance = IngamePlayerSettings.Instance; object obj; if (instance == null) { obj = null; } else { PlayerInput playerInput = instance.playerInput; obj = ((playerInput != null) ? playerInput.actions : null); } InputActionAsset val = (InputActionAsset)obj; if ((Object)(object)val == (Object)null) { return; } for (int i = 0; i < SuppressedActionNames.Length; i++) { InputAction obj2 = val.FindAction(SuppressedActionNames[i], false); if (obj2 != null) { obj2.Enable(); } } } private static string DescribePlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return ""; } string arg = (string.IsNullOrWhiteSpace(player.playerUsername) ? "player" : player.playerUsername); return $"{arg}#{((NetworkBehaviour)player).NetworkObjectId}"; } private static string DescribeHeldItem(PlayerControllerB player) { GrabbableObject val = player?.currentlyHeldObjectServer; if ((Object)(object)val == (Object)null) { return "none"; } if (!((Object)(object)val.itemProperties != (Object)null) || string.IsNullOrWhiteSpace(val.itemProperties.itemName)) { return ((Object)val).name; } return val.itemProperties.itemName; } private static void ResolveReleasePose(PlayerControllerB player, out Vector3 position, out Vector3 direction) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) //IL_00b9: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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) object obj; if (player == null) { obj = null; } else { Camera gameplayCamera = player.gameplayCamera; obj = ((gameplayCamera != null) ? ((Component)gameplayCamera).transform : null); } Transform val = (Transform)obj; direction = (((Object)(object)val != (Object)null) ? val.forward : ((Component)player).transform.forward); Transform val2 = FindChildRecursive(player?.playerModelArmsMetarig, "hand.R"); position = (((Object)(object)val2 != (Object)null) ? (val2.position + ((Vector3)(ref direction)).normalized * 0.12f) : (((Object)(object)val != (Object)null) ? (val.position + ((Vector3)(ref direction)).normalized * 0.35f) : (((Component)player).transform.position + Vector3.up * 1.2f + ((Vector3)(ref direction)).normalized * 0.25f))); } private static Transform FindChildRecursive(Transform root, string name) { if ((Object)(object)root == (Object)null) { return null; } if (string.Equals(((Object)root).name, name, StringComparison.OrdinalIgnoreCase)) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindChildRecursive(root.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static uint NextThrowId() { uint result = _nextThrowId++; if (_nextThrowId == 0) { _nextThrowId = 1u; } return result; } private static void RegisterNetworkHandlers() { //IL_0034: 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) //IL_003f: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (_handlersRegistered || val == null) { return; } try { object obj = <>O.<0>__OnStartRequest; if (obj == null) { HandleNamedMessageDelegate val2 = OnStartRequest; <>O.<0>__OnStartRequest = val2; obj = (object)val2; } val.RegisterNamedMessageHandler("Y4NGZ_HandGrenade_StartRequest_v1", (HandleNamedMessageDelegate)obj); object obj2 = <>O.<1>__OnStartBroadcast; if (obj2 == null) { HandleNamedMessageDelegate val3 = OnStartBroadcast; <>O.<1>__OnStartBroadcast = val3; obj2 = (object)val3; } val.RegisterNamedMessageHandler("Y4NGZ_HandGrenade_Start_v1", (HandleNamedMessageDelegate)obj2); object obj3 = <>O.<2>__OnReleaseRequest; if (obj3 == null) { HandleNamedMessageDelegate val4 = OnReleaseRequest; <>O.<2>__OnReleaseRequest = val4; obj3 = (object)val4; } val.RegisterNamedMessageHandler("Y4NGZ_HandGrenade_ReleaseRequest_v1", (HandleNamedMessageDelegate)obj3); object obj4 = <>O.<3>__OnReleaseBroadcast; if (obj4 == null) { HandleNamedMessageDelegate val5 = OnReleaseBroadcast; <>O.<3>__OnReleaseBroadcast = val5; obj4 = (object)val5; } val.RegisterNamedMessageHandler("Y4NGZ_HandGrenade_Release_v1", (HandleNamedMessageDelegate)obj4); object obj5 = <>O.<4>__OnDetonationBroadcast; if (obj5 == null) { HandleNamedMessageDelegate val6 = OnDetonationBroadcast; <>O.<4>__OnDetonationBroadcast = val6; obj5 = (object)val6; } val.RegisterNamedMessageHandler("Y4NGZ_HandGrenade_Detonate_v1", (HandleNamedMessageDelegate)obj5); _handlersRegistered = true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] network handler registration failed: " + ex.Message)); } } } private static void SendStartRequest(ulong playerNetworkObjectId, uint throwId) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null) { return; } if (singleton.IsServer) { AcceptStart(singleton.LocalClientId, playerNetworkObjectId, throwId); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref playerNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref throwId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("Y4NGZ_HandGrenade_StartRequest_v1", 0uL, val, (NetworkDelivery)3); } finally { ((FastBufferWriter)(ref val)).Dispose(); } } private static void OnStartRequest(ulong senderClientId, FastBufferReader reader) { //IL_0021: 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_0033: 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)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer) { return; } try { ulong playerNetworkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref playerNetworkObjectId, default(ForPrimitives)); uint throwId = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref throwId, default(ForPrimitives)); AcceptStart(senderClientId, playerNetworkObjectId, throwId); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] malformed start request: " + ex.Message)); } } } private static void AcceptStart(ulong senderClientId, ulong playerNetworkObjectId, uint throwId) { if (TryResolveOwnedPlayer(playerNetworkObjectId, senderClientId, out var player) && (!ServerTickets.TryGetValue(playerNetworkObjectId, out var value) || !(value.ExpiresAt > Time.time))) { ServerTickets[playerNetworkObjectId] = new ServerThrowTicket(throwId, Time.time + 4f); if ((Object)(object)player != (Object)(object)GameNetworkManager.Instance?.localPlayerController) { BeginRemotePresentation(playerNetworkObjectId, throwId); } BroadcastStart(playerNetworkObjectId, throwId); } } private static void BroadcastStart(ulong playerNetworkObjectId, uint throwId) { //IL_0027: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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) NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val == null) { return; } FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(12, (Allocator)2, -1); try { ((FastBufferWriter)(ref val2)).WriteValueSafe(ref playerNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref throwId, default(ForPrimitives)); val.SendNamedMessageToAll("Y4NGZ_HandGrenade_Start_v1", val2, (NetworkDelivery)3); } finally { ((FastBufferWriter)(ref val2)).Dispose(); } } private static void OnStartBroadcast(ulong senderClientId, FastBufferReader reader) { //IL_0021: 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_0033: 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)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer) { return; } try { ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); uint throwId = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref throwId, default(ForPrimitives)); PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || ((NetworkBehaviour)val).NetworkObjectId != num) { BeginRemotePresentation(num, throwId); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] malformed start broadcast: " + ex.Message)); } } } private static void ReleaseLocalGrenade(ulong playerNetworkObjectId, uint throwId, Vector3 position, Vector3 direction) { //IL_003a: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0057: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) PlayGrenadeSound(GameNetworkManager.Instance?.localPlayerController, GrenadeContentAssets.LoadThrowSound()); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null) { HandGrenadeProjectile.Spawn(position, direction, playerNetworkObjectId, throwId, authoritative: true); return; } if (singleton.IsServer) { AcceptRelease(singleton.LocalClientId, playerNetworkObjectId, throwId, position, direction); return; } HandGrenadeProjectile.Spawn(position, direction, playerNetworkObjectId, throwId, authoritative: false); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(36, (Allocator)2, -1); try { WriteRelease(val, playerNetworkObjectId, throwId, position, direction); singleton.CustomMessagingManager.SendNamedMessage("Y4NGZ_HandGrenade_ReleaseRequest_v1", 0uL, val, (NetworkDelivery)3); } finally { ((FastBufferWriter)(ref val)).Dispose(); } } private static void OnReleaseRequest(ulong senderClientId, FastBufferReader reader) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer) { return; } try { ReadRelease(reader, out var playerNetworkObjectId, out var throwId, out var position, out var direction); AcceptRelease(senderClientId, playerNetworkObjectId, throwId, position, direction); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] malformed release request: " + ex.Message)); } } } private static void AcceptRelease(ulong senderClientId, ulong playerNetworkObjectId, uint throwId, Vector3 position, Vector3 direction) { //IL_006b: 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_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) if (TryResolveOwnedPlayer(playerNetworkObjectId, senderClientId, out var player) && ServerTickets.TryGetValue(playerNetworkObjectId, out var value) && value.ThrowId == throwId && !(value.ExpiresAt < Time.time)) { ServerTickets.Remove(playerNetworkObjectId); SanitizeReleasePose(player, ref position, ref direction); if ((Object)(object)player != (Object)(object)GameNetworkManager.Instance?.localPlayerController) { PlayGrenadeSound(player, GrenadeContentAssets.LoadThrowSound()); } HandGrenadeProjectile.Spawn(position, direction, playerNetworkObjectId, throwId, authoritative: true); BroadcastRelease(playerNetworkObjectId, throwId, position, direction); } } private static void BroadcastRelease(ulong playerNetworkObjectId, uint throwId, Vector3 position, Vector3 direction) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val == null) { return; } FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(36, (Allocator)2, -1); try { WriteRelease(val2, playerNetworkObjectId, throwId, position, direction); val.SendNamedMessageToAll("Y4NGZ_HandGrenade_Release_v1", val2, (NetworkDelivery)3); } finally { ((FastBufferWriter)(ref val2)).Dispose(); } } private static void OnReleaseBroadcast(ulong senderClientId, FastBufferReader reader) { //IL_001b: 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_0063: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer) { return; } try { ReadRelease(reader, out var playerNetworkObjectId, out var throwId, out var position, out var direction); PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val != (Object)null) || ((NetworkBehaviour)val).NetworkObjectId != playerNetworkObjectId) { PlayGrenadeSound(FindPlayer(playerNetworkObjectId), GrenadeContentAssets.LoadThrowSound()); HandGrenadeProjectile.Spawn(position, direction, playerNetworkObjectId, throwId, authoritative: false); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] malformed release broadcast: " + ex.Message)); } } } internal static void PublishDetonation(ulong playerNetworkObjectId, uint throwId, Vector3 position) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && !singleton.IsServer) { return; } HandGrenadeProjectile.DetonateSynced(playerNetworkObjectId, throwId, position); CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val == null) { return; } FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(24, (Allocator)2, -1); try { ((FastBufferWriter)(ref val2)).WriteValueSafe(ref playerNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref throwId, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref position.x, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref position.y, default(ForPrimitives)); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref position.z, default(ForPrimitives)); val.SendNamedMessageToAll("Y4NGZ_HandGrenade_Detonate_v1", val2, (NetworkDelivery)3); } finally { ((FastBufferWriter)(ref val2)).Dispose(); } } private static void OnDetonationBroadcast(ulong senderClientId, FastBufferReader reader) { //IL_0021: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer) { return; } try { ulong playerNetworkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref playerNetworkObjectId, default(ForPrimitives)); uint throwId = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref throwId, default(ForPrimitives)); float num = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); float num3 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num3, default(ForPrimitives)); HandGrenadeProjectile.DetonateSynced(playerNetworkObjectId, throwId, new Vector3(num, num2, num3)); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] malformed detonation broadcast: " + ex.Message)); } } } private static void WriteRelease(FastBufferWriter writer, ulong playerNetworkObjectId, uint throwId, Vector3 position, Vector3 direction) { //IL_0006: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0035: 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_004c: 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_0063: 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_007a: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) ((FastBufferWriter)(ref writer)).WriteValueSafe(ref playerNetworkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref throwId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref position.x, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref position.y, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref position.z, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref direction.x, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref direction.y, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref direction.z, default(ForPrimitives)); } private static void ReadRelease(FastBufferReader reader, out ulong playerNetworkObjectId, out uint throwId, out Vector3 position, out Vector3 direction) { //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) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) ((FastBufferReader)(ref reader)).ReadValueSafe(ref playerNetworkObjectId, default(ForPrimitives)); ((FastBufferReader)(ref reader)).ReadValueSafe(ref throwId, default(ForPrimitives)); float num = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); float num3 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num3, default(ForPrimitives)); float num4 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num4, default(ForPrimitives)); float num5 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num5, default(ForPrimitives)); float num6 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num6, default(ForPrimitives)); position = new Vector3(num, num2, num3); direction = new Vector3(num4, num5, num6); } private static bool TryResolveOwnedPlayer(ulong playerNetworkObjectId, ulong senderClientId, out PlayerControllerB player) { player = FindPlayer(playerNetworkObjectId); if ((Object)(object)player != (Object)null) { return ((NetworkBehaviour)player).OwnerClientId == senderClientId; } return false; } private static PlayerControllerB FindPlayer(ulong playerNetworkObjectId) { PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if (array == null) { return null; } for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && ((NetworkBehaviour)array[i]).NetworkObjectId == playerNetworkObjectId) { return array[i]; } } return null; } private static void SanitizeReleasePose(PlayerControllerB player, ref Vector3 position, ref Vector3 direction) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0051: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)player != (Object)null) ? ((Component)player).transform.forward : Vector3.forward); if (((Vector3)(ref direction)).sqrMagnitude < 0.25f || float.IsNaN(direction.x) || float.IsNaN(direction.y) || float.IsNaN(direction.z)) { direction = val; } ((Vector3)(ref direction)).Normalize(); Vector3 val2 = (((Object)(object)player != (Object)null) ? (((Component)player).transform.position + Vector3.up * 1.2f + direction * 0.35f) : position); Vector3 val3 = position - val2; if (((Vector3)(ref val3)).sqrMagnitude > 9f) { position = val2; } } private static void BeginRemotePresentation(ulong playerNetworkObjectId, uint throwId) { if (RemotePresentations.ContainsKey(playerNetworkObjectId)) { return; } PlayerControllerB val = FindPlayer(playerNetworkObjectId); if (!((Object)(object)val == (Object)null)) { RemotePresentations[playerNetworkObjectId] = throwId; if (ArmoryPersistentRunner.Run(RemotePresentationRoutine(val, throwId)) == null) { RemotePresentations.Remove(playerNetworkObjectId); } } } private static IEnumerator RemotePresentationRoutine(PlayerControllerB player, uint throwId) { ulong playerNetworkObjectId = ((NetworkBehaviour)player).NetworkObjectId; HeldItemStowHandle stow = HeldItemStowService.Begin(player, "grenade-throw", 6f, disableItemActions: false, force: true); try { yield return (object)new WaitForSeconds(0.28f); if ((Object)(object)player != (Object)null && !player.isPlayerDead) { PlayVanillaThrow(player); PlayGrenadeSound(player, GrenadeContentAssets.LoadPinSound()); } yield return (object)new WaitForSeconds(2.125f); } finally { stow.Dispose(); if (RemotePresentations.TryGetValue(playerNetworkObjectId, out var value) && value == throwId) { RemotePresentations.Remove(playerNetworkObjectId); } } } private static bool TryPlayRetargetedThrow(PlayerControllerB player, out InteractionAnimationHandle handle) { //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) //IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown handle = InteractionAnimationHandle.Empty; if (!EnsurePackRegistered()) { return false; } string text = default(string); if (LCInteractionAnimationAPI.TryStartInteraction(new InteractionAnimationRequest { Player = player, PackId = "y4ngz.upgrades.grenade.fp", InteractionId = "y4ngz.grenade.throw" }, ref handle, ref text)) { return true; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] retargeted throw could not start: " + text)); } return false; } private static bool EnsurePackRegistered() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown if (_packRegistered) { return true; } if (Time.realtimeSinceStartup < _nextRegistrationAttemptAt) { return false; } _nextRegistrationAttemptAt = Time.realtimeSinceStartup + 2f; string directoryName = Path.GetDirectoryName(typeof(Plugin).Assembly.Location); string text = Path.Combine(directoryName ?? string.Empty, "y4ngz-upgrades-grenade-livebody.manifest.json"); if (!File.Exists(text)) { if (!_missingManifestLogged) { _missingManifestLogged = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] retargeted throw manifest not found: " + text)); } } return false; } string manifestJson; try { manifestJson = File.ReadAllText(text); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Grenade] retargeted throw manifest read failed: " + ex.Message)); } return false; } InteractionAnimationPackDefinition val = new InteractionAnimationPackDefinition(); val.PackId = "y4ngz.upgrades.grenade.fp"; val.Version = "0.1.0"; val.AssetRootPath = directoryName ?? string.Empty; val.Interactions = (InteractionAnimationDefinition[])(object)new InteractionAnimationDefinition[1] { new InteractionAnimationDefinition { InteractionId = "y4ngz.grenade.throw", PresentationKind = (InteractionAnimationPresentationKind)1, ManifestJson = manifestJson } }; string text2 = default(string); if (!LCInteractionAnimationAPI.TryRegisterInteractionPack(val, ref text2)) { if (string.Equals(text2, "pack_already_registered", StringComparison.OrdinalIgnoreCase)) { _packRegistered = true; return true; } ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Grenade] retargeted throw pack registration failed: " + text2)); } return false; } _packRegistered = true; _missingManifestLogged = false; ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)"[Grenade] registered retargeted grenade throw pack."); } return true; } private static void PlayVanillaThrow(PlayerControllerB player) { Animator val = player?.playerBodyAnimator; if ((Object)(object)val == (Object)null) { return; } try { player.doingUpperBodyEmote = Mathf.Max(player.doingUpperBodyEmote, 1.16f); val.SetTrigger("PullGrenadePin"); if (val.layerCount > 3) { if (val.HasState(3, VanillaThrowFullPathHash)) { val.Play(VanillaThrowFullPathHash, 3, 0f); } else if (val.HasState(3, VanillaThrowHash)) { val.Play(VanillaThrowHash, 3, 0f); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Grenade] vanilla throw fallback failed: " + ex.Message)); } } } private static void PlayGrenadeSound(PlayerControllerB player, AudioClip clip) { if (!((Object)(object)player == (Object)null) && !((Object)(object)clip == (Object)null)) { AudioSource itemAudio = player.itemAudio; if ((Object)(object)itemAudio != (Object)null) { itemAudio.PlayOneShot(clip, 0.85f); } } } } [HarmonyPatch] internal static class WeaponPatches { [HarmonyPatch(typeof(GrabbableObject), "GrabItem")] [HarmonyPostfix] private static void GrabItem_Postfix(GrabbableObject __instance) { try { if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsServer || !((NetworkBehaviour)__instance).IsSpawned) { return; } if (__instance is Y4NGZWeaponBase y4NGZWeaponBase) { Y4NGZWeaponNet.RegisterHandlers(); y4NGZWeaponBase.PublishAuthoritativeStateFromServer(); return; } Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); ShotgunItem val = (((Object)(object)component != (Object)null) ? component.Shotgun : null); if (!((Object)(object)val == (Object)null) && component.Config != null && component.Config.FireMode != WeaponFireMode.ContinuousStream) { Y4NGZWeaponNet.RegisterHandlers(); Y4NGZWeaponNet.PublishState(((NetworkBehaviour)__instance).NetworkObjectId, val.shellsLoaded, val.safetyOn, val.isReloading, authoritative: true); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Grab-time magazine sync failed safely: " + ex.Message)); } } } [HarmonyPatch(typeof(ShotgunItem), "SetControlTipsForItem")] [HarmonyPrefix] private static void SetControlTipsForItem_Prefix(ShotgunItem __instance) { try { if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent() != (Object)null) { WeaponReloadInput.ApplyReloadTooltips(((GrabbableObject)__instance).itemProperties?.toolTips); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Reload control-tip refresh failed safely: " + ex.Message)); } } } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] [HarmonyPostfix] private static void ShootGun_Postfix(ShotgunItem __instance) { try { Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); WeaponConfig weaponConfig = (((Object)(object)component != (Object)null) ? component.Config : null); bool num = weaponConfig != null && (weaponConfig.FireMode == WeaponFireMode.LobbedProjectile || weaponConfig.FireMode == WeaponFireMode.ContinuousStream); PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!num && (Object)(object)((GrabbableObject)__instance).playerHeldBy != (Object)null && (Object)(object)((GrabbableObject)__instance).playerHeldBy == (Object)(object)val) { CrosshairSignals.RecordCommittedLocalShot(); } if ((Object)(object)component != (Object)null) { component.OnFired(((GrabbableObject)__instance).playerHeldBy); } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons] Recoil postfix threw: {arg}"); } } } [HarmonyPatch(typeof(ShotgunItem), "EquipItem")] [HarmonyPostfix] private static void EquipItem_Postfix(ShotgunItem __instance) { try { WeaponSoundRegistry.ApplyToInstance(__instance); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] Weapon sound equip apply failed safely: " + ex.Message)); } } try { Y4NGZWeaponItem component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || component.Config == null || !((NetworkBehaviour)__instance).IsOwner) { return; } int num = ((Plugin.WeaponsDevGrantShells != null) ? Plugin.WeaponsDevGrantShells.Value : 0); if (component.Config.AmmoType == WeaponAmmoType.Fuel && num > 0) { num = Math.Max(num, 200); } if (AmmoReserve.TryDevGrantOnce(component.Config.AmmoType, num)) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[Y4NGZWeapons] Dev-granted {num} rounds ({component.Config.AmmoType}) on equip (reserve was empty; once per ammo family per save)."); } } } catch (Exception arg) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)$"[Y4NGZWeapons] EquipItem dev-grant postfix threw: {arg}"); } } } [HarmonyPatch(typeof(GameNetworkManager), "Start")] [HarmonyPostfix] private static void GameNetworkManagerStart_Postfix() { try { WeaponRegistry.TryRegisterAll(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons] Weapon registration on GameNetworkManager.Start threw: {arg}"); } } try { NativeWeaponRegistry.TryRegisterAll(); } catch (Exception arg2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)$"[Y4NGZNative] Registration on GameNetworkManager.Start threw safely: {arg2}"); } } try { AmmoPickupRegistry.TryRegisterAll(); } catch (Exception arg3) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)$"[Y4NGZAmmo] Registration on GameNetworkManager.Start threw safely: {arg3}"); } } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)("[Y4NGZWeapons] pre-host registration pass: " + $"native={NativeWeaponRegistry.RegisteredCount} " + $"ammo={AmmoPickupRegistry.RegisteredCount} clones={WeaponRegistry.RegisteredCount}")); } } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] private static void StartOfRoundAwake_Postfix(StartOfRound __instance) { try { WeaponRegistry.TryRegisterAll(); NativeWeaponRegistry.TryRegisterAll(); NativeWeaponRegistry.TryApplyWeaponAudio(); WeaponRegistry.DisableConflictingItems(); AmmoReserve.Reload(); WeaponFirstPersonAnimation.PreloadPacks(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[Y4NGZWeapons] Weapon registration on StartOfRound.Awake threw: {arg}"); } } try { AmmoPickupRegistry.TryRegisterAll(); } catch (Exception arg2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)$"[Y4NGZAmmo] Registration on StartOfRound.Awake threw safely: {arg2}"); } } } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] private static void ConnectClientToPlayerObject_Postfix() { Y4NGZWeaponNet.RegisterHandlers(); FlamethrowerStreamDriver.RegisterNetworkHandlers(); } internal static void OnRoundStarted() { Y4NGZWeaponNet.RegisterHandlers(); WeaponMuzzleFlash.StopAll(); WeaponImpactEffects.StopAll(); WeaponBulletHoleDecals.StopAll(); WeaponImpactAudio.StopAll(); WeaponImpactAudio.Prewarm(); WeaponVfxDiagnostics.Reset(); } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static void EndOfGame_Postfix() { WeaponMuzzleFlash.StopAll(); WeaponImpactEffects.StopAll(); WeaponBulletHoleDecals.StopAll(); WeaponImpactAudio.StopAll(); } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] [HarmonyPostfix] private static void Disconnect_Postfix() { Y4NGZWeaponNet.Reset(); WeaponMuzzleFlash.StopAll(); WeaponImpactEffects.StopAll(); WeaponBulletHoleDecals.StopAll(); WeaponImpactAudio.StopAll(); } } } namespace Y4NGZUpgrades.HUD { internal static class AmmoCounterHud { private static readonly Vector2 Anchor = new Vector2(1f, 0f); private const float Right = 28f; private const float Bottom = 28f; private const float Width = 250f; private const float Height = 72f; private const float HeaderFontSize = 16f; private const float FontSize = 31f; private const float TickInterval = 0.1f; private static GameObject _canvasObject; private static RectTransform _root; private static Image _rule; private static TextMeshProUGUI _header; private static TextMeshProUGUI _text; private static TMP_FontAsset _fontCache; private static float _nextTickAt; private static int _lastMagazine = int.MinValue; private static int _lastReserve = int.MinValue; private static Color _lastAccent; private static Vector2 _motionOffset; private static bool _motionSubscribed; private static bool _shown; internal static void Tick() { //IL_00c8: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < _nextTickAt) { return; } _nextTickAt = Time.unscaledTime + 0.1f; if (!ArmoryUiStyle.GameplayUiVisible) { SetPresentationVisible(visible: false); return; } SetPresentationVisible(visible: true); PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController ?? StartOfRound.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || val.isPlayerDead) { Hide(); return; } if (!TryResolveHeldWeaponAmmo(val, out var magazine, out var reserve)) { Hide(); return; } EnsureCounter(); if (!((Object)(object)_text == (Object)null)) { Show(); if (_lastMagazine != magazine || _lastReserve != reserve) { _lastMagazine = magazine; _lastReserve = reserve; ((TMP_Text)_text).SetText("{0:0} / {1:0}", (float)magazine, (float)reserve); } Color currentAccentColor = ArmoryUiStyle.CurrentAccentColor; if (_lastAccent != currentAccentColor) { _lastAccent = currentAccentColor; ApplyTheme(); } } } internal static void RefreshTheme() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) _lastAccent = ArmoryUiStyle.CurrentAccentColor; ApplyTheme(); } internal static void RequestImmediateRefresh() { _nextTickAt = 0f; } internal static void SetPresentationVisible(bool visible) { bool flag = (Object)(object)_canvasObject != (Object)null && _canvasObject.activeSelf != visible; if (flag) { _canvasObject.SetActive(visible); } if (!visible) { Hide(); } else if (flag) { _nextTickAt = 0f; } } private static void ApplyRootPosition() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null)) { _root.anchoredPosition = new Vector2(-28f + _motionOffset.x, 28f + _motionOffset.y); } } private static void OnHudMotionSampled(Vector2 offset) { //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) _motionOffset = offset; ApplyRootPosition(); } private static bool TryResolveHeldWeaponAmmo(PlayerControllerB player, out int magazine, out int reserve) { magazine = 0; reserve = 0; GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer; if ((Object)(object)currentlyHeldObjectServer == (Object)null || currentlyHeldObjectServer.isPocketed) { return false; } if (currentlyHeldObjectServer is Y4NGZWeaponBase { Config: var config } y4NGZWeaponBase) { if (config == null) { return false; } magazine = y4NGZWeaponBase.Magazine; reserve = AmmoReserve.Get(config.AmmoType); return true; } Y4NGZWeaponItem component = ((Component)currentlyHeldObjectServer).GetComponent(); if ((Object)(object)component != (Object)null && component.Config != null && (Object)(object)component.Shotgun != (Object)null) { magazine = component.Shotgun.shellsLoaded; reserve = AmmoReserve.Get(component.Config.AmmoType); return true; } return false; } private static void Hide() { _shown = false; _lastMagazine = int.MinValue; _lastReserve = int.MinValue; if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf) { ((Component)_root).gameObject.SetActive(false); } } private static void Show() { if (!((Object)(object)_root == (Object)null)) { if (!((Component)_root).gameObject.activeSelf) { ((Component)_root).gameObject.SetActive(true); } if (!_shown) { _shown = true; ApplyRootPosition(); } } } private static void EnsureCounter() { //IL_00d0: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_text != (Object)null)) { if (!_motionSubscribed) { ArmoryUiStyle.SubscribeHudMotion(OnHudMotionSampled); _motionSubscribed = true; } if ((Object)(object)_canvasObject == (Object)null) { _canvasObject = new GameObject("Y4NGZUpgrades_AmmoCounterCanvas"); Object.DontDestroyOnLoad((Object)(object)_canvasObject); Canvas obj = _canvasObject.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 104; CanvasScaler obj2 = _canvasObject.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.matchWidthOrHeight = 1f; _canvasObject.SetActive(ArmoryUiStyle.GameplayUiVisible); } GameObject val = new GameObject("AmmoCounter", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(_canvasObject.transform, false); _root = val.GetComponent(); _root.anchorMin = Anchor; _root.anchorMax = Anchor; _root.pivot = Anchor; _root.sizeDelta = new Vector2(250f, 72f); _root.anchoredPosition = new Vector2(-28f, 28f); _rule = CreateRule(_root); GameObject val2 = new GameObject("Header", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent((Transform)(object)_root, false); _header = val2.AddComponent(); GameObject val3 = new GameObject("Rounds", new Type[1] { typeof(RectTransform) }); val3.transform.SetParent((Transform)(object)_root, false); _text = val3.AddComponent(); TMP_FontAsset val4 = ResolveVanillaFont(); if ((Object)(object)val4 != (Object)null) { ((TMP_Text)_header).font = val4; ((TMP_Text)_text).font = val4; } ((TMP_Text)_header).text = "AMMO"; ((TMP_Text)_header).fontSize = 16f; ((TMP_Text)_header).fontStyle = (FontStyles)0; ((TMP_Text)_header).alignment = (TextAlignmentOptions)260; ((TMP_Text)_header).enableWordWrapping = false; ((Graphic)_header).raycastTarget = false; RectTransform rectTransform = ((TMP_Text)_header).rectTransform; rectTransform.anchorMin = new Vector2(0f, 1f); rectTransform.anchorMax = new Vector2(1f, 1f); rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.anchoredPosition = new Vector2(-4f, -2f); rectTransform.sizeDelta = new Vector2(-12f, 20f); ((TMP_Text)_text).fontSize = 31f; ((TMP_Text)_text).fontStyle = (FontStyles)0; ((TMP_Text)_text).alignment = (TextAlignmentOptions)516; ((TMP_Text)_text).characterSpacing = 0f; ((TMP_Text)_text).lineSpacing = 0f; ((TMP_Text)_text).enableAutoSizing = false; ((TMP_Text)_text).enableWordWrapping = false; ((TMP_Text)_text).overflowMode = (TextOverflowModes)0; ((Graphic)_text).raycastTarget = false; RectTransform rectTransform2 = ((TMP_Text)_text).rectTransform; rectTransform2.anchorMin = Vector2.zero; rectTransform2.anchorMax = Vector2.one; rectTransform2.pivot = new Vector2(0.5f, 0.5f); rectTransform2.offsetMin = new Vector2(10f, 8f); rectTransform2.offsetMax = new Vector2(-6f, -18f); _lastAccent = ArmoryUiStyle.CurrentAccentColor; ApplyTheme(); ((Component)_root).gameObject.SetActive(false); } } private static Image CreateRule(RectTransform parent) { //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_0050: 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) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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) GameObject val = new GameObject("Rule", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); RectTransform component = val.GetComponent(); ((Transform)component).SetParent((Transform)(object)parent, false); component.anchorMin = new Vector2(1f, 0f); component.anchorMax = new Vector2(1f, 0f); component.pivot = new Vector2(1f, 0.5f); component.anchoredPosition = new Vector2(-4f, 4f); component.sizeDelta = new Vector2(132f, 2f); Image component2 = val.GetComponent(); ((Graphic)component2).raycastTarget = false; return component2; } private static void ApplyTheme() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) Color currentAccentColor = ArmoryUiStyle.CurrentAccentColor; if ((Object)(object)_header != (Object)null) { ((Graphic)_header).color = currentAccentColor; } if ((Object)(object)_text != (Object)null) { ((Graphic)_text).color = currentAccentColor; } if ((Object)(object)_rule != (Object)null) { Color borderColor = ArmoryUiStyle.BorderColor; borderColor.a = 0.72f; ((Graphic)_rule).color = borderColor; } } private static TMP_FontAsset ResolveVanillaFont() { if ((Object)(object)_fontCache != (Object)null) { return _fontCache; } HUDManager instance = HUDManager.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.clockNumber != (Object)null && (Object)(object)((TMP_Text)instance.clockNumber).font != (Object)null) { _fontCache = ((TMP_Text)instance.clockNumber).font; } return _fontCache; } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] internal static class AmmoCounterHudTickPatch { [HarmonyPostfix] private static void PostPlayerUpdate(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance?.localPlayerController)) { AmmoCounterHud.Tick(); } } } } namespace Y4NGZUpgrades.Interactive.Feedback { internal static class CombatItemClassifier { private struct ItemClassification { public bool Aimed; public bool Melee; public bool Interactive; public ReticleShape Shape; public WeaponConfig WeaponConfig; } private static readonly Dictionary ClassificationCache = new Dictionary(); internal static bool IsAimedWeapon(GrabbableObject held) { if ((Object)(object)held != (Object)null) { return GetClassification(held).Aimed; } return false; } internal static bool IsMeleeWeapon(GrabbableObject held) { if ((Object)(object)held != (Object)null) { return GetClassification(held).Melee; } return false; } internal static bool IsInteractiveHeldItem(GrabbableObject held) { if ((Object)(object)held != (Object)null) { return GetClassification(held).Interactive; } return false; } internal static ReticleShape ResolveReticleShape(GrabbableObject held, out WeaponConfig weaponConfig) { if ((Object)(object)held == (Object)null) { weaponConfig = null; return ReticleShape.None; } ItemClassification classification = GetClassification(held); weaponConfig = classification.WeaponConfig; return classification.Shape; } internal static void ClearCache() { ClassificationCache.Clear(); } internal static bool IsLikelyLocalAimedWeaponHit(PlayerControllerB playerWhoHit) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)playerWhoHit == (Object)(object)val) { return true; } if ((Object)(object)playerWhoHit == (Object)null) { return IsAimedWeapon(val.currentlyHeldObjectServer); } return false; } internal static string GetHeldItemDebugName(PlayerControllerB player) { GrabbableObject val = (((Object)(object)player != (Object)null) ? player.currentlyHeldObjectServer : null); if ((Object)(object)val == (Object)null) { return string.Empty; } Item itemProperties = val.itemProperties; if ((Object)(object)itemProperties != (Object)null && !string.IsNullOrWhiteSpace(itemProperties.itemName)) { return itemProperties.itemName; } return ((Object)val).name ?? string.Empty; } private static string BuildItemHaystack(GrabbableObject held) { Item itemProperties = held.itemProperties; return (((object)held).GetType().FullName + " " + ((object)held).GetType().Name + " " + ((Object)held).name + " " + (((Object)(object)itemProperties != (Object)null) ? itemProperties.itemName : string.Empty) + " " + (((Object)(object)itemProperties != (Object)null) ? ((Object)itemProperties).name : string.Empty)).ToLowerInvariant(); } private static ItemClassification GetClassification(GrabbableObject held) { int instanceID = ((Object)held).GetInstanceID(); if (ClassificationCache.TryGetValue(instanceID, out var value)) { return value; } ItemClassification itemClassification = Classify(held); ClassificationCache[instanceID] = itemClassification; return itemClassification; } private static ItemClassification Classify(GrabbableObject held) { Item itemProperties = held.itemProperties; if (held is Y4NGZWeaponBase y4NGZWeaponBase) { return ClassifyConfiguredWeapon(y4NGZWeaponBase.Config); } Y4NGZWeaponItem component = ((Component)held).GetComponent(); if ((Object)(object)component != (Object)null) { return ClassifyConfiguredWeapon(component.Config); } if (held is ShotgunItem) { return new ItemClassification { Aimed = true, Interactive = true, Shape = ReticleShape.Shotgun }; } string value = BuildItemHaystack(held); if (string.IsNullOrWhiteSpace(value)) { return new ItemClassification { Interactive = ((Object)(object)itemProperties == (Object)null || (itemProperties.toolTips != null && itemProperties.toolTips.Length != 0)) }; } bool flag = ContainsAny(value, "shovel", "knife", "kitchen knife", "stop sign", "stopsign", "yield sign", "yieldsign", "melee", "hammer", "axe") || ContainsWholeToken(value, "bat"); bool flag2 = !flag && !ContainsAny(value, "spray", "flashlight", "walkie", "boombox", "jetpack", "key", "lockpicker") && ContainsAny(value, "flamethrower", "flame thrower", "flame_thrower", "flame-thrower", "shotgun", "gun", "pistol", "revolver", "rifle", "smg", "launcher", "rocket", "cannon", "blaster", "laser", "zap", "taser", "stun gun", "crossbow", "bow", "dart"); if (!flag2 && (Object)(object)itemProperties != (Object)null && itemProperties.isDefensiveWeapon && itemProperties.itemIsTrigger && itemProperties.twoHanded) { flag2 = true; } if (!flag && (Object)(object)itemProperties != (Object)null && itemProperties.isDefensiveWeapon && !flag2) { flag = true; } bool interactive = (Object)(object)itemProperties == (Object)null || itemProperties.itemIsTrigger || itemProperties.holdButtonUse || itemProperties.canBeInspected || (itemProperties.toolTips != null && itemProperties.toolTips.Length != 0); return new ItemClassification { Aimed = flag2, Melee = flag, Interactive = interactive, Shape = (flag2 ? ReticleShape.Pistol : ReticleShape.None) }; } private static ItemClassification ClassifyConfiguredWeapon(WeaponConfig config) { return new ItemClassification { Aimed = true, Melee = false, Interactive = true, WeaponConfig = config, Shape = ((config == null) ? ReticleShape.Pistol : ShapeForFamily(config.CrosshairFamily)) }; } private static ReticleShape ShapeForFamily(WeaponCrosshairFamily family) { return family switch { WeaponCrosshairFamily.Marksman => ReticleShape.Marksman, WeaponCrosshairFamily.Pistol => ReticleShape.Pistol, WeaponCrosshairFamily.ShotgunBracket => ReticleShape.Shotgun, WeaponCrosshairFamily.Stream => ReticleShape.Stream, WeaponCrosshairFamily.Projectile => ReticleShape.Projectile, _ => ReticleShape.Rifle, }; } private static bool ContainsAny(string value, params string[] needles) { for (int i = 0; i < needles.Length; i++) { if (value.Contains(needles[i])) { return true; } } return false; } private static bool ContainsWholeToken(string value, string token) { int num = 0; while (num <= value.Length - token.Length) { int num2 = value.IndexOf(token, num, StringComparison.Ordinal); if (num2 < 0) { return false; } int num3 = num2 + token.Length; bool num4 = num2 == 0 || !char.IsLetterOrDigit(value[num2 - 1]); bool flag = num3 == value.Length || !char.IsLetterOrDigit(value[num3]); if (num4 && flag) { return true; } num = num2 + 1; } return false; } } internal sealed class CombatReticleHud : MonoBehaviour { private readonly struct FamilySizing { internal readonly float MinFraction; internal readonly float MaxFraction; internal readonly float CosmeticFraction; internal FamilySizing(float minFraction, float maxFraction, float cosmeticFraction) { MinFraction = minFraction; MaxFraction = maxFraction; CosmeticFraction = cosmeticFraction; } } private const float HitPulseDuration = 0.16f; private const float FirePulseDuration = 0.18f; private const float TargetAcquireDuration = 0.12f; private const float CrosshairFadeSpeed = 12f; private const float InteractionFadeSpeed = 10f; private const float HitBarLength = 18f; private const float HitBarThickness = 3f; private const float FirePulseGapBoost = 6f; private const float StreamOpenGapBoost = 3f; private const float DefaultVerticalFov = 66f; private const float WeaponAlpha = 0.78f; private const float ActiveTargetAlpha = 0.9f; private const float DisabledTargetAlpha = 0.4f; private static readonly Color ReticleColor = new Color(0.9f, 0.97f, 1f, 1f); private static readonly Color HitMarkerColor = new Color(1f, 0.84f, 0.34f, 1f); private static CombatReticleHud _instance; private static Sprite _pixelSprite; private static AudioClip _hitTickClip; private static AudioClip _interactTickClip; private RectTransform _root; private RectTransform _segmentRoot; private RectTransform[] _segmentRects; private Image[] _segmentImages; private ReticleSegment[] _segments; private CanvasGroup _hitGroup; private RectTransform[] _hitBars; private ReticleShape _weaponShape; private ReticleShape _targetShape; private WeaponConfig _weaponConfig; private bool _weaponRequested; private bool _targetRequested; private float _weaponAlpha; private float _targetAlpha; private float _lastWeaponRadius = 10f; private float _hitPulseStart = -999f; private float _targetAcquireStart = -999f; private float _lastInteractTickTime = -999f; private int _lastActiveTargetKey; private PlayerControllerB _capturedCursorPlayer; private Image _capturedCursorIcon; private bool _capturedCursorEnabled; private Sprite _capturedCursorSprite; private Color _capturedCursorColor; private bool _cursorSuppressed; private VanillaCursorIconMode _appliedCursorMode = VanillaCursorIconMode.Show; public static void UpdateWeaponState(PlayerControllerB player) { if (!ArmoryUiStyle.GameplayUiVisible || !CanPresentForPlayer(player)) { if ((Object)(object)_instance != (Object)null) { _instance.SetWeaponState(ReticleShape.None, null); } return; } ReticleShape reticleShape = ReticleShape.None; WeaponConfig weaponConfig = null; if (Plugin.CombatFeedbackEnabled != null && Plugin.CombatFeedbackEnabled.Value && Plugin.CombatFeedbackWeaponCrosshairEnabled != null && Plugin.CombatFeedbackWeaponCrosshairEnabled.Value) { reticleShape = CombatItemClassifier.ResolveReticleShape(player.currentlyHeldObjectServer, out weaponConfig); } if (reticleShape != ReticleShape.None || !((Object)(object)_instance == (Object)null)) { CombatReticleHud combatReticleHud = Ensure(); if ((Object)(object)combatReticleHud != (Object)null) { combatReticleHud.SetWeaponState(reticleShape, weaponConfig); } } } internal static void CaptureInteractionState(PlayerControllerB player) { //IL_0054: 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_0059: 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_0147: Unknown result type (might be due to invalid IL or missing references) if (!ArmoryUiStyle.GameplayUiVisible || !CanPresentForPlayer(player)) { SetPresentationVisible(visible: false); return; } Image cursorIcon = player.cursorIcon; bool flag = (Object)(object)cursorIcon != (Object)null && ((Behaviour)cursorIcon).enabled; Sprite val = (((Object)(object)cursorIcon != (Object)null) ? cursorIcon.sprite : null); Color color = (((Object)(object)cursorIcon != (Object)null) ? ((Graphic)cursorIcon).color : Color.white); if ((Object)(object)_instance != (Object)null) { _instance.CaptureVanillaCursorState(player, cursorIcon, flag, val, color); } if (Plugin.WorldFeedbackEnabled == null || !Plugin.WorldFeedbackEnabled.Value || Plugin.WorldFeedbackInteractionReticleEnabled == null || !Plugin.WorldFeedbackInteractionReticleEnabled.Value || !flag || (Object)(object)cursorIcon == (Object)null) { if ((Object)(object)_instance != (Object)null) { _instance.ClearTargetAndRestoreCursor(); } return; } ReticleShape shape = (((Object)(object)val == (Object)(object)player.grabItemIcon) ? ReticleShape.Pickup : ((!((Object)(object)player.hoveringOverTrigger != (Object)null) || player.hoveringOverTrigger.interactable) ? ReticleShape.Interactable : ReticleShape.DisabledInteractable)); CombatReticleHud combatReticleHud = Ensure(); if ((Object)(object)combatReticleHud == (Object)null) { if ((Object)(object)_instance != (Object)null) { _instance.ClearTargetAndRestoreCursor(); } return; } if ((Object)(object)combatReticleHud._capturedCursorIcon != (Object)(object)cursorIcon || (Object)(object)combatReticleHud._capturedCursorPlayer != (Object)(object)player) { combatReticleHud.CaptureVanillaCursorState(player, cursorIcon, flag, val, color); } int targetKey = ComputeTargetKey(player, val, shape); if (combatReticleHud.SetTargetState(shape, targetKey)) { combatReticleHud.PrimeTargetGeometry(); } combatReticleHud.ApplyVanillaCursorMode(); } public static void PulseHit() { if (!ArmoryUiStyle.GameplayUiVisible || Plugin.CombatFeedbackEnabled == null || !Plugin.CombatFeedbackEnabled.Value || Plugin.CombatFeedbackHitMarkerEnabled == null || !Plugin.CombatFeedbackHitMarkerEnabled.Value) { return; } CombatReticleHud combatReticleHud = Ensure(); if (!((Object)(object)combatReticleHud == (Object)null)) { combatReticleHud._hitPulseStart = Time.unscaledTime; ((Component)combatReticleHud).gameObject.SetActive(true); combatReticleHud.UpdateVisuals(); if (Plugin.CombatFeedbackHitSoundEnabled != null && Plugin.CombatFeedbackHitSoundEnabled.Value && (Object)(object)HUDManager.Instance != (Object)null && (Object)(object)HUDManager.Instance.UIAudio != (Object)null) { HUDManager.Instance.UIAudio.PlayOneShot(GetHitTickClip(), 0.35f); } } } public static void DestroyInstance() { if (!((Object)(object)_instance == (Object)null)) { _instance.ClearPresentationAndRestoreCursor(); Object.Destroy((Object)(object)((Component)_instance).gameObject); _instance = null; } } internal static void SetPresentationVisible(bool visible) { if (!((Object)(object)_instance == (Object)null || visible)) { _instance.ClearPresentationAndRestoreCursor(); } } private static bool CanPresentForPlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null || !((NetworkBehaviour)player).IsOwner || !player.isPlayerControlled) { return false; } if ((Object)(object)player != (Object)(object)GameNetworkManager.Instance?.localPlayerController || player.isPlayerDead) { return false; } if ((Object)(object)player.quickMenuManager != (Object)null && player.quickMenuManager.isMenuOpen) { return false; } if (!player.isTypingChat && !player.inTerminalMenu) { return !player.inSpecialMenu; } return false; } private static int ComputeTargetKey(PlayerControllerB player, Sprite sprite, ReticleShape shape) { int num = (int)(shape + 1) * 486187739; if ((Object)(object)sprite != (Object)null) { num = (num * 397) ^ ((Object)sprite).GetInstanceID(); } if (shape != ReticleShape.Pickup && (Object)(object)player.hoveringOverTrigger != (Object)null) { num = (num * 397) ^ ((Object)player.hoveringOverTrigger).GetInstanceID(); } else if ((Object)(object)player.cursorTip != (Object)null && !string.IsNullOrEmpty(((TMP_Text)player.cursorTip).text)) { num = (num * 397) ^ ((TMP_Text)player.cursorTip).text.GetHashCode(); } if (num == 0) { return 1; } return num; } private static CombatReticleHud Ensure() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_instance != (Object)null) { return _instance; } if ((Object)(object)HUDManager.Instance == (Object)null || (Object)(object)HUDManager.Instance.playerScreenTexture == (Object)null) { return null; } Canvas canvas = ((Graphic)HUDManager.Instance.playerScreenTexture).canvas; if ((Object)(object)canvas == (Object)null) { return null; } GameObject val = new GameObject("Y4NGZ_CombatReticleHud"); val.transform.SetParent(((Component)canvas).transform, false); CombatReticleHud combatReticleHud = val.AddComponent(); combatReticleHud.Build(); _instance = combatReticleHud; return combatReticleHud; } private void Build() { //IL_0021: 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_0055: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) _root = ((Component)this).gameObject.AddComponent(); _root.anchorMin = new Vector2(0.5f, 0.5f); _root.anchorMax = new Vector2(0.5f, 0.5f); _root.pivot = new Vector2(0.5f, 0.5f); _root.sizeDelta = new Vector2(800f, 800f); _root.anchoredPosition = Vector2.zero; GameObject val = new GameObject("ReticleSegments"); val.transform.SetParent(((Component)this).transform, false); _segmentRoot = val.AddComponent(); ConfigureCenteredRoot(_segmentRoot); _segments = new ReticleSegment[16]; _segmentRects = (RectTransform[])(object)new RectTransform[16]; _segmentImages = (Image[])(object)new Image[16]; for (int i = 0; i < 16; i++) { AddPooledSegment(i); } _hitGroup = CreateGroup("HitMarker"); _hitBars = (RectTransform[])(object)new RectTransform[4]; AddHitBar(0, new Vector2(-9f, 9f), 45f); AddHitBar(1, new Vector2(9f, 9f), -45f); AddHitBar(2, new Vector2(-9f, -9f), -45f); AddHitBar(3, new Vector2(9f, -9f), 45f); _hitGroup.alpha = 0f; ((Component)this).gameObject.SetActive(false); } private static void ConfigureCenteredRoot(RectTransform rect) { //IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = new Vector2(0.5f, 0.5f); rect.anchorMax = new Vector2(0.5f, 0.5f); rect.pivot = new Vector2(0.5f, 0.5f); rect.sizeDelta = new Vector2(800f, 800f); rect.anchoredPosition = Vector2.zero; } private CanvasGroup CreateGroup(string name) { //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) //IL_0018: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(((Component)this).transform, false); ConfigureCenteredRoot(val.AddComponent()); CanvasGroup obj = val.AddComponent(); obj.blocksRaycasts = false; obj.interactable = false; return obj; } private void AddPooledSegment(int index) { //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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_008d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ReticleSegment_" + index.ToString("00")); val.transform.SetParent((Transform)(object)_segmentRoot, false); RectTransform val2 = val.AddComponent(); val2.anchorMin = new Vector2(0.5f, 0.5f); val2.anchorMax = new Vector2(0.5f, 0.5f); val2.pivot = new Vector2(0.5f, 0.5f); Image val3 = val.AddComponent(); val3.sprite = GetPixelSprite(); ((Graphic)val3).raycastTarget = false; ((Graphic)val3).color = ReticleColor; _segmentRects[index] = val2; _segmentImages[index] = val3; val.SetActive(false); } private void AddHitBar(int index, Vector2 position, float rotation) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HitBar"); val.transform.SetParent(((Component)_hitGroup).transform, false); RectTransform val2 = val.AddComponent(); val2.anchorMin = new Vector2(0.5f, 0.5f); val2.anchorMax = new Vector2(0.5f, 0.5f); val2.pivot = new Vector2(0.5f, 0.5f); val2.sizeDelta = new Vector2(18f, 3f); val2.anchoredPosition = position; ((Transform)val2).localRotation = Quaternion.Euler(0f, 0f, rotation); Image obj = val.AddComponent(); obj.sprite = GetPixelSprite(); ((Graphic)obj).raycastTarget = false; ((Graphic)obj).color = HitMarkerColor; _hitBars[index] = val2; } private void SetWeaponState(ReticleShape shape, WeaponConfig config) { _weaponRequested = shape != ReticleShape.None; if (_weaponRequested) { _weaponShape = shape; _weaponConfig = config; ((Component)this).gameObject.SetActive(true); } } private bool SetTargetState(ReticleShape shape, int targetKey) { bool targetRequested = _targetRequested; ReticleShape targetShape = _targetShape; int lastActiveTargetKey = _lastActiveTargetKey; _targetRequested = shape == ReticleShape.Pickup || shape == ReticleShape.Interactable || shape == ReticleShape.DisabledInteractable; if (!_targetRequested) { ClearTargetAndRestoreCursor(); return false; } _targetShape = shape; bool flag = shape != ReticleShape.DisabledInteractable; if (flag && targetKey != _lastActiveTargetKey) { _targetAcquireStart = Time.unscaledTime; if (Time.unscaledTime - _lastInteractTickTime > 0.12f) { _lastInteractTickTime = Time.unscaledTime; PlayInteractTick(); } } _lastActiveTargetKey = (flag ? targetKey : 0); ((Component)this).gameObject.SetActive(true); if (targetRequested && targetShape == shape) { if (flag) { return lastActiveTargetKey != targetKey; } return false; } return true; } private void PrimeTargetGeometry() { _targetAlpha = ((_targetShape == ReticleShape.DisabledInteractable) ? 0.4f : 0.9f); ((Component)this).transform.SetAsLastSibling(); DrawCombinedGeometry(_lastWeaponRadius, 1f); } private void ClearTargetAndRestoreCursor() { _targetRequested = false; _lastActiveTargetKey = 0; RestoreVanillaCursor(); } private void CaptureVanillaCursorState(PlayerControllerB player, Image cursorIcon, bool enabled, Sprite sprite, Color color) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) if ((Object)(object)_capturedCursorIcon != (Object)(object)cursorIcon || (Object)(object)_capturedCursorPlayer != (Object)(object)player) { RestoreVanillaCursor(); _capturedCursorPlayer = player; _capturedCursorIcon = cursorIcon; _capturedCursorColor = color; } else if (!_cursorSuppressed || _appliedCursorMode != VanillaCursorIconMode.Fade || color.a > 0.001f) { _capturedCursorColor = color; } _capturedCursorEnabled = enabled; _capturedCursorSprite = sprite; } private void ApplyVanillaCursorMode() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (!_targetRequested || (Object)(object)_capturedCursorIcon == (Object)null) { RestoreVanillaCursor(); return; } VanillaCursorIconMode vanillaCursorIconMode = ((Plugin.CrosshairVanillaCursorIcon != null) ? Plugin.CrosshairVanillaCursorIcon.Value : VanillaCursorIconMode.Hide); if (vanillaCursorIconMode == VanillaCursorIconMode.Show) { RestoreVanillaCursor(); return; } if (_cursorSuppressed && _appliedCursorMode != vanillaCursorIconMode) { RestoreVanillaCursor(); } if (vanillaCursorIconMode == VanillaCursorIconMode.Hide) { ((Behaviour)_capturedCursorIcon).enabled = false; } else { Color capturedCursorColor = _capturedCursorColor; capturedCursorColor.a = 0f; ((Graphic)_capturedCursorIcon).color = capturedCursorColor; } _appliedCursorMode = vanillaCursorIconMode; _cursorSuppressed = true; } private void RestoreVanillaCursor() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!_cursorSuppressed) { return; } if ((Object)(object)_capturedCursorIcon != (Object)null) { if (_appliedCursorMode == VanillaCursorIconMode.Hide) { ((Behaviour)_capturedCursorIcon).enabled = _capturedCursorEnabled; } else if (_appliedCursorMode == VanillaCursorIconMode.Fade) { ((Graphic)_capturedCursorIcon).color = _capturedCursorColor; } } _cursorSuppressed = false; _appliedCursorMode = VanillaCursorIconMode.Show; } private void ReleaseCursorCapture() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) RestoreVanillaCursor(); _capturedCursorPlayer = null; _capturedCursorIcon = null; _capturedCursorEnabled = false; _capturedCursorSprite = null; _capturedCursorColor = Color.white; } private void ClearPresentationAndRestoreCursor() { _weaponRequested = false; _targetRequested = false; _weaponShape = ReticleShape.None; _targetShape = ReticleShape.None; _weaponConfig = null; _weaponAlpha = 0f; _targetAlpha = 0f; _lastActiveTargetKey = 0; ReleaseCursorCapture(); if ((Object)(object)_hitGroup != (Object)null) { _hitGroup.alpha = 0f; } HideAllSegments(); ((Component)this).gameObject.SetActive(false); } private void Update() { UpdateVisuals(); } private void UpdateVisuals() { //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) if (!ArmoryUiStyle.GameplayUiVisible) { SetPresentationVisible(visible: false); return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (_capturedCursorPlayer != null && (Object)(object)_capturedCursorPlayer != (Object)(object)val) { _targetRequested = false; _lastActiveTargetKey = 0; ReleaseCursorCapture(); } ((Component)this).transform.SetAsLastSibling(); float unscaledTime = Time.unscaledTime; bool flag = Plugin.CombatFeedbackWeaponFirePulseEnabled != null && Plugin.CombatFeedbackWeaponFirePulseEnabled.Value; float num = 0f; if (_weaponRequested && flag) { float num2 = unscaledTime - CrosshairSignals.LatestCommittedLocalShotTime; if (num2 >= 0f && num2 < 0.18f) { num = 1f - num2 / 0.18f; } } float num3 = Mathf.Clamp01((unscaledTime - _hitPulseStart) / 0.16f); float num4 = ((num3 < 1f) ? (1f - num3 * num3) : 0f); bool flag2 = _weaponRequested && _weaponShape == ReticleShape.Stream && flag && CrosshairSignals.ContinuousStreamActive; float num5 = (_weaponRequested ? Mathf.Clamp01(0.78f + num * 0.22f + (flag2 ? 0.1f : 0f)) : 0f); _weaponAlpha = Mathf.MoveTowards(_weaponAlpha, num5, Time.unscaledDeltaTime * 12f); float num6 = 0f; if (_targetRequested) { num6 = ((_targetShape == ReticleShape.DisabledInteractable) ? 0.4f : 0.9f); } _targetAlpha = Mathf.MoveTowards(_targetAlpha, num6, Time.unscaledDeltaTime * 10f); if ((Object)(object)_hitGroup != (Object)null) { _hitGroup.alpha = num4; ((Component)_hitGroup).transform.localScale = Vector3.one * Mathf.Lerp(0.9f, 1.34f, (num3 < 1f) ? num3 : 1f); } if (_weaponRequested) { _lastWeaponRadius = ResolveCrosshairInnerRadius(num, num4, flag2); } float targetScale = 1f; if (_targetRequested && _targetShape != ReticleShape.DisabledInteractable) { float num7 = Mathf.Clamp01((unscaledTime - _targetAcquireStart) / 0.12f); targetScale = Mathf.Lerp(1f, 1.25f, num7); } DrawCombinedGeometry(_lastWeaponRadius, targetScale); if (!_weaponRequested && _weaponAlpha <= 0.001f) { _weaponShape = ReticleShape.None; _weaponConfig = null; } if (!_targetRequested && _targetAlpha <= 0.001f) { _targetShape = ReticleShape.None; } if (!(_weaponAlpha > 0.001f) && !(_targetAlpha > 0.001f) && !(num4 > 0.01f)) { ((Component)this).gameObject.SetActive(false); } } private void DrawCombinedGeometry(float weaponRadius, float targetScale) { int num = 0; if (_weaponShape != ReticleShape.None && _weaponAlpha > 0.001f) { num = ReticleGeometry.BuildWeapon(_weaponShape, weaponRadius, _segments, 0); } int num2 = 0; if (_targetShape != ReticleShape.None && _targetAlpha > 0.001f) { num2 = ReticleGeometry.BuildTarget(_targetShape, targetScale, _segments, num); } int num3 = num + num2; for (int i = 0; i < num3; i++) { float alpha = ((i < num) ? _weaponAlpha : _targetAlpha); ApplySegment(i, _segments[i], alpha); } for (int j = num3; j < 16; j++) { if (((Component)_segmentRects[j]).gameObject.activeSelf) { ((Component)_segmentRects[j]).gameObject.SetActive(false); } } } private void ApplySegment(int index, ReticleSegment segment, float alpha) { //IL_0016: 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_0048: 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_0057: 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) RectTransform val = _segmentRects[index]; val.anchoredPosition = new Vector2(segment.X, segment.Y); val.sizeDelta = new Vector2(segment.Width, segment.Height); ((Transform)val).localRotation = Quaternion.Euler(0f, 0f, segment.RotationDegrees); Color reticleColor = ReticleColor; reticleColor.a = Mathf.Clamp01(alpha * segment.Opacity); ((Graphic)_segmentImages[index]).color = reticleColor; if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } } private void HideAllSegments() { if (_segmentRects == null) { return; } for (int i = 0; i < _segmentRects.Length; i++) { if ((Object)(object)_segmentRects[i] != (Object)null && ((Component)_segmentRects[i]).gameObject.activeSelf) { ((Component)_segmentRects[i]).gameObject.SetActive(false); } } } private float ResolveCrosshairInnerRadius(float fireStrength, float hitStrength, bool streamOpen) { float num = ResolveConeViewRadius(); if (num < 0f) { num = ResolveFixedFamilyRadius(_weaponShape); } float num2 = Mathf.Max(fireStrength, hitStrength * 0.75f); num += 6f * num2; if (streamOpen) { num += 3f; } return num; } private static float ResolveFixedFamilyRadius(ReticleShape shape) { return shape switch { ReticleShape.Marksman => 9f, ReticleShape.Rifle => 12f, ReticleShape.Shotgun => 16f, ReticleShape.Stream => 14f, _ => 10f, }; } private float ResolveConeViewRadius() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (!_weaponRequested || _weaponConfig == null) { return -1f; } if (Plugin.CrosshairAccuracySizingEnabled != null && !Plugin.CrosshairAccuracySizingEnabled.Value) { return -1f; } if ((Object)(object)HUDManager.Instance == (Object)null || (Object)(object)HUDManager.Instance.playerScreenTexture == (Object)null) { return -1f; } RectTransform rectTransform = ((Graphic)HUDManager.Instance.playerScreenTexture).rectTransform; if ((Object)(object)rectTransform == (Object)null) { return -1f; } Rect rect = rectTransform.rect; float height = ((Rect)(ref rect)).height; if (height <= 0f) { return -1f; } FamilySizing familySizing = SizingFor(_weaponConfig.CrosshairFamily); bool flag = Plugin.CrosshairHonestSizingOnly == null || Plugin.CrosshairHonestSizingOnly.Value; if (_weaponConfig.SpreadIsCosmetic && flag) { return height * familySizing.CosmeticFraction; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; Camera val2 = (((Object)(object)val != (Object)null) ? val.gameplayCamera : null); float verticalFovDeg = (((Object)(object)val2 != (Object)null) ? val2.fieldOfView : 66f); return Mathf.Clamp(WeaponAccuracy.HalfAngleToViewRadius(WeaponAccuracy.Sample(val, _weaponConfig), height, verticalFovDeg), height * familySizing.MinFraction, height * familySizing.MaxFraction); } private static FamilySizing SizingFor(WeaponCrosshairFamily family) { return family switch { WeaponCrosshairFamily.Marksman => new FamilySizing(0.0056f, 0.1f, 0.012f), WeaponCrosshairFamily.Pistol => new FamilySizing(0.0056f, 0.12f, 0.017f), WeaponCrosshairFamily.ShotgunBracket => new FamilySizing(0.02f, 0.34f, 0.15f), WeaponCrosshairFamily.Stream => new FamilySizing(0.02f, 0.34f, 0.06f), WeaponCrosshairFamily.Projectile => new FamilySizing(0.0056f, 0.12f, 0.018f), _ => new FamilySizing(0.0056f, 0.14f, 0.027f), }; } private static Sprite GetPixelSprite() { //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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown if ((Object)(object)_pixelSprite != (Object)null) { return _pixelSprite; } Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); val.SetPixel(0, 0, Color.white); val.Apply(); ((Object)val).hideFlags = (HideFlags)61; _pixelSprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f)); ((Object)_pixelSprite).hideFlags = (HideFlags)61; return _pixelSprite; } private static AudioClip GetHitTickClip() { if ((Object)(object)_hitTickClip != (Object)null) { return _hitTickClip; } int num = Mathf.CeilToInt(1543.5f); float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i / 44100f; float num3 = Mathf.Exp((0f - num2) * 95f); float num4 = Mathf.Sin(MathF.PI * 3700f * num2); array[i] = num4 * num3 * 0.55f; } _hitTickClip = AudioClip.Create("Y4NGZ_CombatHitTick", num, 1, 44100, false); _hitTickClip.SetData(array, 0); ((Object)_hitTickClip).hideFlags = (HideFlags)61; return _hitTickClip; } private static void PlayInteractTick() { if (!((Object)(object)HUDManager.Instance == (Object)null) && !((Object)(object)HUDManager.Instance.UIAudio == (Object)null)) { HUDManager.Instance.UIAudio.PlayOneShot(GetInteractTickClip(), 0.045f); } } private static AudioClip GetInteractTickClip() { if ((Object)(object)_interactTickClip != (Object)null) { return _interactTickClip; } int num = Mathf.CeilToInt(1234.8f); float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i / 44100f; float num3 = Mathf.Exp((0f - num2) * 125f); float num4 = Mathf.Sin(MathF.PI * 2500f * num2); array[i] = num4 * num3 * 0.28f; } _interactTickClip = AudioClip.Create("Y4NGZ_InteractTargetTick", num, 1, 44100, false); _interactTickClip.SetData(array, 0); ((Object)_interactTickClip).hideFlags = (HideFlags)61; return _interactTickClip; } } internal static class CrosshairSignals { private const float NoShotTime = -999f; private static float _latestCommittedLocalShotTime = -999f; private static bool _continuousStreamActive; internal static float LatestCommittedLocalShotTime => _latestCommittedLocalShotTime; internal static bool ContinuousStreamActive => _continuousStreamActive; internal static void RecordCommittedLocalShot() { _latestCommittedLocalShotTime = Time.unscaledTime; } internal static void SetContinuousStream(bool active) { _continuousStreamActive = active; if (active) { RecordCommittedLocalShot(); } } internal static void Reset() { _latestCommittedLocalShotTime = -999f; _continuousStreamActive = false; } } internal enum ReticleShape { None, Pistol, Rifle, Marksman, Shotgun, Stream, Projectile, Pickup, Interactable, DisabledInteractable } internal readonly struct ReticleSegment { internal readonly float X; internal readonly float Y; internal readonly float Width; internal readonly float Height; internal readonly float RotationDegrees; internal readonly float Opacity; internal ReticleSegment(float x, float y, float width, float height, float rotationDegrees = 0f, float opacity = 1f) { X = x; Y = y; Width = width; Height = height; RotationDegrees = rotationDegrees; Opacity = opacity; } } internal static class ReticleGeometry { internal const int PoolSize = 16; internal const int MaximumCombinedSegments = 15; private const float WeaponThickness = 2f; private const float FineThickness = 1.5f; private const float DiagonalHalfProjection = 0.35355338f; internal static int BuildWeapon(ReticleShape shape, float innerRadius, ReticleSegment[] destination, int startIndex) { float num = ((innerRadius > 0f) ? innerRadius : 0f); switch (shape) { case ReticleShape.Pistol: RequireCapacity(destination, startIndex, 5); WriteCardinalTicks(destination, startIndex, num, 8f, 2f, includeTop: true); destination[startIndex + 4] = new ReticleSegment(0f, 0f, 3f, 3f); return 5; case ReticleShape.Rifle: RequireCapacity(destination, startIndex, 4); WriteCardinalTicks(destination, startIndex, num + 3f, 13f, 2f, includeTop: true); return 4; case ReticleShape.Marksman: RequireCapacity(destination, startIndex, 4); WriteThreeWayTicks(destination, startIndex, num, 6f, 1.5f); destination[startIndex + 3] = new ReticleSegment(0f, 0f, 2.5f, 2.5f); return 4; case ReticleShape.Shotgun: RequireCapacity(destination, startIndex, 6); WriteShotgunBrackets(destination, startIndex, num); return 6; case ReticleShape.Stream: RequireCapacity(destination, startIndex, 4); WriteStreamChevrons(destination, startIndex, num); return 4; case ReticleShape.Projectile: RequireCapacity(destination, startIndex, 5); WriteProjectilePip(destination, startIndex, num); return 5; default: return 0; } } internal static int BuildTarget(ReticleShape shape, float scale, ReticleSegment[] destination, int startIndex) { float num = ((scale > 0f) ? scale : 1f); switch (shape) { case ReticleShape.Pickup: RequireCapacity(destination, startIndex, 5); WritePickupDiamond(destination, startIndex, num); return 5; case ReticleShape.Interactable: RequireCapacity(destination, startIndex, 9); WriteCornerBrackets(destination, startIndex, num, 0.82f); destination[startIndex + 8] = new ReticleSegment(0f, 0f, 3f * num, 3f * num); return 9; case ReticleShape.DisabledInteractable: RequireCapacity(destination, startIndex, 8); WriteCornerBrackets(destination, startIndex, num, 1f); return 8; default: return 0; } } private static void WriteCardinalTicks(ReticleSegment[] destination, int startIndex, float radius, float length, float thickness, bool includeTop) { float num = radius + length * 0.5f; int num2 = startIndex; if (includeTop) { destination[num2++] = new ReticleSegment(0f, num, thickness, length); } destination[num2++] = new ReticleSegment(0f, 0f - num, thickness, length); destination[num2++] = new ReticleSegment(0f - num, 0f, length, thickness); destination[num2] = new ReticleSegment(num, 0f, length, thickness); } private static void WriteThreeWayTicks(ReticleSegment[] destination, int startIndex, float radius, float length, float thickness) { float num = radius + length * 0.5f; destination[startIndex] = new ReticleSegment(0f - num, 0f, length, thickness); destination[startIndex + 1] = new ReticleSegment(num, 0f, length, thickness); destination[startIndex + 2] = new ReticleSegment(0f, 0f - num, thickness, length); } private static void WriteShotgunBrackets(ReticleSegment[] destination, int startIndex, float radius) { float num = Max(6f, radius * 0.22f); float num2 = Max(14f, radius * 0.55f); float num3 = radius + num - 1f; float num4 = radius + num * 0.5f; float num5 = num2 * 0.5f - 1f; destination[startIndex] = new ReticleSegment(0f - num3, 0f, 2f, num2); destination[startIndex + 1] = new ReticleSegment(0f - num4, num5, num, 2f); destination[startIndex + 2] = new ReticleSegment(0f - num4, 0f - num5, num, 2f); destination[startIndex + 3] = new ReticleSegment(num3, 0f, 2f, num2); destination[startIndex + 4] = new ReticleSegment(num4, num5, num, 2f); destination[startIndex + 5] = new ReticleSegment(num4, 0f - num5, num, 2f); } private static void WriteStreamChevrons(ReticleSegment[] destination, int startIndex, float radius) { float num = Clamp(radius * 0.45f, 8f, 22f); float num2 = num * 0.35355338f; destination[startIndex] = new ReticleSegment(0f - radius - num2, num2, num, 2f, -45f); destination[startIndex + 1] = new ReticleSegment(0f - radius - num2, 0f - num2, num, 2f, 45f); destination[startIndex + 2] = new ReticleSegment(radius + num2, num2, num, 2f, 45f); destination[startIndex + 3] = new ReticleSegment(radius + num2, 0f - num2, num, 2f, -45f); } private static void WriteProjectilePip(ReticleSegment[] destination, int startIndex, float radius) { destination[startIndex] = new ReticleSegment(0f, 3.5f, 7f, 1.5f); destination[startIndex + 1] = new ReticleSegment(0f, -3.5f, 7f, 1.5f); destination[startIndex + 2] = new ReticleSegment(-3.5f, 0f, 1.5f, 7f); destination[startIndex + 3] = new ReticleSegment(3.5f, 0f, 1.5f, 7f); destination[startIndex + 4] = new ReticleSegment(0f, 0f - (Max(radius, 6.5f) + 2f), 7f, 1.5f); } private static void WritePickupDiamond(ReticleSegment[] destination, int startIndex, float scale) { float num = 4f * scale; float width = num * 1.4142135f; float num2 = num * 0.5f; float height = 1.5f * scale; destination[startIndex] = new ReticleSegment(0f - num2, num2, width, height, 45f, 0.82f); destination[startIndex + 1] = new ReticleSegment(num2, num2, width, height, -45f, 0.82f); destination[startIndex + 2] = new ReticleSegment(0f - num2, 0f - num2, width, height, -45f, 0.82f); destination[startIndex + 3] = new ReticleSegment(num2, 0f - num2, width, height, 45f, 0.82f); destination[startIndex + 4] = new ReticleSegment(0f, 0f, 2.5f * scale, 2.5f * scale); } private static void WriteCornerBrackets(ReticleSegment[] destination, int startIndex, float scale, float opacity) { float num = 7f * scale; float num2 = 4f * scale; float num3 = num2 * 0.5f; float num4 = 1.5f * scale; destination[startIndex] = new ReticleSegment(0f - num + num3, num, num2, num4, 0f, opacity); destination[startIndex + 1] = new ReticleSegment(0f - num, num - num3, num4, num2, 0f, opacity); destination[startIndex + 2] = new ReticleSegment(num - num3, num, num2, num4, 0f, opacity); destination[startIndex + 3] = new ReticleSegment(num, num - num3, num4, num2, 0f, opacity); destination[startIndex + 4] = new ReticleSegment(0f - num + num3, 0f - num, num2, num4, 0f, opacity); destination[startIndex + 5] = new ReticleSegment(0f - num, 0f - num + num3, num4, num2, 0f, opacity); destination[startIndex + 6] = new ReticleSegment(num - num3, 0f - num, num2, num4, 0f, opacity); destination[startIndex + 7] = new ReticleSegment(num, 0f - num + num3, num4, num2, 0f, opacity); } private static void RequireCapacity(ReticleSegment[] destination, int startIndex, int required) { if (destination == null) { throw new ArgumentNullException("destination"); } if (startIndex < 0 || startIndex > destination.Length - required) { throw new ArgumentOutOfRangeException("startIndex"); } } private static float Max(float left, float right) { if (!(left > right)) { return right; } return left; } private static float Clamp(float value, float minimum, float maximum) { if (value < minimum) { return minimum; } if (!(value > maximum)) { return value; } return maximum; } } } namespace BetterArmory { internal static class ArmoryConfigMigration { private const string LogPrefix = "[Y4NGZArmoryConfig]"; internal const string UpgradesConfigFileName = "com.y4ngz.upgrades.cfg"; internal static readonly (string NewSection, string NewKey, string OldSection, string OldKey)[] RenamedKeys = new(string, string, string, string)[9] { ("Ammo: Shotgun Shells", "Rounds Per Box", "Ammo", "Rounds Per Shotgun Shells Box"), ("Ammo: Small Caliber Rounds", "Rounds Per Box", "Ammo", "Rounds Per .357 Box"), ("Ammo: Heavy Caliber Rounds", "Rounds Per Box", "Ammo", "Rounds Per Heavy Caliber Box"), ("Ammo: Fuel", "Rounds Per Box", "Ammo", "Rounds Per Fuel Tank"), ("Ammo: Shotgun Shells", "Interior Spawn Rarity", "Ammo", "Scrap Pool Rarity Shotgun Shells"), ("Ammo: Small Caliber Rounds", "Interior Spawn Rarity", "Ammo", "Scrap Pool Rarity .357 Rounds"), ("Ammo: Heavy Caliber Rounds", "Interior Spawn Rarity", "Ammo", "Scrap Pool Rarity Heavy Caliber Rounds"), ("Ammo: Fuel", "Interior Spawn Rarity", "Ammo", "Scrap Pool Rarity Fuel Tank"), ("Ammo: Grenades", "Interior Spawn Rarity", "Ammo", "Scrap Pool Rarity Grenade") }; internal static readonly (string SectionPrefix, string Key)[] RetiredKeys = new(string, string)[2] { ("Weapon: ", "Damage Near"), ("Weapon: ", "Damage Far") }; private static Dictionary _ownFileBeforeBind; private static Dictionary _upgradesFile; internal static void CaptureSources(string ownConfigPath) { _ownFileBeforeBind = ReadCfg(ownConfigPath); string path = null; try { path = Path.Combine(Paths.ConfigPath, "com.y4ngz.upgrades.cfg"); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZArmoryConfig] Could not resolve the BepInEx config path: " + ex.Message)); } } _upgradesFile = ReadCfg(path); } internal static int Apply(ConfigFile config) { if (config == null || _ownFileBeforeBind == null) { return 0; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); (string, string, string, string)[] renamedKeys = RenamedKeys; for (int i = 0; i < renamedKeys.Length; i++) { (string, string, string, string) tuple = renamedKeys[i]; dictionary[Compose(tuple.Item1, tuple.Item2)] = (tuple.Item3, tuple.Item4); } int num = 0; foreach (KeyValuePair item in config) { ConfigDefinition key = item.Key; ConfigEntryBase value = item.Value; if (key == (ConfigDefinition)null || value == null) { continue; } string key2 = Compose(key.Section, key.Key); if (_ownFileBeforeBind.ContainsKey(key2)) { continue; } if (!dictionary.TryGetValue(key2, out var value2)) { value2 = (key.Section, key.Key); } string key3 = Compose(value2.Item1, value2.Item2); if ((!_ownFileBeforeBind.TryGetValue(key3, out var value3) && (_upgradesFile == null || !_upgradesFile.TryGetValue(key3, out value3))) || string.IsNullOrEmpty(value3)) { continue; } try { value.BoxedValue = TomlTypeConverter.ConvertToValue(value3, value.SettingType); num++; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZArmoryConfig] Migrated [" + value2.Item1 + "] " + value2.Item2 + " = " + value3 + " -> [" + key.Section + "] " + key.Key + ".")); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Y4NGZArmoryConfig] Could not migrate [" + value2.Item1 + "] " + value2.Item2 + " (value '" + value3 + "') into [" + key.Section + "] " + key.Key + "; the default stands: " + ex.Message)); } } } if (num > 0) { try { config.Save(); } catch (Exception ex2) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZArmoryConfig] Migration could not save the config file: " + ex2.Message)); } } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogMessage((object)(string.Format("{0} Carried over {1} setting(s) from the pre-split config. ", "[Y4NGZArmoryConfig]", num) + "Nothing was removed from com.y4ngz.upgrades.cfg.")); } } return num; } internal static int PruneRetiredKeys(ConfigFile config) { if (config == null || RetiredKeys.Length == 0) { return 0; } try { if (!(typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(config) is Dictionary { Count: not 0 } dictionary)) { return 0; } List list = new List(); foreach (ConfigDefinition key in dictionary.Keys) { if (key == (ConfigDefinition)null) { continue; } (string, string)[] retiredKeys = RetiredKeys; for (int i = 0; i < retiredKeys.Length; i++) { (string, string) tuple = retiredKeys[i]; if (string.Equals(key.Key, tuple.Item2, StringComparison.Ordinal) && key.Section != null && key.Section.StartsWith(tuple.Item1, StringComparison.Ordinal)) { list.Add(key); break; } } } if (list.Count == 0) { return 0; } foreach (ConfigDefinition item in list) { dictionary.Remove(item); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Y4NGZArmoryConfig] Removed retired setting [" + item.Section + "] " + item.Key + "; it no longer means anything and its replacement is bound alongside it.")); } } config.Save(); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogMessage((object)string.Format("{0} Pruned {1} retired setting(s) from the config file.", "[Y4NGZArmoryConfig]", list.Count)); } return list.Count; } catch (Exception ex) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Y4NGZArmoryConfig] Could not prune retired settings; the stale lines stay in the file and are otherwise inert: " + ex.Message)); } return 0; } } private static string Compose(string section, string key) { return section + "::" + key; } private static Dictionary ReadCfg(string path) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(path)) { return dictionary; } try { if (!File.Exists(path)) { return dictionary; } string section = string.Empty; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text[0] == '#') { continue; } if (text[0] == '[' && text[text.Length - 1] == ']') { section = text.Substring(1, text.Length - 2).Trim(); continue; } int num = text.IndexOf('='); if (num > 0) { string text2 = text.Substring(0, num).Trim(); string value = text.Substring(num + 1).Trim(); if (text2.Length != 0) { dictionary[Compose(section, text2)] = value; } } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Y4NGZArmoryConfig] Could not read '" + path + "' for migration: " + ex.Message)); } } return dictionary; } } public class ArmoryKeybinds : LcInputActions { [InputAction("/r", Name = "[Y4NGZ] Reload Weapon")] public InputAction ReloadWeapon { get; set; } } internal static class ArmoryPersistentRunner { private sealed class ArmoryPersistentRunnerBehaviour : MonoBehaviour { private const float VisibilitySampleInterval = 0.25f; private float _nextVisibilitySampleAt; private bool _lastVisible = true; private void Update() { SampleGameplayUiVisibility(); } private void SampleGameplayUiVisibility() { if (!(Time.unscaledTime < _nextVisibilitySampleAt)) { _nextVisibilitySampleAt = Time.unscaledTime + 0.25f; bool gameplayUiVisible = ArmoryUiStyle.GameplayUiVisible; if (gameplayUiVisible != _lastVisible) { _lastVisible = gameplayUiVisible; AmmoCounterHud.SetPresentationVisible(gameplayUiVisible); CombatReticleHud.SetPresentationVisible(gameplayUiVisible); } } } } private static ArmoryPersistentRunnerBehaviour _runner; internal static GameObject Host { get { Ensure(); if (!((Object)(object)_runner != (Object)null)) { return null; } return ((Component)_runner).gameObject; } } internal static void Ensure() { //IL_0013: 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_001e: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_runner != (Object)null)) { GameObject val = new GameObject("BetterArmoryPersistentRunner"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; _runner = val.AddComponent(); } } internal static Coroutine Run(IEnumerator routine) { if (routine == null) { return null; } Ensure(); if (!((Object)(object)_runner != (Object)null)) { return null; } return ((MonoBehaviour)_runner).StartCoroutine(routine); } internal static void Stop(Coroutine routine) { if (routine != null && !((Object)(object)_runner == (Object)null)) { ((MonoBehaviour)_runner).StopCoroutine(routine); } } } [HarmonyPatch] internal static class ArmoryRoundLifecycle { private static bool _startedThisRound; [HarmonyPatch(typeof(StartOfRound), "openingDoorsSequence")] [HarmonyPostfix] private static void PostOpeningDoorsSequence() { if (!_startedThisRound) { _startedThisRound = true; ArmoryPersistentRunner.Ensure(); Dispatch(GrenadeLauncherPatches.OnRoundStarted, "GrenadeLauncherPatches"); Dispatch(WeaponPatches.OnRoundStarted, "WeaponPatches"); Dispatch(ArmoryCombatReticlePatch.OnRoundStarted, "ArmoryCombatReticlePatch"); } } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static void PostEndOfGame() { _startedThisRound = false; } [HarmonyPatch(typeof(StartOfRound), "SetShipReadyToLand")] [HarmonyPostfix] private static void PostSetShipReadyToLand() { _startedThisRound = false; } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] [HarmonyPostfix] private static void PostDisconnect() { _startedThisRound = false; } private static void Dispatch(Action handler, string label) { try { handler(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"[BetterArmory] RoundStarted subscriber {label} threw: {arg}"); } } } } internal static class ArmorySaveBridge { private const string TypeName = "Y4NGZUpgrades.SaveIdentityApi"; private static bool _resolved; private static MethodInfo _getCurrentKey; private static MethodInfo _getCurrentExistingOrSlotKey; private static bool _installed; internal static bool TryGetCurrentKey(out string key) { key = Invoke(ResolveGetCurrentKey()); return !string.IsNullOrWhiteSpace(key); } internal static bool TryGetCurrentExistingOrSlotKey(out string key) { key = Invoke(ResolveGetCurrentExistingOrSlotKey()); return !string.IsNullOrWhiteSpace(key); } internal static void Install() { if (_installed) { return; } _installed = true; Type type = ResolveType(); if (type == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[BetterArmory] Y4NGZUpgrades' SaveIdentityApi was not found. The ammo reserve will not follow save re-points or deletions this session."); } } else { Subscribe(type, "StoresRepointed", typeof(Action), "OnStoresRepointed"); Subscribe(type, "SaveKeyDeleted", typeof(Action), "OnSaveKeyDeleted"); } } private static void OnStoresRepointed() { try { AmmoReserve.Reload(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BetterArmory] ammo-reserve re-point failed: " + ex.Message)); } } } private static void OnSaveKeyDeleted(string key) { try { AmmoReserve.DeleteForKey(key); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BetterArmory] ammo-reserve delete failed: " + ex.Message)); } } } private static void Subscribe(Type type, string eventName, Type handlerType, string methodName) { try { EventInfo eventInfo = type.GetEvent(eventName, BindingFlags.Static | BindingFlags.Public); if (eventInfo == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BetterArmory] SaveIdentityApi." + eventName + " is missing.")); } } else { MethodInfo method = typeof(ArmorySaveBridge).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic); eventInfo.AddEventHandler(null, Delegate.CreateDelegate(handlerType, method)); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[BetterArmory] Could not subscribe " + eventName + ": " + ex.Message)); } } } private static string Invoke(MethodInfo method) { if (method == null) { return null; } try { return method.Invoke(null, null) as string; } catch { return null; } } private static MethodInfo ResolveGetCurrentKey() { Resolve(); return _getCurrentKey; } private static MethodInfo ResolveGetCurrentExistingOrSlotKey() { Resolve(); return _getCurrentExistingOrSlotKey; } private static void Resolve() { if (!_resolved) { _resolved = true; Type type = ResolveType(); if (!(type == null)) { _getCurrentKey = type.GetMethod("GetCurrentSaveKey", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); _getCurrentExistingOrSlotKey = type.GetMethod("GetCurrentExistingOrSlotSaveKey", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); } } } private static Type ResolveType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType("Y4NGZUpgrades.SaveIdentityApi", throwOnError: false); if (type != null) { return type; } } catch { } } return null; } } [HarmonyPatch] internal static class ArmoryCombatReticlePatch { private const float FeedbackSampleInterval = 0.05f; private static float _nextFeedbackSampleTime; [HarmonyPatch(typeof(EnemyAI), "HitEnemyOnLocalClient")] [HarmonyPostfix] private static void PostHitEnemyOnLocalClient(EnemyAI __instance, int force, PlayerControllerB playerWhoHit) { if (!((Object)(object)__instance == (Object)null) && force != 0 && Plugin.CombatFeedbackEnabled.Value) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null) && (CombatItemClassifier.IsLikelyLocalAimedWeaponHit(playerWhoHit) || !((Object)(object)playerWhoHit != (Object)(object)val))) { CombatReticleHud.PulseHit(); } } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] private static void PostPlayerLateUpdate(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance?.localPlayerController)) { CombatReticleHud.CaptureInteractionState(__instance); if (!(Time.unscaledTime < _nextFeedbackSampleTime)) { _nextFeedbackSampleTime = Time.unscaledTime + 0.05f; CombatReticleHud.UpdateWeaponState(__instance); } } } internal static void OnRoundStarted() { Reset(); } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static void PostEndOfGame() { Reset(); } private static void Reset() { _nextFeedbackSampleTime = 0f; CombatItemClassifier.ClearCache(); CrosshairSignals.Reset(); CombatReticleHud.DestroyInstance(); } internal static void Shutdown() { CombatReticleHud.DestroyInstance(); CombatItemClassifier.ClearCache(); CrosshairSignals.Reset(); } } public enum VanillaCursorIconMode { Hide, Fade, Show } [BepInPlugin("com.y4ngz.betterarmory", "BetterArmory", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.y4ngz.betterarmory"; public const string Name = "BetterArmory"; public const string Version = "0.1.0"; public static ConfigEntry WeaponsDevSpawnEnabled; public static ConfigEntry WeaponsDevAutoSpawn; public static ConfigEntry WeaponsDevSpawnKey; public static ConfigEntry WeaponsHsVisualPos; public static ConfigEntry WeaponsHsVisualRot; public static ConfigEntry WeaponsHsVisualScale; public static ConfigEntry WeaponsRevolverVisualPos; public static ConfigEntry WeaponsRevolverVisualRot; public static ConfigEntry WeaponsRevolverVisualScale; public static ConfigEntry WeaponsDevGrantShells; public static ConfigEntry WeaponsDisableConflictingItems; public static ConfigEntry WeaponsCameraResidueJanitor; public static ConfigEntry WeaponsHeavyShotgunFpAnimation; public static ConfigEntry WeaponsFpLeftHandGunAnchor; public static ConfigEntry WeaponsFpPropPosDelta; public static ConfigEntry WeaponsFpPropRotDelta; public static ConfigEntry WeaponsFpPropScaleMult; public static ConfigEntry WeaponsVfxDiagnostics; public static ConfigEntry WeaponsFingerCurlDiagnostics; public static ConfigEntry WeaponsVfxIsolationKey; public static ConfigEntry WeaponsAimProbeZeroSpread; public static ConfigEntry WeaponsLegacyEnemySpherecast; public static ConfigEntry WeaponsImpactAudioEnabled; public static ConfigEntry WeaponsImpactAudioVolume; public static ConfigEntry WeaponsMuzzleFlashScale; public static ConfigEntry WeaponsImpactScale; public static ConfigEntry WeaponsBulletHoleDecalsEnabled; public static ConfigEntry WeaponsBulletHoleDecalScale; public static ConfigEntry WeaponsBulletHoleDecalLifetime; public static ConfigEntry WeaponsBulletHoleDecalFadeSeconds; public static ConfigEntry WeaponsBulletHoleDecalMaxLive; public static ConfigEntry WeaponsAuthoredAudioGain; public static ConfigEntry WeaponsNativeSuppressVanillaBodyTriggers; public static ConfigEntry WeaponsCreatureBlood; public static ConfigEntry WeaponsCreatureBloodBurstScale; public static ConfigEntry WeaponsCreatureBloodFleshTint; public static ConfigEntry WeaponsCreatureBloodInsectTint; public static ConfigEntry AmmoDevSpawnKeyEnabled; public static ConfigEntry FlameStreamAttackSeconds; public static ConfigEntry FlameStreamReleaseSeconds; public static ConfigEntry FlameStreamLightIntensity; public static ConfigEntry FlameStreamLightEnabled; public static ConfigEntry ScorchMarksEnabled; public static ConfigEntry ScorchMarkDwellSeconds; public static ConfigEntry ScorchMarkSpacing; public static ConfigEntry ScorchMarkPoolSize; public static ConfigEntry ScorchMarkForceReceiveDecals; public static ConfigEntry GroundFireEnabled; public static ConfigEntry GroundFireDwellSeconds; public static ConfigEntry GroundFireRadius; public static ConfigEntry GroundFireDurationSeconds; public static ConfigEntry GroundFireMaxPatches; public static ConfigEntry CombatFeedbackEnabled; public static ConfigEntry CombatFeedbackHitMarkerEnabled; public static ConfigEntry CombatFeedbackHitSoundEnabled; public static ConfigEntry CombatFeedbackWeaponCrosshairEnabled; public static ConfigEntry CombatFeedbackWeaponFirePulseEnabled; public static ConfigEntry CrosshairAccuracySizingEnabled; public static ConfigEntry CrosshairHonestSizingOnly; public static ConfigEntry CrosshairVanillaCursorIcon; public static ConfigEntry WorldFeedbackEnabled; public static ConfigEntry WorldFeedbackInteractionReticleEnabled; private static readonly Dictionary Pos, ConfigEntry Rot, ConfigEntry Scale)> NativeWeaponVisualEntries = new Dictionary, ConfigEntry, ConfigEntry)>(); private static bool _applicationQuitting; private Harmony _harmony; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ArmoryKeybinds Keybinds { get; private set; } internal static Vector3 WeaponsFpPropPosDeltaValue { get; private set; } = Vector3.zero; internal static Vector3 WeaponsFpPropRotDeltaValue { get; private set; } = Vector3.zero; internal static float WeaponsFpPropScaleMultValue { get; private set; } = 1f; internal static bool TryGetNativeWeaponVisualConfig(string configId, out ConfigEntry pos, out ConfigEntry rot, out ConfigEntry scale) { if (configId != null && NativeWeaponVisualEntries.TryGetValue(configId, out (ConfigEntry, ConfigEntry, ConfigEntry) value)) { (pos, rot, scale) = value; return true; } pos = null; rot = null; scale = null; return false; } private void Awake() { //IL_00fc: 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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Application.quitting += OnApplicationQuitting; ArmoryConfigMigration.CaptureSources(((BaseUnityPlugin)this).Config.ConfigFilePath); BindConfig(); ArmoryContentConfig.ApplyToCatalogs(); ArmoryPersistentRunner.Ensure(); if (Keybinds == null) { Keybinds = new ArmoryKeybinds(); Keybinds.ReloadWeapon.performed += WeaponReloadInput.OnReloadPerformed; } ArmorySaveBridge.Install(); WeaponDevSpawnHost.Enabled = WeaponsDevSpawnEnabled.Value; WeaponDevSpawnHost.AutoSpawn = WeaponsDevAutoSpawn.Value; Key? val = ParseKey(WeaponsDevSpawnKey.Value); if (val.HasValue) { WeaponDevSpawnHost.SpawnKey = val.Value; } WeaponCreatureBlood.Enabled = WeaponsCreatureBlood.Value; WeaponCreatureBlood.BurstScale = WeaponsCreatureBloodBurstScale.Value; ImpactMaterialCatalog.FleshTint = ToTint(WeaponsCreatureBloodFleshTint.Value, Color.clear); ImpactMaterialCatalog.InsectTint = ToTint(WeaponsCreatureBloodInsectTint.Value, ImpactMaterialCatalog.DefaultInsectTint); WeaponVfxDiagnostics.Enabled = WeaponsVfxDiagnostics.Value; WeaponFirstPersonAnimation.FingerCurlDiagnostics = WeaponsFingerCurlDiagnostics.Value; WeaponVfxDiagnostics.AimProbeZeroSpread = WeaponsAimProbeZeroSpread.Value; WeaponDevSpawnHost.VfxIsolationKey = ParseKey(WeaponsVfxIsolationKey.Value); Y4NGZWeaponBallistics.LegacyEnemySpherecast = WeaponsLegacyEnemySpherecast.Value; WeaponBulletHoleDecals.Configure(WeaponsBulletHoleDecalsEnabled.Value, WeaponsBulletHoleDecalLifetime.Value, WeaponsBulletHoleDecalFadeSeconds.Value, WeaponsBulletHoleDecalMaxLive.Value, WeaponsBulletHoleDecalScale.Value); if (WeaponsLegacyEnemySpherecast.Value) { Log.LogWarning((object)"[Y4NGZWeaponVfx] Legacy Enemy Spherecast is ON: enemy damage ignores the pellet direction and sweeps a 5 m sphere from 10 m behind the shooter (#116). The crosshair does not describe what takes damage while this is on."); } if (WeaponsAimProbeZeroSpread.Value) { Log.LogWarning((object)"[Y4NGZWeaponVfx] Aim Probe Zero Spread is ON: every native weapon fires with a zero-degree cone. Diagnostic only — turn it off for normal play."); } if (WeaponsAimProbeZeroSpread.Value && !WeaponsVfxDiagnostics.Value) { Log.LogWarning((object)"[Y4NGZWeaponVfx] Aim Probe Zero Spread is on but VFX Diagnostics is off, so the probe will not report anything. Enable 'Weapons / VFX Diagnostics' to read the run."); } ApplyWeaponVisualConfig(); ApplyWeaponFpPropConfig(); _harmony = new Harmony("com.y4ngz.betterarmory"); _harmony.PatchAll(typeof(Plugin).Assembly); WeaponRegistry.TryRegisterAll(); try { NativeWeaponRegistry.TryRegisterAll(); } catch (Exception arg) { Log.LogError((object)$"[Y4NGZNative] Registration during plugin Awake threw safely: {arg}"); } try { AmmoPickupRegistry.TryRegisterAll(); } catch (Exception arg2) { Log.LogError((object)$"[Y4NGZAmmo] Registration during plugin Awake threw safely: {arg2}"); } WeaponDevSpawnHost.Ensure(); AmmoPickupDevSpawnHost.Enabled = AmmoDevSpawnKeyEnabled.Value; AmmoPickupDevSpawnHost.Ensure(); Log.LogInfo((object)($"[Y4NGZWeapons] registration pass: native={NativeWeaponRegistry.RegisteredCount} " + $"ammo={AmmoPickupRegistry.RegisteredCount} clones={WeaponRegistry.RegisteredCount}")); Log.LogMessage((object)"BetterArmory 0.1.0 loaded"); } private void OnDestroy() { if (!_applicationQuitting) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[Y4NGZWeapons] The plugin host GameObject was destroyed mid-session (BepInEx [Chainloader] HideManagerGameObject is false). Harmony patches remain ACTIVE and nothing was torn down; gameplay continues normally."); } return; } if (Keybinds != null && Keybinds.ReloadWeapon != null) { Keybinds.ReloadWeapon.performed -= WeaponReloadInput.OnReloadPerformed; } Keybinds = null; ArmoryCombatReticlePatch.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static void OnApplicationQuitting() { _applicationQuitting = true; } private void BindConfig() { FlameStreamAttackSeconds = ((BaseUnityPlugin)this).Config.Bind("Flamethrower Stream", "Attack Seconds", 0.25f, "Seconds the flamethrower stream takes to ramp from idle to full intensity."); FlameStreamReleaseSeconds = ((BaseUnityPlugin)this).Config.Bind("Flamethrower Stream", "Release Seconds", 0.6f, "Seconds the flamethrower stream takes to fade out after the trigger is released."); FlameStreamLightIntensity = ((BaseUnityPlugin)this).Config.Bind("Flamethrower Stream", "Light Intensity", 4.5f, "Point-light intensity used by the flamethrower muzzle light at full stream intensity."); FlameStreamLightEnabled = ((BaseUnityPlugin)this).Config.Bind("Flamethrower Stream", "Light Enabled", true, "Spawn a flickering muzzle light alongside the flamethrower stream."); ScorchMarksEnabled = ((BaseUnityPlugin)this).Config.Bind("Scorch Marks", "Enabled", true, "Leave scorch marks on floors and walls where the flamethrower stream dwells."); ScorchMarkDwellSeconds = ((BaseUnityPlugin)this).Config.Bind("Scorch Marks", "Dwell Seconds", 0.6f, "Seconds the stream must stay on one patch of surface before it leaves a mark."); ScorchMarkSpacing = ((BaseUnityPlugin)this).Config.Bind("Scorch Marks", "Minimum Spacing", 1.2f, "Metres between scorch marks on the same surface. Also the size of the patch the dwell timer charges."); ScorchMarkPoolSize = ((BaseUnityPlugin)this).Config.Bind("Scorch Marks", "Pool Size", 32, "Hard cap on live scorch marks. Past the cap the oldest mark is moved to the newest hit."); ScorchMarkForceReceiveDecals = ((BaseUnityPlugin)this).Config.Bind("Scorch Marks", "Force Surface Decal Reception", true, "Turn HDRP decal reception on for struck surfaces. Only used when the vanilla mark is a decal projector; interior materials ship with reception off."); GroundFireEnabled = ((BaseUnityPlugin)this).Config.Bind("Ground Fire", "Enabled", true, "Leave a burning patch on the floor where the flamethrower stream dwells."); GroundFireDwellSeconds = ((BaseUnityPlugin)this).Config.Bind("Ground Fire", "Dwell Seconds", 1f, "Seconds the stream must stay on one patch of floor before it catches light."); GroundFireRadius = ((BaseUnityPlugin)this).Config.Bind("Ground Fire", "Patch Radius", 1.6f, "Radius in metres of a ground-fire patch. Also the spacing that stops patches stacking."); GroundFireDurationSeconds = ((BaseUnityPlugin)this).Config.Bind("Ground Fire", "Burn Seconds", 5f, "Seconds a ground-fire patch burns before it fades out."); GroundFireMaxPatches = ((BaseUnityPlugin)this).Config.Bind("Ground Fire", "Max Patches", 6, "Hard cap on live ground-fire patches. Spawning past the cap extinguishes the oldest."); WeaponsDevSpawnEnabled = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Dev Spawn Enabled", true, "Dev-only: allow spawning a Heavy Shotgun with a hotkey (host only). Disable for release."); WeaponsDevAutoSpawn = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Dev Auto Spawn", true, "Dev-only: auto-spawn one Heavy Shotgun a few seconds after you gain control while hosting. Disable for release."); WeaponsDevSpawnKey = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Dev Spawn Key", "Home", "Key to dev-spawn a Heavy Shotgun in front of the local player. Use Unity InputSystem Key names."); WeaponsHsVisualPos = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Heavy Shotgun Visual Pos", "0,0,0", "Heavy Shotgun native visual-root position nudge 'x,y,z' on top of its accepted grip mount. Re-read on each spawn."); WeaponsHsVisualRot = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Heavy Shotgun Visual Rot", "0,0,0", "Heavy Shotgun native visual-root euler nudge 'x,y,z' on top of its accepted grip mount. Re-read on each spawn."); WeaponsHsVisualScale = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Heavy Shotgun Visual Scale", 1f, "Heavy Shotgun native visual-root scale multiplier on top of its accepted 1.5523 base scale. Re-read on each spawn."); WeaponsRevolverVisualPos = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Revolver Visual Pos", "0,0,0", "Revolver native visual-root position nudge 'x,y,z' on top of its accepted grip mount. Re-read on each spawn."); WeaponsRevolverVisualRot = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Revolver Visual Rot", "0,0,0", "Revolver native visual-root euler nudge 'x,y,z' on top of its accepted grip mount. Re-read on each spawn."); WeaponsRevolverVisualScale = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Revolver Visual Scale", 1f, "Revolver native visual-root scale multiplier on top of its accepted 1.4427 base scale. Re-read on each spawn."); WeaponsDevGrantShells = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Dev Grant Shells When Empty", 8, "Dev-only: when a dev-spawned gun finds the shotgun-shell reserve empty, top it up to this amount so reload-from-reserve is testable. 0 = off."); WeaponsDisableConflictingItems = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Disable Conflicting Weapon Items", true, "When another mod registers an item with the same name as one of our weapons (e.g. a second 'Heavy Shotgun'), rename it with a [disabled by Y4NGZ] tag and remove it from moon scrap pools so the right gun is unambiguous."); WeaponsCameraResidueJanitor = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Camera Residue Janitor", true, "Heal safe local gameplay-camera yaw/roll residue after recoil and live-body animation sessions. Disable only for camera-writer diagnostics."); WeaponsHeavyShotgunFpAnimation = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Heavy Shotgun FP Animation", true, "Enable the Heavy Shotgun first-person arms and animated prop interaction."); WeaponsFpLeftHandGunAnchor = ((BaseUnityPlugin)this).Config.Bind("Weapons", "FP Left Hand Gun Anchor", true, "Re-anchor the first-person Heavy Shotgun left-hand IK target to the actual gun prop pose each frame."); WeaponsFpPropPosDelta = ((BaseUnityPlugin)this).Config.Bind("Weapons", "FP Prop Pos Delta", "0,0,0", "First-person Heavy Shotgun prop local position delta 'x,y,z' in meters. Re-read on each interaction start."); WeaponsFpPropRotDelta = ((BaseUnityPlugin)this).Config.Bind("Weapons", "FP Prop Rot Delta", "0,0,0", "First-person Heavy Shotgun prop local euler rotation delta 'x,y,z' in degrees. Re-read on each interaction start."); WeaponsFpPropScaleMult = ((BaseUnityPlugin)this).Config.Bind("Weapons", "FP Prop Scale Mult", 1f, "First-person Heavy Shotgun prop local scale multiplier. Re-read on each interaction start."); WeaponsVfxDiagnostics = ((BaseUnityPlugin)this).Config.Bind("Weapons", "VFX Diagnostics", false, "Diagnostic-only: report what the weapon fire path DID — which ItemActivate branch ran, the resolved muzzle position, which bundle the flash prefab came from, and each particle renderer's mesh/material/shader. One line per event per session, never per shot. Off by default; enable only when chasing a missing effect."); WeaponsFingerCurlDiagnostics = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Finger Curl Diagnostics", false, "Diagnostic-only: log the live first-person finger, fingertip, and thumb curl deltas every two seconds while a weapon is held. Off by default; enable only when tuning the hand pose."); WeaponsMuzzleFlashScale = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Muzzle Flash Scale", 1f, "Uniform scale on the muzzle flash effect. The RVFX effects are authored at rifle proportions (5-30 cm particles); raise this if a pistol flash reads too small. Look tuning, no in-game verdict yet."); WeaponsImpactScale = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Impact Burst Scale", 1f, "Uniform scale on the surface impact burst (dust and debris) spawned where a native weapon's shot lands. Authored at rifle proportions in the same RVFX pack as the muzzle flash. Look tuning, no in-game verdict yet."); WeaponsBulletHoleDecalsEnabled = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Bullet Hole Decals", true, "Place fading RVFX mesh-quad bullet holes on world surfaces hit by native Y4NGZ weapons (#85). Players, creatures, and held items are excluded by the shared impact-surface guard."); WeaponsBulletHoleDecalScale = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Bullet Hole Decal Scale", 1f, "Uniform size multiplier on bullet-hole mesh quads. Clamped to 0.1-5.0; 1.0 is the RVFX authored size and remains unverified in game."); WeaponsBulletHoleDecalLifetime = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Bullet Hole Decal Lifetime", 15f, "Seconds a bullet hole remains alive, including its fade. Clamped to 5-120 seconds; lowered from 45 to 15 (#180) because sustained automatic fire saturated the cap with overlapping quads."); WeaponsBulletHoleDecalFadeSeconds = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Bullet Hole Decal Fade Seconds", 2f, "Seconds at the end of each bullet hole's lifetime spent fading through a MaterialPropertyBlock. Clamped between zero and the configured lifetime; creates no material instances. Lowered from 10 to 2 (#180): a fading decal is excluded from the SRP Batcher, so long fades made every live decal its own draw call."); WeaponsBulletHoleDecalMaxLive = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Bullet Hole Decal Max Live", 32, "Global Upgrades-owned bullet-hole cap across every player. Oldest marks retire first; clamped to 8-256 and deliberately separate from the Y4NGZBloodFX blood-decal budget."); NativeWeaponVisualEntries.Clear(); foreach (WeaponConfig item in WeaponCatalog.AllNative()) { if (item.Id == "heavy_shotgun") { NativeWeaponVisualEntries[item.Id] = (WeaponsHsVisualPos, WeaponsHsVisualRot, WeaponsHsVisualScale); } else if (item.Id == "revolver") { NativeWeaponVisualEntries[item.Id] = (WeaponsRevolverVisualPos, WeaponsRevolverVisualRot, WeaponsRevolverVisualScale); } else { NativeWeaponVisualEntries[item.Id] = (((BaseUnityPlugin)this).Config.Bind("Weapons", item.DisplayName + " Visual Pos", "0,0,0", item.DisplayName + " visual-root local position offset 'x,y,z' under the item root. Moves the model AND every landmark derived from it (muzzle, ejection port, sights). Re-read on each spawn."), ((BaseUnityPlugin)this).Config.Bind("Weapons", item.DisplayName + " Visual Rot", "0,0,0", item.DisplayName + " visual-root local euler rotation 'x,y,z'. To calibrate after a mount change, enable VFX Diagnostics, fire once, and paste the logged 'suggestedVisualLocalEuler' here. Re-read on each spawn."), ((BaseUnityPlugin)this).Config.Bind("Weapons", item.DisplayName + " Visual Scale", 1f, item.DisplayName + " visual-root uniform scale, for presenting the dimensionally accurate model at Lethal Company's larger-than-life prop proportions. Landmarks scale with it but the bore direction does not; the grab collider follows on its own. The muzzle flash does NOT: raise 'Muzzle Flash Scale' alongside this one.")); } } WeaponsAuthoredAudioGain = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Authored Audio Gain", 1.6f, "Volume multiplier on AUTHORED weapon clips only — the bundled fire and reload takes. The vanilla shotgun clips that still fill the unauthored slots (dry fire, safety) are already mixed against the game and are deliberately left alone, so raising this does not drift them out of balance. The pack's samples sit quieter than Lethal Company's, which is what this corrects. Above ~2 the louder transients start to clip."); WeaponsNativeSuppressVanillaBodyTriggers = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Native Suppress Vanilla Body Triggers", true, "Stop native Y4NGZ weapons firing vanilla's ShootShotgun/ReloadShotgun/SwitchGunSafety animator parameters into a player body the animation API currently owns. Required by the runtime wiring contract: never fire fallback vanilla triggers into an externally owned custom controller. When no Y4NGZ interaction is active the vanilla triggers still play, because no authored body animation exists to replace them yet (#96)."); WeaponsAimProbeZeroSpread = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Aim Probe Zero Spread", false, "Diagnostic-only (#111): collapse every native weapon's spread cone to zero so the aim probe measures the shot RAY instead of the pattern drawn around it, making its pass criteria geometric identities rather than statistics. This CHANGES BALLISTICS while it is on — in multiplayer, leave it to the host or expect the shooter and everyone else to disagree about where a shot went. Read the 'AIM VERDICT' line in the log. Off by default."); WeaponsImpactAudioEnabled = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Impact Audio Enabled", true, "Play authored-first per-material bullet-impact audio where a round lands, with Lethal Company's footstepSurfaces[i].hitSurfaceSFX as the safe material fallback (#118). Unknown or clipless surfaces use the authored General pool when available. Creature hits are NOT played here: EnemyType.hitBodySFX already fires inside IHittable.Hit."); WeaponsImpactAudioVolume = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Impact Audio Volume", 0.75f, "Volume of authored-first per-surface bullet impacts and their vanilla fallback. Default 0.75; live mix verdict still pending (#118)."); WeaponsLegacyEnemySpherecast = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Legacy Enemy Spherecast", false, "Escape hatch (#116): restore the pre-2026-08-02 enemy damage cast — a 5 metre sphere swept from 10 m BEHIND the shooter along the un-spread aim vector, out to 25 m. That shape damaged every enemy in a roughly 10 m wide, 35 m long capsule regardless of where the bullet actually went, which made the crosshair and the whole accuracy model decorative for damage. Native weapons now resolve enemies per pellet, on the pellet's own direction, within 'EnemyCastRadiusMeters' and no further than the pellet actually travelled. Turn this on only to A/B the old feel; it cannot be right, only familiar."); WeaponsCreatureBlood = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Creature Blood", true, "Make flesh and insectoid creatures bleed where a bullet lands (#120), using the optional Y4NGZBloodFX plugin's blood system — the same bursts, splatter and decal budget that player blood uses, so the '08 - Blood FX' section of com.y4ngz.bloodfx.cfg governs how much of it there is. Robots spark instead and never bleed; ghosts and unclassified creatures draw nothing. Y4NGZBloodFX is NOT a dependency: without it installed, creature hits simply draw no blood. Turning Blood FX off there turns this off with it; this switch exists to judge creature blood separately from player blood."); WeaponsCreatureBloodBurstScale = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Creature Blood Burst Scale", 1f, "How big a creature blood burst is, as a multiplier on the authored size (#147). 1.0 is the size every blood burst has been since the system shipped — and that size was authored for a PLAYER wound seen at melee range, never judged on a creature at shooting distance. Raise this if wounds read too small. Per-weapon spread is applied on top: small caliber 1.0, heavy caliber 1.45, shotgun 1.7, grenades 2.2. This scales the burst's SIZE; '[08 - Blood FX] Intensity' in com.y4ngz.bloodfx.cfg scales its particle COUNT, which is a different question."); WeaponsCreatureBloodFleshTint = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Flesh Blood Tint", string.Empty, "Colour that flesh creatures bleed, as 'r,g,b' from 0 to 1. LEAVE EMPTY for the authored red — the blood assets are already red and their textures are greyscale masks, so an empty value draws the shipped look untouched rather than tinting red over red. Set a value only to push human/animal blood somewhere else deliberately."); WeaponsCreatureBloodInsectTint = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Insect Blood Tint", "0.32,0.44,0.06", "Colour that insectoid creatures bleed (spiders, centipedes, bees, hoarding bugs), as 'r,g,b' from 0 to 1. Empty falls back to this same green. The decal masks are authored for red, so a strongly shifted hue can read muddy — if one does, the fix is a dedicated asset rather than a further push on this number."); WeaponsVfxIsolationKey = ((BaseUnityPlugin)this).Config.Bind("Weapons", "VFX Isolation Test Key", "F9", "Diagnostic-only: spawns the muzzle flash unparented 1.5 m in front of the camera and reports it, separating 'the effect does not render' from 'the effect is mounted where you cannot see it'. Requires VFX Diagnostics. Use Unity InputSystem Key names; empty disables."); AmmoDevSpawnKeyEnabled = ((BaseUnityPlugin)this).Config.Bind("Ammo", "Dev Spawn Key Enabled", true, "Dev-only: while hosting, press Insert to spawn one of each ammo pickup near the local player."); CombatFeedbackEnabled = ((BaseUnityPlugin)this).Config.Bind("Combat Feedback", "Enabled", true, "Enable global combat feel improvements such as hit markers and enemy hit flashes."); CombatFeedbackHitMarkerEnabled = ((BaseUnityPlugin)this).Config.Bind("Combat Feedback", "Hit Marker Enabled", true, "Show a brief center-screen hit marker when the local player hits an enemy."); CombatFeedbackHitSoundEnabled = ((BaseUnityPlugin)this).Config.Bind("Combat Feedback", "Hit Sound Enabled", true, "Play a small UI tick when the local player hits an enemy."); CombatFeedbackWeaponCrosshairEnabled = ((BaseUnityPlugin)this).Config.Bind("Combat Feedback", "Weapon Crosshair Enabled", true, "Show a subtle center crosshair while holding aimed/projectile weapons."); CombatFeedbackWeaponFirePulseEnabled = ((BaseUnityPlugin)this).Config.Bind("Combat Feedback", "Weapon Fire Pulse Enabled", true, "Pulse the weapon crosshair when firing an aimed/projectile weapon."); CrosshairAccuracySizingEnabled = ((BaseUnityPlugin)this).Config.Bind("Crosshair", "Accuracy Sizing", true, "Size the weapon crosshair from the cone the weapon would actually fire right now — its spread plus movement, stance, fire and recoil bloom — projected through the live camera FOV. Off falls back to the old fixed 16-24 px gap for every weapon."); CrosshairHonestSizingOnly = ((BaseUnityPlugin)this).Config.Bind("Crosshair", "Honest Sizing Only", true, "Only size the crosshair from spread when that spread reaches a bullet. The cloned first-generation weapons fire through vanilla ShootGun, which applies NO spread at all, so their authored cone is decoration — with this on they draw a fixed per-family size instead of a number nothing consumes. Each weapon stops being cosmetic as it migrates to the native base (#117). Turn off to let those weapons bloom cosmetically anyway."); CrosshairVanillaCursorIcon = ((BaseUnityPlugin)this).Config.Bind("Crosshair", "Vanilla Cursor Icon", VanillaCursorIconMode.Hide, "How the vanilla centre interaction icon coexists with the custom target cue. Hide replaces it, Fade keeps it enabled at zero alpha for compatibility, and Show leaves it visible."); WorldFeedbackEnabled = ((BaseUnityPlugin)this).Config.Bind("World Feedback", "Enabled", true, "Enable client-side interaction, scrap, near miss, and scan feedback."); WorldFeedbackInteractionReticleEnabled = ((BaseUnityPlugin)this).Config.Bind("World Feedback", "Interaction Reticle Enabled", true, "Show a small center cue while targeting pickups or interactables."); ArmoryContentConfig.Bind(((BaseUnityPlugin)this).Config); ArmoryConfigMigration.Apply(((BaseUnityPlugin)this).Config); ArmoryConfigMigration.PruneRetiredKeys(((BaseUnityPlugin)this).Config); } private static void ReserveUpgradesKeys(HashSet used) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) string[] reservedKeyNames = UpgradesBridge.GetReservedKeyNames(); for (int i = 0; i < reservedKeyNames.Length; i++) { if (Enum.TryParse(reservedKeyNames[i], ignoreCase: true, out Key result)) { used.Add(result); } } } private static void ReserveActionKeys(HashSet used, InputAction action) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_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_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) if (action == null) { return; } Enumerator enumerator = action.bindings.GetEnumerator(); try { while (enumerator.MoveNext()) { InputBinding current = enumerator.Current; ReserveKey(used, ParseKeyboardBindingPath(((InputBinding)(ref current)).effectivePath)); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } private static Key? ParseKeyboardBindingPath(string path) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(path)) { return null; } if (!path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) { return null; } string text = path.Substring("/".Length).Trim(); if (text.Length == 1 && text[0] >= '1' && text[0] <= '9') { return (Key)(41 + (text[0] - 49)); } if (text == "0") { return (Key)50; } if (!Enum.TryParse(text, ignoreCase: true, out Key result)) { return null; } return result; } private static void ReserveKey(HashSet used, Key? key) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (key.HasValue) { used.Add(key.Value); } } private unsafe static void ResolveAbilityKey(HashSet used, ref Key? key, ConfigEntry entry, Key preferredFallback, Key secondaryFallback, string label) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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) if (!key.HasValue) { return; } if (!used.Contains(key.Value)) { used.Add(key.Value); return; } Key val = ((!used.Contains(preferredFallback)) ? preferredFallback : secondaryFallback); if (used.Contains(val)) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)(label + " keybind conflicts with another ability key; " + label + " keybind disabled until config is changed.")); } key = null; return; } entry.Value = ((object)(*(Key*)(&val))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); key = val; used.Add(val); ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)(label + " keybind conflicted with another ability; reassigned to [" + entry.Value + "].")); } } public static string FormatKeyLabel(Key? key, string fallback) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) string text = (key.HasValue ? ((object)key.Value/*cast due to .constrained prefix*/).ToString() : fallback); if (string.IsNullOrWhiteSpace(text)) { return ""; } if (text.StartsWith("Digit", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Digit".Length); } else if (text.StartsWith("Numpad", StringComparison.OrdinalIgnoreCase)) { text = "NUM" + text.Substring("Numpad".Length); } else if (text.StartsWith("Alpha", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Alpha".Length); } return text.ToUpperInvariant(); } internal static void ReloadWeaponVisualConfig() { if ((Object)(object)Instance == (Object)null) { return; } try { ((BaseUnityPlugin)Instance).Config.Reload(); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons] config reload failed: " + ex.Message)); } } ApplyWeaponVisualConfig(); } internal static void ReloadWeaponFpPropConfig() { if ((Object)(object)Instance == (Object)null) { return; } try { ((BaseUnityPlugin)Instance).Config.Reload(); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[Y4NGZWeapons.FP] config reload failed: " + ex.Message)); } } ApplyWeaponFpPropConfig(); } private static void ApplyWeaponVisualConfig() { //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_001b: 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) //IL_003b: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_0098: Unknown result type (might be due to invalid IL or missing references) WeaponVisuals.HeavyShotgunPos = ParseVec(WeaponsHsVisualPos?.Value, Vector3.zero); WeaponVisuals.HeavyShotgunEuler = ParseVec(WeaponsHsVisualRot?.Value, Vector3.zero); WeaponVisuals.HeavyShotgunScale = ((WeaponsHsVisualScale != null) ? WeaponsHsVisualScale.Value : 1f); WeaponVisuals.RevolverPos = ParseVec(WeaponsRevolverVisualPos?.Value, Vector3.zero); WeaponVisuals.RevolverEuler = ParseVec(WeaponsRevolverVisualRot?.Value, Vector3.zero); WeaponVisuals.RevolverScale = ((WeaponsRevolverVisualScale != null) ? WeaponsRevolverVisualScale.Value : 1f); } private static void ApplyWeaponFpPropConfig() { //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_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) WeaponsFpPropPosDeltaValue = ParseVec(WeaponsFpPropPosDelta?.Value, Vector3.zero); WeaponsFpPropRotDeltaValue = ParseVec(WeaponsFpPropRotDelta?.Value, Vector3.zero); WeaponsFpPropScaleMultValue = ((WeaponsFpPropScaleMult != null) ? WeaponsFpPropScaleMult.Value : 1f); } internal static Vector3 ParseVectorOrDefault(string s, Vector3 fallback) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) return ParseVec(s, fallback); } private static Color ToTint(string configured, Color fallback) { //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) //IL_0024: 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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(configured)) { return fallback; } Vector3 val = ParseVec(configured, new Vector3(float.NaN, 0f, 0f)); if (float.IsNaN(val.x)) { return fallback; } return new Color(Mathf.Clamp01(val.x), Mathf.Clamp01(val.y), Mathf.Clamp01(val.z), 1f); } private static Vector3 ParseVec(string s, Vector3 fallback) { //IL_0008: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(s)) { return fallback; } string[] array = s.Split(','); if (array.Length != 3) { return fallback; } CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (float.TryParse(array[0].Trim(), NumberStyles.Float, invariantCulture, out var result) && float.TryParse(array[1].Trim(), NumberStyles.Float, invariantCulture, out var result2) && float.TryParse(array[2].Trim(), NumberStyles.Float, invariantCulture, out var result3)) { return new Vector3(result, result2, result3); } return fallback; } private static Key? ParseKey(string keyName) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(keyName)) { return null; } if (Enum.TryParse(keyName, ignoreCase: true, out Key result)) { return result; } switch (keyName.ToLowerInvariant().Trim()) { case "a": return (Key)15; case "b": return (Key)16; case "c": return (Key)17; case "d": return (Key)18; case "e": return (Key)19; case "f": return (Key)20; case "g": return (Key)21; case "h": return (Key)22; case "i": return (Key)23; case "j": return (Key)24; case "k": return (Key)25; case "l": return (Key)26; case "m": return (Key)27; case "n": return (Key)28; case "o": return (Key)29; case "p": return (Key)30; case "q": return (Key)31; case "r": return (Key)32; case "s": return (Key)33; case "t": return (Key)34; case "u": return (Key)35; case "v": return (Key)36; case "w": return (Key)37; case "x": return (Key)38; case "y": return (Key)39; case "z": return (Key)40; case "capslock": case "caps": return (Key)72; case "tab": return (Key)3; case "space": return (Key)1; case "f1": return (Key)94; case "f2": return (Key)95; case "f3": return (Key)96; case "f4": return (Key)97; case "f5": return (Key)98; case "f6": return (Key)99; case "f7": return (Key)100; case "f8": return (Key)101; default: { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("ParseKey: unrecognised key name '" + keyName + "'. Ability will use its default key.")); } return null; } } } } internal static class UpgradesBridge { private const string UpgradesPluginGuid = "com.y4ngz.upgrades"; private static bool _presenceResolved; private static bool _present; private static bool _reservedKeysResolved; private static MethodInfo _getReservedKeyNames; private static bool _scavengerResolved; private static MethodInfo _getAmmoMultiplier; private static bool _mantleResolved; private static MethodInfo _isDebugThirdPersonCamActive; private static bool _budgetResolved; private static MethodInfo _budgetRegister; private static MethodInfo _budgetUnregister; private static MethodInfo _budgetTick; internal static bool IsUpgradesPresent { get { if (_presenceResolved) { return _present; } _presenceResolved = true; try { _present = Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("com.y4ngz.upgrades"); } catch { _present = false; } return _present; } } internal static string[] GetReservedKeyNames() { if (!_reservedKeysResolved) { _reservedKeysResolved = true; _getReservedKeyNames = ResolveMethod("Y4NGZUpgrades.KeybindReservationApi", "GetReservedKeyNames", Type.EmptyTypes); if (_getReservedKeyNames == null && IsUpgradesPresent) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[BetterArmory] Y4NGZUpgrades' KeybindReservationApi was not found. The grenade key will not be resolved against its ability keys this session."); } } } if (_getReservedKeyNames == null) { return new string[0]; } try { return (_getReservedKeyNames.Invoke(null, null) as string[]) ?? new string[0]; } catch { return new string[0]; } } internal static float GetAmmoMultiplier() { if (!_scavengerResolved) { _scavengerResolved = true; _getAmmoMultiplier = ResolveMethod("Y4NGZUpgrades.ProgressionApi", "GetScavengerAmmoMultiplier", Type.EmptyTypes); } if (_getAmmoMultiplier == null) { return 1f; } try { return (float)_getAmmoMultiplier.Invoke(null, null); } catch { return 1f; } } internal static bool IsDebugThirdPersonCamActive() { if (!_mantleResolved) { _mantleResolved = true; _isDebugThirdPersonCamActive = ResolveMethod("Y4NGZUpgrades.Patches.LedgeMantlePatch", "IsDebugThirdPersonCamActive", Type.EmptyTypes); } if (_isDebugThirdPersonCamActive == null) { return false; } try { return (bool)_isDebugThirdPersonCamActive.Invoke(null, null); } catch { return false; } } internal static void RegisterFireLight(Light light) { ResolveBudget(); Invoke(_budgetRegister, light); } internal static void UnregisterFireLight(Light light) { ResolveBudget(); Invoke(_budgetUnregister, light); } internal static void TickFireLightBudget() { ResolveBudget(); if (_budgetTick == null) { return; } try { _budgetTick.Invoke(null, null); } catch { } } private static void ResolveBudget() { if (!_budgetResolved) { _budgetResolved = true; _budgetRegister = ResolveMethod("Y4NGZUpgrades.Effects.BurningFireLightBudget", "Register", new Type[1] { typeof(Light) }); _budgetUnregister = ResolveMethod("Y4NGZUpgrades.Effects.BurningFireLightBudget", "Unregister", new Type[1] { typeof(Light) }); _budgetTick = ResolveMethod("Y4NGZUpgrades.Effects.BurningFireLightBudget", "Tick", Type.EmptyTypes); } } private static void Invoke(MethodInfo method, Light light) { if (method == null || (Object)(object)light == (Object)null) { return; } try { method.Invoke(null, new object[1] { light }); } catch { } } private static MethodInfo ResolveMethod(string typeName, string methodName, Type[] parameters) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType(typeName, throwOnError: false); if (type == null) { continue; } return type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null); } catch { } } return null; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "BetterArmory"; public const string PLUGIN_NAME = "BetterArmory"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace BetterArmory.Ui { internal static class ArmoryUiStyle { private static readonly Color FallbackAccent = new Color(1f, 0.4266f, 0.06f, 1f); private const string UiThemeTypeName = "Y4NGZCompany.Experience.UITheme.UiTheme"; private const string VisibilityTypeName = "Y4NGZCompany.Experience.UITheme.GameplayUiVisibility"; private const string HudMotionTypeName = "Y4NGZCompany.Experience.UITheme.GameplayHudMotion"; private static bool _resolved; private static PropertyInfo _accentProperty; private static PropertyInfo _visibilityProperty; private static Action _motionListeners; private static bool _motionSubscribed; internal static Color CurrentAccentColor { get { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Resolve(); if (_accentProperty != null) { try { return (Color)_accentProperty.GetValue(null); } catch { } } return FallbackAccent; } } internal static Color BorderColor { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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) Color currentAccentColor = CurrentAccentColor; currentAccentColor.a = 0.6f; return currentAccentColor; } } internal static bool GameplayUiVisible { get { Resolve(); if (_visibilityProperty != null) { try { return (bool)_visibilityProperty.GetValue(null); } catch { } } return true; } } internal static Vector2 HudMotionOffset { get; private set; } internal static void SubscribeHudMotion(Action listener) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (listener != null) { _motionListeners = (Action)Delegate.Combine(_motionListeners, listener); EnsureMotionSubscription(); listener(HudMotionOffset); } } private static void EnsureMotionSubscription() { //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_0097: Unknown result type (might be due to invalid IL or missing references) if (_motionSubscribed) { return; } _motionSubscribed = true; try { Type type = FindType("Y4NGZCompany.Experience.UITheme.GameplayHudMotion"); EventInfo eventInfo = type?.GetEvent("MotionSampled", BindingFlags.Static | BindingFlags.Public); if (!(eventInfo == null)) { MethodInfo method = typeof(ArmoryUiStyle).GetMethod("OnHudMotionSampled", BindingFlags.Static | BindingFlags.NonPublic); eventInfo.AddEventHandler(null, Delegate.CreateDelegate(eventInfo.EventHandlerType, method)); PropertyInfo property = type.GetProperty("CurrentOffset", BindingFlags.Static | BindingFlags.Public); if (property != null && property.GetValue(null) is Vector2 hudMotionOffset) { HudMotionOffset = hudMotionOffset; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BetterArmory] HUD parallax is unavailable: " + ex.Message + ". Weapon HUD elements sit at their authored anchors.")); } } } private static void OnHudMotionSampled(Vector2 offset) { //IL_0000: 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) HudMotionOffset = offset; try { _motionListeners?.Invoke(offset); } catch { } } private static void Resolve() { if (!_resolved) { _resolved = true; Type type = FindType("Y4NGZCompany.Experience.UITheme.UiTheme"); if (type != null) { _accentProperty = type.GetProperty("Accent", BindingFlags.Static | BindingFlags.Public); } Type type2 = FindType("Y4NGZCompany.Experience.UITheme.GameplayUiVisibility"); if (type2 != null) { _visibilityProperty = type2.GetProperty("IsVisible", BindingFlags.Static | BindingFlags.Public); } } } private static Type FindType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType(fullName, throwOnError: false); if (type != null) { return type; } } catch { } } return null; } } } namespace BetterArmory.Interactive { internal readonly struct HeldItemStowHandle : IDisposable { private readonly PlayerControllerB _player; private readonly long _token; internal bool IsActive { get { if (_token != 0L) { return HeldItemStowService.IsTokenLive(_player, _token); } return false; } } internal HeldItemStowHandle(PlayerControllerB player, long token) { _player = player; _token = token; } public void Dispose() { if (_token != 0L) { HeldItemStowService.Release(_player, _token); } } } internal static class HeldItemStowService { private const string TypeName = "Y4NGZUpgrades.HeldItemStowApi"; private static bool _resolved; private static MethodInfo _beginToken; private static MethodInfo _isTokenLive; private static MethodInfo _releaseToken; private static MethodInfo _endStow; private static MethodInfo _isStowed; private static bool _warned; internal static HeldItemStowHandle Begin(PlayerControllerB player, string reason, float timeoutSeconds, bool disableItemActions = false, bool force = false) { if ((Object)(object)player == (Object)null) { return default(HeldItemStowHandle); } Resolve(); if (_beginToken == null) { return default(HeldItemStowHandle); } try { return (_beginToken.Invoke(null, new object[5] { player, reason, timeoutSeconds, disableItemActions, force }) is long num && num != 0L) ? new HeldItemStowHandle(player, num) : default(HeldItemStowHandle); } catch (Exception ex) { Warn("BeginStowToken", ex); return default(HeldItemStowHandle); } } internal static bool IsTokenLive(PlayerControllerB player, long token) { Resolve(); if (_isTokenLive == null || (Object)(object)player == (Object)null) { return false; } try { return (bool)_isTokenLive.Invoke(null, new object[2] { player, token }); } catch (Exception ex) { Warn("IsStowTokenLive", ex); return false; } } internal static void Release(PlayerControllerB player, long token) { Resolve(); if (_releaseToken == null || (Object)(object)player == (Object)null) { return; } try { _releaseToken.Invoke(null, new object[2] { player, token }); } catch (Exception ex) { Warn("ReleaseStowToken", ex); } } internal static void End(PlayerControllerB player, string reason) { Resolve(); if (_endStow == null || (Object)(object)player == (Object)null) { return; } try { _endStow.Invoke(null, new object[2] { player, reason }); } catch (Exception ex) { Warn("EndStow", ex); } } internal static bool IsStowed(PlayerControllerB player) { Resolve(); if (_isStowed == null || (Object)(object)player == (Object)null) { return false; } try { return (bool)_isStowed.Invoke(null, new object[1] { player }); } catch (Exception ex) { Warn("IsStowed", ex); return false; } } private static void Resolve() { if (_resolved) { return; } _resolved = true; Type type = FindType("Y4NGZUpgrades.HeldItemStowApi"); if (type == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[BetterArmory] Y4NGZUpgrades' HeldItemStowApi is not present. Grenade throws will suppress item input locally instead of stowing the held item."); } return; } _beginToken = type.GetMethod("BeginStowToken", BindingFlags.Static | BindingFlags.Public, null, new Type[5] { typeof(PlayerControllerB), typeof(string), typeof(float), typeof(bool), typeof(bool) }, null); _isTokenLive = type.GetMethod("IsStowTokenLive", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(PlayerControllerB), typeof(long) }, null); _releaseToken = type.GetMethod("ReleaseStowToken", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(PlayerControllerB), typeof(long) }, null); _endStow = type.GetMethod("EndStow", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(PlayerControllerB), typeof(string) }, null); _isStowed = type.GetMethod("IsStowed", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(PlayerControllerB) }, null); if (_beginToken == null || _isTokenLive == null || _releaseToken == null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[BetterArmory] HeldItemStowApi is present but its token members did not resolve. Grenade throws fall back to local item-input suppression."); } } } private static void Warn(string member, Exception ex) { if (!_warned) { _warned = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BetterArmory] HeldItemStowApi." + member + " failed safely: " + ex.Message)); } } } private static Type FindType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType(fullName, throwOnError: false); if (type != null) { return type; } } catch { } } return null; } } } namespace BetterArmory.Effects { internal static class BloodFxBridge { private const string TypeName = "Y4NGZCompany.Experience.BloodFX.BloodFXCreatureBlood"; private static bool _resolved; private static PropertyInfo _isAvailable; private static MethodInfo _playCreatureBleed; internal static bool IsAvailable { get { Resolve(); if (_isAvailable == null || _playCreatureBleed == null) { return false; } try { return (bool)_isAvailable.GetValue(null); } catch { return false; } } } internal static bool PlayCreatureBleed(int victimInstanceId, Vector3 point, Vector3 travel, Color tint, int contacts, float scale) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) Resolve(); if (_playCreatureBleed == null) { return false; } try { object obj = _playCreatureBleed.Invoke(null, new object[6] { victimInstanceId, point, travel, tint, contacts, scale }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BetterArmory] creature-blood bridge threw: " + ex.Message)); } return false; } } private static void Resolve() { if (_resolved) { return; } _resolved = true; Type type = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { type = assembly.GetType("Y4NGZCompany.Experience.BloodFX.BloodFXCreatureBlood", throwOnError: false); if (type != null) { break; } } catch { } } if (!(type == null)) { _isAvailable = type.GetProperty("IsAvailable", BindingFlags.Static | BindingFlags.Public); _playCreatureBleed = type.GetMethod("PlayCreatureBleed", BindingFlags.Static | BindingFlags.Public, null, new Type[6] { typeof(int), typeof(Vector3), typeof(Vector3), typeof(Color), typeof(int), typeof(float) }, null); } } } internal static class EnemyStatusEffects { private const string TypeName = "Y4NGZUpgrades.Effects.EnemyStatusEffects"; private static bool _resolved; private static MethodInfo _applyBurning; private static bool _warned; internal static void ApplyBurning(EnemyAI enemy, PlayerControllerB sourcePlayer, float duration, int damagePerTick, float tickInterval) { if ((Object)(object)enemy == (Object)null) { return; } Resolve(); if (_applyBurning == null) { if (!_warned) { _warned = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[BetterArmory] Burning status is unavailable: Y4NGZUpgrades' EnemyStatusEffects.ApplyBurning could not be resolved. Flamethrower and ground fire will deal their direct damage without setting enemies alight."); } } return; } try { _applyBurning.Invoke(null, new object[5] { enemy, sourcePlayer, duration, damagePerTick, tickInterval }); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[BetterArmory] ApplyBurning bridge threw: " + ex.Message)); } } } private static void Resolve() { if (_resolved) { return; } _resolved = true; Type type = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { type = assembly.GetType("Y4NGZUpgrades.Effects.EnemyStatusEffects", throwOnError: false); if (type != null) { break; } } catch { } } if (!(type == null)) { _applyBurning = type.GetMethod("ApplyBurning", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[5] { typeof(EnemyAI), typeof(PlayerControllerB), typeof(float), typeof(int), typeof(float) }, null); } } } internal static class SlideAnimationBridge { private const string TypeName = "Y4NGZUpgrades.Effects.SlideAnimationBridge"; private static bool _resolved; private static MethodInfo _isActive; internal static bool IsActive(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return false; } Resolve(); if (_isActive == null) { return false; } try { return (bool)_isActive.Invoke(null, new object[1] { player }); } catch { return false; } } private static void Resolve() { if (_resolved) { return; } _resolved = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType("Y4NGZUpgrades.Effects.SlideAnimationBridge", throwOnError: false); if (type == null) { continue; } _isActive = type.GetMethod("IsActive", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(PlayerControllerB) }, null); break; } catch { } } } } internal static class VanillaCloneStaging { private static Transform _nursery; internal static GameObject CloneInactive(GameObject template, Transform parent, string name) { //IL_0088: 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) if ((Object)(object)template == (Object)null || (Object)(object)parent == (Object)null) { return null; } Transform val = EnsureNursery(); if ((Object)(object)val == (Object)null) { return null; } GameObject val2; try { val2 = Object.Instantiate(template, val, false); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[VanillaClone] cloning '" + ((Object)template).name + "' failed: " + ex.Message)); } return null; } ((Object)val2).name = name; val2.SetActive(false); StripNetworking(val2); val2.transform.SetParent(parent, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; return val2; } private static void StripNetworking(GameObject clone) { NetworkBehaviour[] componentsInChildren = clone.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } } NetworkObject[] componentsInChildren2 = clone.GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren2.Length; j++) { if ((Object)(object)componentsInChildren2[j] != (Object)null) { Object.DestroyImmediate((Object)(object)componentsInChildren2[j]); } } } private static Transform EnsureNursery() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_nursery != (Object)null) { return _nursery; } GameObject val = new GameObject("Y4NGZ_VanillaCloneNursery"); val.SetActive(false); ((Object)val).hideFlags = (HideFlags)61; _nursery = val.transform; return _nursery; } } internal static class VanillaEnemyPrefabs { internal static T Find(Func usable) where T : Component { //IL_00d0: 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 (usable == null) { return default(T); } QuickMenuManager val = Object.FindObjectOfType(); T val2 = FindInLevel(((Object)(object)val != (Object)null) ? val.testAllEnemiesLevel : null, usable); if ((Object)(object)val2 != (Object)null) { return val2; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && instance.levels != null) { for (int i = 0; i < instance.levels.Length; i++) { T val3 = FindInLevel(instance.levels[i], usable); if ((Object)(object)val3 != (Object)null) { return val3; } } } T[] array = Resources.FindObjectsOfTypeAll(); T val4 = default(T); foreach (T val5 in array) { if (!((Object)(object)val5 == (Object)null) && usable(val5)) { Scene scene = ((Component)val5).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return val5; } if ((Object)(object)val4 == (Object)null) { val4 = val5; } } } return val4; } private static T FindInLevel(SelectableLevel level, Func usable) where T : Component { if ((Object)(object)level == (Object)null) { return default(T); } T val = FindInSpawnList(level.Enemies, usable); if ((Object)(object)val != (Object)null) { return val; } val = FindInSpawnList(level.OutsideEnemies, usable); if ((Object)(object)val != (Object)null) { return val; } return FindInSpawnList(level.DaytimeEnemies, usable); } private static T FindInSpawnList(List spawns, Func usable) where T : Component { if (spawns == null) { return default(T); } for (int i = 0; i < spawns.Count; i++) { SpawnableEnemyWithRarity val = spawns[i]; GameObject val2 = ((val != null && (Object)(object)val.enemyType != (Object)null) ? val.enemyType.enemyPrefab : null); if (!((Object)(object)val2 == (Object)null)) { T component = val2.GetComponent(); if ((Object)(object)component != (Object)null && usable(component)) { return component; } } } return default(T); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }