Decompiled source of ForgeOrdnance Arsenal v1.0.0
ForgeOrdnanceArsenal.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers.Binary; 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.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.Json; using Agents; using BepInEx; using BepInEx.Configuration; using BepInEx.Unity.IL2CPP; using Enemies; using ForgeAudio; using ForgeCore; using ForgeOrdnance; using ForgeUI; using ForgeVisual; using GTFO.API; using GameData; using Gear; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using Player; using SNetwork; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("ForgeOrdnanceArsenal")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+66ec6b43e1a1603bac84a4b9a226674300b2fc7d")] [assembly: AssemblyProduct("ForgeOrdnanceArsenal")] [assembly: AssemblyTitle("ForgeOrdnanceArsenal")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } [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 ForgeOrdnanceArsenal { public interface IReach { bool Reaches(int index); } public interface IBlocker { bool Blocked(float ax, float ay, float az, float bx, float by, float bz); } public enum RouteStep { Moving, Arrived, Blocked } public sealed class BeamRoute { public const int Capacity = 48; private readonly float[] _x = new float[48]; private readonly float[] _y = new float[48]; private readonly float[] _z = new float[48]; private int _count; private int _next; public float X; public float Y; public float Z; public float Moved; public int Count => _count; public BeamRoute(float x, float y, float z) { X = x; Y = y; Z = z; } public void Begin() { _count = 0; _next = 0; } public bool Add(float x, float y, float z) { if (_count == 48) { Begin(); return false; } _x[_count] = x; _y[_count] = y; _z[_count] = z; _count++; return true; } public RouteStep Step<T>(float distance, ref T blocker) where T : IBlocker { Moved = 0f; while (distance > 1E-06f) { if (_next >= _count) { return RouteStep.Arrived; } float num = _x[_next] - X; float num2 = _z[_next] - Z; float num3 = MathF.Sqrt(num * num + num2 * num2); if (num3 <= 0.0001f) { Y = _y[_next]; _next++; continue; } float num4 = MathF.Min(distance, num3); float num5 = num4 / num3; float num6 = Y + (_y[_next] - Y) * num5; float x = X; float y = Y; float z = Z; float bx = X + num * num5; float bz = Z + num2 * num5; if (blocker.Blocked(x, y, z, bx, num6, bz)) { return RouteStep.Blocked; } X += num * num5; Y = num6; Z += num2 * num5; Moved += num4; distance -= num4; if (num4 >= num3 - 0.0001f) { _next++; } } if (_next < _count) { return RouteStep.Moving; } return RouteStep.Arrived; } } public static class ClusterScatter { public const int Sparklets = 3; public static uint Seed(ulong summoner, uint throwId, float x, float z) { return (((StrikePlan.Seed(summoner, throwId) ^ (uint)(int)MathF.Round(x * 100f)) * 16777619) ^ (uint)(int)MathF.Round(z * 100f)) * 16777619; } public static void Offsets(uint seed, int count, float radius, float[] offsets) { if (count < 0 || offsets.Length < count * 2) { throw new ArgumentOutOfRangeException("count"); } StrikePlan.Lcg lcg = new StrikePlan.Lcg(seed); float num = lcg.Next() * (float)Math.PI * 2f; for (int i = 0; i < count; i++) { float x = num + (float)i * (float)Math.PI * 2f / (float)count + (lcg.Next() - 0.5f) * 0.7f; float num2 = radius * (0.5f + 0.5f * lcg.Next()); offsets[2 * i] = MathF.Cos(x) * num2; offsets[2 * i + 1] = MathF.Sin(x) * num2; } } } public static class HeavyModels { public const string MarkerPrefix = "Forge Heavy "; private static readonly Dictionary<uint, string> Known = new Dictionary<uint, string>(); private static readonly Dictionary<string, (uint Hash, string Id)> ByMarker = new Dictionary<string, (uint, string)>(StringComparer.Ordinal); public static uint Hash(string id) { return Fnv.Hash32(id); } public static string Marker(uint hash) { return "Forge Heavy " + hash.ToString("x8", CultureInfo.InvariantCulture); } public static bool TryMarker(string? name, out uint hash) { hash = 0u; if (name == null || !ByMarker.TryGetValue(name, out (uint, string) value)) { return false; } (hash, _) = value; return true; } public static bool TryMarkerId(string? name, out string id) { id = ""; if (name == null || !ByMarker.TryGetValue(name, out (uint, string) value)) { return false; } id = value.Item2; return true; } public static bool IsId(string? id) { if (string.IsNullOrEmpty(id)) { return false; } int num = id.IndexOf(':'); if (num > 0 && num < id.Length - 1 && id.IndexOf(':', num + 1) < 0) { return id.IndexOf(' ') < 0; } return false; } public static bool TryId(uint hash, out string id) { return Known.TryGetValue(hash, out id); } public static string? Register(string id) { uint num = Hash(id); if (Known.TryAdd(num, id)) { ByMarker[Marker(num)] = (num, id); return null; } if (Known[num] == id) { return null; } return "its hash " + num.ToString("x8", CultureInfo.InvariantCulture) + " is the same as the hash of the model " + Known[num] + " (" + id + " is refused; rename one of them)."; } public static void Clear() { Known.Clear(); ByMarker.Clear(); } } public sealed record GrenadeSpec(float Damage, float Radius, float Speed) { internal bool Valid { get { if (Damage >= 0f && (double)Damage <= 20000.0 && (double)Radius >= 0.5 && (double)Radius <= 20.0 && (double)Speed >= 5.0) { return (double)Speed <= 150.0; } return false; } } internal const double DamageMax = 20000.0; internal const double RadiusMin = 0.5; internal const double RadiusMax = 20.0; internal const double SpeedMin = 5.0; internal const double SpeedMax = 150.0; [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { RuntimeHelpers.EnsureSufficientExecutionStack(); builder.Append("Damage = "); builder.Append(Damage.ToString()); builder.Append(", Radius = "); builder.Append(Radius.ToString()); builder.Append(", Speed = "); builder.Append(Speed.ToString()); return true; } [CompilerGenerated] private GrenadeSpec(GrenadeSpec original) { Damage = original.Damage; Radius = original.Radius; Speed = original.Speed; } } public sealed class HeavyWeaponSpec { public const string TypeName = "arsenal.HeavyWeapon"; private static readonly string[] Known = Concat(new string[4] { "Model", "Gear", "AmmoRatio", "Grenade" }, ArchetypeTuning.Names); private static readonly string[] GrenadeFields = new string[3] { "Damage", "Radius", "Speed" }; private static readonly string[] TypeField = new string[1] { "Type" }; public string Model { get; private set; } = ""; public uint ModelHash { get; private set; } public string Marker { get; private set; } = ""; public uint? GearId { get; private set; } public string? GearName { get; private set; } public float AmmoRatio { get; private set; } public GrenadeSpec? Grenade { get; private set; } public ArchetypeTuning Tuning { get; private set; } = ArchetypeTuning.None; public static HeavyWeaponSpec Parse(JsonElement payload) { //IL_0014: 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) if (payload.ValueKind != JsonValueKind.Object) { throw new StrictJsonException("Payload", "must be an object."); } StrictJson.OnlyKnown(payload, "", Known, TypeField, "a heavy weapon"); if (!payload.TryGetProperty("Model", out var value) || value.ValueKind != JsonValueKind.String || !HeavyModels.IsId(value.GetString())) { throw new StrictJsonException("Model", "is required: a ForgeVisual model id written Pack:item."); } HeavyWeaponSpec heavyWeaponSpec = WithModel(value.GetString()); HeavyWeaponSpec heavyWeaponSpec2 = heavyWeaponSpec; (uint?, string) tuple = StrictJson.Reference(payload, "", "Gear"); heavyWeaponSpec2.GearId = tuple.Item1; heavyWeaponSpec.GearName = tuple.Item2; heavyWeaponSpec.AmmoRatio = (float)StrictJson.Number(payload, "", "AmmoRatio", (double?)1.0, 0.05, 1.0); heavyWeaponSpec.Tuning = ArchetypeTuning.Parse(payload); if (payload.TryGetProperty("Grenade", out var value2)) { StrictJson.OnlyKnown(value2, "Grenade.", GrenadeFields, (string[])null, (string)null); heavyWeaponSpec.Grenade = new GrenadeSpec((float)StrictJson.Number(value2, "Grenade.", "Damage", (double?)140.0, 0.0, 20000.0), (float)StrictJson.Number(value2, "Grenade.", "Radius", (double?)4.0, 0.5, 20.0), (float)StrictJson.Number(value2, "Grenade.", "Speed", (double?)32.0, 5.0, 150.0)); } return heavyWeaponSpec; } public static HeavyWeaponSpec? Restore(string model, uint gearId, float ammoRatio, GrenadeSpec? grenade, ArchetypeTuning? tuning) { if (!HeavyModels.IsId(model) || gearId == 0 || !(ammoRatio >= 0.05f) || !(ammoRatio <= 1f) || tuning == null || ((object)grenade != null && !grenade.Valid)) { return null; } HeavyWeaponSpec heavyWeaponSpec = WithModel(model); heavyWeaponSpec.GearId = gearId; heavyWeaponSpec.AmmoRatio = ammoRatio; heavyWeaponSpec.Grenade = grenade; heavyWeaponSpec.Tuning = tuning; return heavyWeaponSpec; } private static HeavyWeaponSpec WithModel(string model) { uint num = HeavyModels.Hash(model); return new HeavyWeaponSpec { Model = model, ModelHash = num, Marker = HeavyModels.Marker(num) }; } private static string[] Concat(string[] a, string[] b) { string[] array = new string[a.Length + b.Length]; a.CopyTo(array, 0); b.CopyTo(array, a.Length); return array; } } public sealed class ArchetypeTuning { public const int Count = 12; private static readonly (string Name, double Min, double Max, bool Whole)[] Table = new(string, double, double, bool)[12] { ("Damage", 0.01, 20000.0, false), ("ShotDelay", 0.02, 10.0, false), ("Cooldown", 0.0, 30.0, false), ("Chargeup", 0.0, 10.0, false), ("Magazine", 1.0, 1000.0, true), ("Reload", 0.1, 30.0, false), ("PrecisionMultiplier", 0.0, 10.0, false), ("StaggerMultiplier", 0.0, 20.0, false), ("Pierce", 0.0, 20.0, true), ("AmmoCost", 0.01, 1000.0, false), ("FalloffStart", 0.0, 1000.0, false), ("FalloffEnd", 0.01, 1000.0, false) }; public static readonly string[] Names = Array.ConvertAll(Table, ((string Name, double Min, double Max, bool Whole) row) => row.Name); public static readonly ArchetypeTuning None = new ArchetypeTuning(Filled(float.NaN)); private readonly float[] _v; public float this[int index] => _v[index]; public float Damage => _v[0]; public float ShotDelay => _v[1]; public float Cooldown => _v[2]; public float Chargeup => _v[3]; public float Magazine => _v[4]; public float Reload => _v[5]; public float Precision => _v[6]; public float Stagger => _v[7]; public float Pierce => _v[8]; public float AmmoCost => _v[9]; public float FalloffStart => _v[10]; public float FalloffEnd => _v[11]; public bool IsEmpty { get { float[] v = _v; for (int i = 0; i < v.Length; i++) { if (!float.IsNaN(v[i])) { return false; } } return true; } } public ArchetypeTuning(float[] values) { if (values.Length != 12) { throw new ArgumentException("An archetype tuning has " + 12 + " values."); } _v = (float[])values.Clone(); } private static float[] Filled(float value) { float[] array = new float[12]; Array.Fill(array, value); return array; } public static ArchetypeTuning Parse(JsonElement payload) { //IL_00b9: 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) float[] array = new float[12]; for (int i = 0; i < 12; i++) { (string, double, double, bool) tuple = Table[i]; array[i] = ((!payload.TryGetProperty(tuple.Item1, out var _)) ? float.NaN : ((float)(tuple.Item4 ? StrictJson.Integer(payload, "", tuple.Item1, (double?)null, tuple.Item2, tuple.Item3) : StrictJson.Number(payload, "", tuple.Item1, (double?)null, tuple.Item2, tuple.Item3)))); } if (float.IsNaN(array[10]) != float.IsNaN(array[11])) { throw new StrictJsonException("FalloffStart", "is set together with FalloffEnd."); } if (!float.IsNaN(array[10]) && array[11] <= array[10]) { throw new StrictJsonException("FalloffEnd", "must be greater than FalloffStart."); } return new ArchetypeTuning(array); } public static ArchetypeTuning? FromWire(float[] values) { if (values.Length != 12) { return null; } for (int i = 0; i < 12; i++) { float num = values[i]; if (!float.IsNaN(num)) { (string, double, double, bool) tuple = Table[i]; if (!((double)num >= tuple.Item2) || !((double)num <= tuple.Item3) || (tuple.Item4 && Math.Floor(num) != (double)num)) { return null; } } } if (float.IsNaN(values[10]) != float.IsNaN(values[11]) || (!float.IsNaN(values[10]) && values[11] <= values[10])) { return null; } return new ArchetypeTuning(values); } public ArchetypeTuning Over(ArchetypeTuning native) { float[] array = new float[12]; for (int i = 0; i < 12; i++) { array[i] = (float.IsNaN(_v[i]) ? native._v[i] : _v[i]); } return new ArchetypeTuning(array); } public double Rounds(float ammoRatio, float poolMax) { return Math.Floor((double)ammoRatio * (double)poolMax / (double)AmmoCost) + (double)Magazine; } public bool Valid() { float[] v = _v; for (int i = 0; i < v.Length; i++) { if (!float.IsFinite(v[i])) { return false; } } if (ShotDelay > 0f && AmmoCost > 0f) { return Magazine >= 1f; } return false; } public bool SameAs(ArchetypeTuning other) { for (int i = 0; i < 12; i++) { if (_v[i] != other._v[i] && (!float.IsNaN(_v[i]) || !float.IsNaN(other._v[i]))) { return false; } } return true; } } public enum LoanEnd : byte { None, Empty, Dropped, Down } public sealed class HeavyLoan { public const float SettleSeconds = 1.5f; public float StartedAt { get; } public LoanEnd Ended { get; private set; } public HeavyLoan(float startedAt) { StartedAt = startedAt; } public LoanEnd Update(float now, int clip, int reserve, bool dropPressed, bool down) { if (Ended != LoanEnd.None) { return LoanEnd.None; } if (down) { Ended = LoanEnd.Down; } else if (dropPressed) { Ended = LoanEnd.Dropped; } else if (now - StartedAt >= 1.5f && clip <= 0 && reserve <= 0) { Ended = LoanEnd.Empty; } return Ended; } } internal sealed class LauncherLoan { internal const float OriginTolerance = 2.4f; internal readonly Guid Identity = Guid.NewGuid(); internal readonly HeavyWeaponSpec Spec; internal readonly uint GearChecksum; private readonly float _interval; private float _nextShot; private uint _lastShot; internal int Remaining { get; private set; } internal LauncherLoan(HeavyWeaponSpec spec, uint gearChecksum, int ammunition, float interval, float createdAt) { if (spec.Grenade == null || ammunition <= 0 || !float.IsFinite(interval) || interval <= 0f || !float.IsFinite(createdAt)) { throw new ArgumentException("Invalid host launcher budget or cadence."); } Spec = spec; GearChecksum = gearChecksum; Remaining = ammunition; _interval = interval; _nextShot = createdAt; } internal bool TrySchedule(Guid identity, uint sequence, float now, float originDistanceSquared, out float delay, out string reason) { delay = 0f; reason = ((identity != Identity) ? "wrong loan identity" : ((sequence == 0 || sequence <= _lastShot) ? "stale shot identity" : ((!(originDistanceSquared <= 5.76f) || !float.IsFinite(originDistanceSquared)) ? "origin outside host-observed reach" : ((!float.IsFinite(now) || now < 0f) ? "invalid host time" : ((Remaining <= 0) ? "loan ammunition exhausted" : ""))))); if (reason.Length != 0) { return false; } float num = Math.Max(now, _nextShot); float num2 = num + _interval; if (!float.IsFinite(num) || !float.IsFinite(num2)) { reason = "fire schedule overflowed"; return false; } Remaining--; _lastShot = sequence; _nextShot = num2; delay = num - now; return true; } } public sealed class LoanBook { private readonly Dictionary<ulong, (ulong Summoner, uint ThrowId, uint Attempt)> _loans = new Dictionary<ulong, (ulong, uint, uint)>(); private readonly Dictionary<ulong, bool> _stashed = new Dictionary<ulong, bool>(); public bool Any => _loans.Count != 0; public void Commit(ulong summoner, uint throwId, ulong player, uint attempt) { _loans[player] = (summoner, throwId, attempt); } public bool Release(ulong summoner, uint throwId, ulong player, uint attempt) { if (_loans.TryGetValue(player, out (ulong, uint, uint) value)) { (ulong, uint, uint) tuple = value; if (tuple.Item1 == summoner && tuple.Item2 == throwId && tuple.Item3 == attempt) { _stashed.Remove(player); return _loans.Remove(player); } } return false; } public bool Stash(ulong summoner, uint throwId, ulong player, uint attempt) { if (_loans.TryGetValue(player, out (ulong, uint, uint) value)) { (ulong, uint, uint) tuple = value; if (tuple.Item1 == summoner && tuple.Item2 == throwId && tuple.Item3 == attempt) { _stashed.TryAdd(player, value: false); return true; } } return false; } public bool IsStashed(ulong player) { return _stashed.ContainsKey(player); } public bool Observe(ulong player, bool marked) { if (!_stashed.TryGetValue(player, out var value)) { return marked; } if (!marked) { _stashed[player] = true; } else if (value) { _stashed.Remove(player); } return true; } public bool HasLoan(ulong player) { return _loans.ContainsKey(player); } internal void ReconcileLoans(Func<ulong, bool> isStillBorrowing, Action<ulong> released) { List<ulong> list = null; foreach (KeyValuePair<ulong, (ulong, uint, uint)> loan in _loans) { if (!isStillBorrowing(loan.Key)) { (list ?? (list = new List<ulong>())).Add(loan.Key); } } if (list == null) { return; } foreach (ulong item in list) { _loans.Remove(item); _stashed.Remove(item); released(item); } } public void Clear() { _loans.Clear(); _stashed.Clear(); } } public sealed record AmmoStash(float Pool, int Clip); public enum ShellLook : byte { Shell = 1, Bomblet, Canister, Emitter } public readonly struct PlannedShell { public readonly float Right; public readonly float Forward; public readonly float Time; public PlannedShell(float right, float forward, float time) { Right = right; Forward = forward; Time = time; } } public static class StrikePlan { internal struct Lcg { private uint _state; internal Lcg(uint seed) { _state = ((seed == 0) ? 2654435769u : seed); } internal float Next() { _state = _state * 1664525 + 1013904223; return (float)(_state >> 8) / 16777216f; } } public static ShellLook Look(StrikeKind kind) { return kind switch { StrikeKind.Cluster => ShellLook.Bomblet, StrikeKind.Gas => ShellLook.Canister, StrikeKind.Stasis => ShellLook.Emitter, _ => ShellLook.Shell, }; } public static PlannedShell[] Build(StrikeSpec spec, uint seed) { Lcg lcg = new Lcg(seed); switch (spec.Kind) { case StrikeKind.Precision: case StrikeKind.Incendiary: case StrikeKind.Gas: case StrikeKind.Stasis: return new PlannedShell[1] { new PlannedShell(0f, 0f, 0f) }; case StrikeKind.Area: { PlannedShell[] array2 = new PlannedShell[spec.Shells]; for (int j = 0; j < array2.Length; j++) { float x = lcg.Next() * (float)Math.PI * 2f; float num = spec.Spread * MathF.Sqrt(lcg.Next()); float num2 = ((array2.Length == 1) ? 0f : (spec.Duration * (float)j / (float)(array2.Length - 1))); float num3 = ((array2.Length == 1 || j == 0) ? 0f : ((lcg.Next() - 0.5f) * spec.Duration / (float)array2.Length * 0.6f)); array2[j] = new PlannedShell(MathF.Cos(x) * num, MathF.Sin(x) * num, Math.Clamp(num2 + num3, 0f, spec.Duration)); } return array2; } case StrikeKind.Creeping: { PlannedShell[] array3 = new PlannedShell[spec.Rows * spec.Shells]; for (int k = 0; k < spec.Rows; k++) { for (int l = 0; l < spec.Shells; l++) { float num4 = ((spec.Shells == 1) ? 0f : (spec.Width * ((float)l / (float)(spec.Shells - 1) - 0.5f))); float num5 = (lcg.Next() - 0.5f) * 1.2f; array3[k * spec.Shells + l] = new PlannedShell(num4 + num5, (float)k * spec.Length + (lcg.Next() - 0.5f), (float)k * spec.RowInterval + lcg.Next() * 0.25f); } } return array3; } case StrikeKind.Cluster: { PlannedShell[] array = new PlannedShell[spec.Shells]; for (int i = 0; i < array.Length; i++) { float right = ((array.Length == 1) ? 0f : (spec.Length * ((float)i / (float)(array.Length - 1) - 0.5f))); array[i] = new PlannedShell(right, (lcg.Next() - 0.5f) * 1.5f, (array.Length == 1) ? 0f : (spec.Duration * (float)i / (float)(array.Length - 1))); } return array; } default: return Array.Empty<PlannedShell>(); } } public static uint Seed(ulong summoner, uint throwId) { uint num = 2166136261u; for (int i = 0; i < 8; i++) { num ^= (byte)(summoner >> i * 8); num *= 16777619; } for (int j = 0; j < 4; j++) { num ^= (byte)(throwId >> j * 8); num *= 16777619; } return num; } } public static class Targeting { public static int Largest(ReadOnlySpan<float> healthMax, ReadOnlySpan<float> distance) { int num = -1; for (int i = 0; i < healthMax.Length; i++) { if (num < 0 || healthMax[i] > healthMax[num] || (healthMax[i] == healthMax[num] && distance[i] < distance[num])) { num = i; } } return num; } public static int Nearest(ReadOnlySpan<float> distance) { int num = -1; for (int i = 0; i < distance.Length; i++) { if (num < 0 || distance[i] < distance[num]) { num = i; } } return num; } public static int NearestReachable<T>(ReadOnlySpan<float> distance, Span<float> scratch, int budget, ref T probe) where T : IReach { distance.CopyTo(scratch); Span<float> span = scratch.Slice(0, distance.Length); for (int i = 0; i < budget; i++) { int num = Nearest(span); if (num < 0 || float.IsPositiveInfinity(span[num])) { return -1; } if (probe.Reaches(num)) { return num; } span[num] = float.PositiveInfinity; } return -1; } } public enum StrikeKind : byte { Precision = 1, Area, Creeping, Cluster, Incendiary, Gas, Stasis, Beam, Hunter } public sealed class StrikeSpec { private readonly struct Field { internal readonly string Name; internal readonly double Fallback; internal readonly double Min; internal readonly double Max; internal readonly Action<StrikeSpec, double> Set; internal readonly bool Integer; internal Field(string name, double fallback, double min, double max, Action<StrikeSpec, double> set, bool integer = false) { Name = name; Fallback = fallback; Min = min; Max = max; Set = set; Integer = integer; } } public const string TypeName = "arsenal.Strike"; private static readonly Dictionary<StrikeKind, Field[]> Fields = new Dictionary<StrikeKind, Field[]> { [StrikeKind.Precision] = new Field[3] { Damage_(600.0), Blast(5.0), Force_(800.0) }, [StrikeKind.Area] = new Field[6] { Damage_(180.0), Blast(4.5), Force_(500.0), Shells_(7.0), Spread_(15.0), Duration_(5.0) }, [StrikeKind.Creeping] = new Field[8] { Damage_(160.0), Blast(4.5), Force_(500.0), Shells_(3.0), new Field("Rows", 5.0, 1.0, 12.0, delegate(StrikeSpec s, double v) { s.Rows = (int)v; }, integer: true), new Field("Length", 5.0, 1.0, 20.0, delegate(StrikeSpec s, double v) { s.Length = (float)v; }), new Field("Width", 10.0, 0.0, 30.0, delegate(StrikeSpec s, double v) { s.Width = (float)v; }), new Field("RowInterval", 1.2, 0.2, 10.0, delegate(StrikeSpec s, double v) { s.RowInterval = (float)v; }) }, [StrikeKind.Cluster] = new Field[6] { Damage_(90.0), Blast(3.5), Force_(300.0), Shells_(10.0), Duration_(1.5), new Field("Length", 20.0, 1.0, 60.0, delegate(StrikeSpec s, double v) { s.Length = (float)v; }) }, [StrikeKind.Incendiary] = new Field[7] { Damage_(80.0), Blast(3.5), Force_(300.0), Duration_(10.0, 1.0), Tick_(0.5), TickDamage_(3.0), Zone(6.0) }, [StrikeKind.Gas] = new Field[4] { Duration_(12.0, 1.0), Tick_(0.5), TickDamage_(2.5), Zone(7.0) }, [StrikeKind.Stasis] = new Field[3] { Duration_(20.0, 1.0), Zone(8.0), new Field("Slow", 0.35, 0.05, 0.95, delegate(StrikeSpec s, double v) { s.Slow = (float)v; }) }, [StrikeKind.Beam] = new Field[5] { Duration_(10.0, 1.0), Tick_(0.2), TickDamage_(6.0), Spread_(18.0), Speed_(4.0) }, [StrikeKind.Hunter] = new Field[5] { Damage_(2000.0, 50000.0), Blast(3.0), Force_(800.0), Spread_(25.0), TickDamage_(60.0) } }; private static readonly string[] KindFields = new string[2] { "Type", "Kind" }; public StrikeKind Kind { get; internal set; } public float Damage { get; internal set; } public float BlastRadius { get; internal set; } public float Force { get; internal set; } public int Shells { get; internal set; } public float Spread { get; internal set; } public float Duration { get; internal set; } public int Rows { get; internal set; } public float Length { get; internal set; } public float Width { get; internal set; } public float RowInterval { get; internal set; } public float Tick { get; internal set; } public float TickDamage { get; internal set; } public float ZoneRadius { get; internal set; } public float Speed { get; internal set; } public float Slow { get; internal set; } private static Field Damage_(double d, double max = 20000.0) { return new Field("Damage", d, 0.0, max, delegate(StrikeSpec s, double v) { s.Damage = (float)v; }); } private static Field Blast(double d) { return new Field("BlastRadius", d, 0.5, 30.0, delegate(StrikeSpec s, double v) { s.BlastRadius = (float)v; }); } private static Field Force_(double d) { return new Field("Force", d, 0.0, 5000.0, delegate(StrikeSpec s, double v) { s.Force = (float)v; }); } private static Field Shells_(double d) { return new Field("Shells", d, 1.0, 32.0, delegate(StrikeSpec s, double v) { s.Shells = (int)v; }, integer: true); } private static Field Spread_(double d) { return new Field("Spread", d, 0.0, 60.0, delegate(StrikeSpec s, double v) { s.Spread = (float)v; }); } private static Field Duration_(double d, double min = 0.0) { return new Field("Duration", d, min, 120.0, delegate(StrikeSpec s, double v) { s.Duration = (float)v; }); } private static Field Tick_(double d) { return new Field("Tick", d, 0.1, 5.0, delegate(StrikeSpec s, double v) { s.Tick = (float)v; }); } private static Field TickDamage_(double d) { return new Field("TickDamage", d, 0.0, 2000.0, delegate(StrikeSpec s, double v) { s.TickDamage = (float)v; }); } private static Field Speed_(double d) { return new Field("Speed", d, 0.5, 20.0, delegate(StrikeSpec s, double v) { s.Speed = (float)v; }); } private static Field Zone(double d) { return new Field("ZoneRadius", d, 0.5, 30.0, delegate(StrikeSpec s, double v) { s.ZoneRadius = (float)v; }); } public static StrikeSpec Parse(JsonElement payload) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (payload.ValueKind != JsonValueKind.Object) { throw new StrictJsonException("Payload", "must be an object."); } StrikeKind strikeKind = StrictJson.Enum<StrikeKind>(payload, "", "Kind"); Field[] array = Fields[strikeKind]; StrictJson.OnlyKnown(payload, "", Array.ConvertAll(array, (Field f) => f.Name), KindFields, strikeKind.ToString()); StrikeSpec strikeSpec = new StrikeSpec { Kind = strikeKind }; Field[] array2 = array; for (int num = 0; num < array2.Length; num++) { Field field = array2[num]; field.Set(strikeSpec, field.Integer ? StrictJson.Integer(payload, "", field.Name, (double?)field.Fallback, field.Min, field.Max) : StrictJson.Number(payload, "", field.Name, (double?)field.Fallback, field.Min, field.Max)); } return strikeSpec; } } public static class StrikeTiming { public const float FallSeconds = 1.8f; public const float DebrisDelay = 0.5f; public const float IgniteDelay = 0.2f; public const float BeamChargeSeconds = 1.5f; public static float ZoneStartDelay(StrikeKind kind) { switch (kind) { case StrikeKind.Incendiary: case StrikeKind.Gas: return 0.8f; case StrikeKind.Stasis: return 1f; default: return 0f; } } } public enum DataTag : byte { Shell = 1, Zone = 2, Beam = 3, BeamEnd = 4, ZoneEnd = 6, Rack = 7, RackUnavailable = 10 } public readonly struct RackRecord { public readonly HeavyWeaponSpec Spec; public readonly uint GearId; public readonly float X; public readonly float Y; public readonly float Z; public readonly float Yaw; public readonly string Id; public RackRecord(HeavyWeaponSpec spec, uint gearId, float x, float y, float z, float yaw, string id) { Spec = spec; GearId = gearId; X = x; Y = y; Z = z; Yaw = yaw; Id = id; } } public readonly struct ShellRecord { public readonly ShellLook Look; public readonly StrikeKind Kind; public readonly float X; public readonly float Y; public readonly float Z; public readonly float Top; public readonly float Fall; public readonly float Blast; public ShellRecord(ShellLook look, StrikeKind kind, float x, float y, float z, float top, float fall, float blast) { Look = look; Kind = kind; X = x; Y = y; Z = z; Top = top; Fall = fall; Blast = blast; } } public readonly struct ZoneRecord { public readonly StrikeKind Kind; public readonly float X; public readonly float Y; public readonly float Z; public readonly float Radius; public readonly float Seconds; public readonly float Slow; public ZoneRecord(StrikeKind kind, float x, float y, float z, float radius, float seconds, float slow = 1f) { Kind = kind; X = x; Y = y; Z = z; Radius = radius; Seconds = seconds; Slow = slow; } } public readonly struct BeamRecord { public readonly Guid Generation; public readonly float OX; public readonly float OY; public readonly float OZ; public readonly float TX; public readonly float TY; public readonly float TZ; public readonly bool HasTarget; public BeamRecord(Guid generation, float ox, float oy, float oz, float tx, float ty, float tz, bool hasTarget) { Generation = generation; OX = ox; OY = oy; OZ = oz; TX = tx; TY = ty; TZ = tz; HasTarget = hasTarget; } } public static class Wire { public const int ShellBytes = 26; public const int ZoneBytes = 25; public const int BeamBytes = 41; public const int RackBytes = 88; public const int MaxDataBytes = 192; public static byte[] Shell(in ShellRecord r) { byte[] array = new byte[26]; array[0] = (byte)r.Look; array[1] = (byte)r.Kind; Put(array.AsSpan(2), 0, r.X); Put(array.AsSpan(2), 1, r.Y); Put(array.AsSpan(2), 2, r.Z); Put(array.AsSpan(2), 3, r.Top); Put(array.AsSpan(2), 4, r.Fall); Put(array.AsSpan(2), 5, r.Blast); return array; } public static bool TryShell(byte[] b, out ShellRecord r) { r = default(ShellRecord); if (b.Length != 26 || !Enum.IsDefined(typeof(ShellLook), b[0]) || !Enum.IsDefined(typeof(StrikeKind), b[1])) { return false; } Span<byte> span = b.AsSpan(2); r = new ShellRecord((ShellLook)b[0], (StrikeKind)b[1], F(span, 0), F(span, 1), F(span, 2), F(span, 3), F(span, 4), F(span, 5)); if (float.IsFinite(r.X) && float.IsFinite(r.Y) && float.IsFinite(r.Z) && float.IsFinite(r.Top) && float.IsFinite(r.Fall) && float.IsFinite(r.Blast) && r.Fall >= 0f) { return r.Fall < 30f; } return false; } public static byte[] Zone(in ZoneRecord r) { byte[] array = new byte[25]; array[0] = (byte)r.Kind; Put(array.AsSpan(1), 0, r.X); Put(array.AsSpan(1), 1, r.Y); Put(array.AsSpan(1), 2, r.Z); Put(array.AsSpan(1), 3, r.Radius); Put(array.AsSpan(1), 4, r.Seconds); Put(array.AsSpan(1), 5, r.Slow); return array; } public static bool TryZone(byte[] b, out ZoneRecord r) { r = default(ZoneRecord); if (b.Length != 25 || !Enum.IsDefined(typeof(StrikeKind), b[0])) { return false; } Span<byte> span = b.AsSpan(1); r = new ZoneRecord((StrikeKind)b[0], F(span, 0), F(span, 1), F(span, 2), F(span, 3), F(span, 4), F(span, 5)); if (float.IsFinite(r.X) && float.IsFinite(r.Y) && float.IsFinite(r.Z) && float.IsFinite(r.Radius) && float.IsFinite(r.Seconds) && r.Radius > 0f && r.Seconds > 0f && r.Seconds <= 600f && r.Slow > 0f) { return r.Slow <= 1f; } return false; } public static byte[] Beam(in BeamRecord r) { byte[] array = new byte[41]; array[0] = (r.HasTarget ? ((byte)1) : ((byte)0)); Put(array.AsSpan(1), 0, r.OX); Put(array.AsSpan(1), 1, r.OY); Put(array.AsSpan(1), 2, r.OZ); Put(array.AsSpan(1), 3, r.TX); Put(array.AsSpan(1), 4, r.TY); Put(array.AsSpan(1), 5, r.TZ); r.Generation.TryWriteBytes(array.AsSpan(25)); return array; } public static bool TryBeam(byte[] b, out BeamRecord r) { r = default(BeamRecord); if (b.Length != 41 || b[0] > 1) { return false; } Span<byte> span = b.AsSpan(1); r = new BeamRecord(new Guid(b.AsSpan(25)), F(span, 0), F(span, 1), F(span, 2), F(span, 3), F(span, 4), F(span, 5), b[0] == 1); if (r.Generation != Guid.Empty) { if (float.IsFinite(r.OX) && float.IsFinite(r.OY) && float.IsFinite(r.OZ) && float.IsFinite(r.TX) && float.IsFinite(r.TY)) { return float.IsFinite(r.TZ); } return false; } return false; } public static byte[] Rack(in RackRecord r) { byte[] array = Utf8Prefix(r.Id, 104); byte[] array2 = new byte[88 + array.Length]; BinaryPrimitives.WriteUInt32LittleEndian(array2.AsSpan(0, 4), r.Spec.ModelHash); BinaryPrimitives.WriteUInt32LittleEndian(array2.AsSpan(4, 4), r.GearId); Put(array2.AsSpan(8), 0, r.Spec.AmmoRatio); Put(array2.AsSpan(8), 1, r.Spec.Grenade?.Damage ?? 0f); Put(array2.AsSpan(8), 2, r.Spec.Grenade?.Radius ?? 0f); Put(array2.AsSpan(8), 3, r.Spec.Grenade?.Speed ?? 0f); Put(array2.AsSpan(8), 4, r.X); Put(array2.AsSpan(8), 5, r.Y); Put(array2.AsSpan(8), 6, r.Z); Put(array2.AsSpan(8), 7, r.Yaw); for (int i = 0; i < 12; i++) { Put(array2.AsSpan(8), 8 + i, r.Spec.Tuning[i]); } array.CopyTo(array2, 88); return array2; } public static bool TryRack(byte[] b, out RackRecord r) { r = default(RackRecord); if (b.Length < 88 || b.Length > 192) { return false; } Span<byte> span = b.AsSpan(8); float num = F(span, 4); float num2 = F(span, 5); float num3 = F(span, 6); float num4 = F(span, 7); if (!float.IsFinite(num) || !float.IsFinite(num2) || !float.IsFinite(num3) || !float.IsFinite(num4)) { return false; } if (!HeavyModels.TryId(BinaryPrimitives.ReadUInt32LittleEndian(b.AsSpan(0, 4)), out string id)) { return false; } uint gearId = BinaryPrimitives.ReadUInt32LittleEndian(b.AsSpan(4, 4)); float num5 = F(span, 1); float num6 = F(span, 2); float num7 = F(span, 3); GrenadeSpec grenade = ((num5 == 0f && num6 == 0f && num7 == 0f) ? null : new GrenadeSpec(num5, num6, num7)); HeavyWeaponSpec heavyWeaponSpec = HeavyWeaponSpec.Restore(id, gearId, F(span, 0), grenade, ArchetypeTuning.FromWire(Tuned(span))); if (heavyWeaponSpec == null) { return false; } string id2; try { id2 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(b, 88, b.Length - 88); } catch (ArgumentException) { return false; } r = new RackRecord(heavyWeaponSpec, gearId, num, num2, num3, num4, id2); return true; } public static bool UnknownRackModel(byte[] b, out uint hash) { hash = 0u; if (b.Length < 88 || b.Length > 192) { return false; } hash = BinaryPrimitives.ReadUInt32LittleEndian(b.AsSpan(0, 4)); string id; return !HeavyModels.TryId(hash, out id); } private static byte[] Utf8Prefix(string text, int limit) { byte[] bytes = Encoding.UTF8.GetBytes(text); if (bytes.Length <= limit) { return bytes; } int num = limit; while (num > 0 && (bytes[num] & 0xC0) == 128) { num--; } return bytes.AsSpan(0, num).ToArray(); } private static float[] Tuned(ReadOnlySpan<byte> s) { float[] array = new float[12]; for (int i = 0; i < array.Length; i++) { array[i] = F(s, 8 + i); } return array; } private static void Put(Span<byte> into, int index, float value) { BinaryPrimitives.WriteSingleLittleEndian(into.Slice(index * 4, 4), value); } private static float F(ReadOnlySpan<byte> s, int index) { return BinaryPrimitives.ReadSingleLittleEndian(s.Slice(index * 4, 4)); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LoanNotice { public const string Name = "Loan"; public ulong Summoner; public uint ThrowId; public uint Attempt; public LoanAction Action; } public enum LoanAction : byte { Returned, Stashed } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct GrenadeShot { public const string Name = "Grenade"; public ulong Shooter; public Guid Loan; public uint Sequence; public float OX; public float OY; public float OZ; public float VX; public float VY; public float VZ; public float Damage; public float Radius; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct GrenadeBurst { public const string Name = "GrenadeBurst"; public ulong Shooter; public Guid Loan; public uint Sequence; public float X; public float Y; public float Z; } internal static class ArsenalArt { internal const string BundleFile = "forge-ordnance-arsenal.bundle"; internal const string Pack = "Arsenal"; internal static readonly Quaternion FrontToForward = Quaternion.Euler(0f, 180f, 0f); internal static readonly Quaternion NoseDown = Quaternion.Euler(-90f, 0f, 0f); private static bool _tried; private static BundleHandle? _pack; internal static ModelHandle? Shell; internal static ModelHandle? Bomblet; internal static ModelHandle? Canister; internal static ModelHandle? Emitter; private static readonly Dictionary<string, ModelHandle> Weapons = new Dictionary<string, ModelHandle>(StringComparer.Ordinal); internal static BundleHandle? Bundle { get; private set; } internal static ArsenalSheets? Sheets { get; private set; } internal static string Failure { get; private set; } = "the level has not been built yet"; internal static void Register() { try { string text = Path.Combine(Path.GetDirectoryName(typeof(ArsenalArt).Assembly.Location) ?? throw new InvalidOperationException("The plugin folder is unknown."), "forge-ordnance-arsenal.bundle"); if (!File.Exists(text)) { throw new FileNotFoundException("Install forge-ordnance-arsenal.bundle next to ForgeOrdnanceArsenal.dll.", text); } BundleHandle pack = Bundles.Register("NAinfini.ForgeOrdnanceArsenal", "Arsenal", text) ?? throw new InvalidDataException("ForgeVisual refused forge-ordnance-arsenal.bundle (see its error above)."); Shell = Model("shell"); Bomblet = Model("bomblet"); Canister = Model("gas-canister"); Emitter = Model("stasis-emitter"); _pack = pack; ArsenalTurrets.Register(Model); ModelHandle Model(string name) { ModelHandle result = default(ModelHandle); if (!pack.TryModel(name, ref result)) { throw new InvalidDataException("forge-ordnance-arsenal.bundle has no model " + name + "."); } return result; } } catch (Exception ex) { Failure = ex.ToString(); Plugin.Error("Arsenal art could not be registered; strikes, heavy weapons and turrets work without their models and effect looks: " + ex); } } internal static void Load() { if (_tried) { return; } _tried = true; if (_pack == null) { return; } try { BundleHandle bundle = _pack; Sheets = new ArsenalSheets { Smoke = Sheet("smoke", "vfx-smoke", 5, 3, (FxBlend)0, sheddable: true), Blast = Sheet("blast", "vfx-blast", 5, 5, (FxBlend)0), Fireball = Sheet("fireball", "vfx-fireball", 8, 8, (FxBlend)1), Flash = Sheet("flash", "vfx-flash", 8, 8, (FxBlend)1), Flame = Sheet("flame", "vfx-flame", 16, 4, (FxBlend)1), Flare = Sheet("flare", "vfx-flare", 1, 1, (FxBlend)1), Ring = Sheet("ring", "vfx-ring", 1, 1, (FxBlend)1), Scorch = Sheet("scorch", "vfx-scorch", 1, 1, (FxBlend)0), Streak = Sheet("streak", "vfx-streak", 1, 1, (FxBlend)1), Glow = Sheet("glow", "vfx-glow", 1, 1, (FxBlend)1), Mist = Sheet("mist", "vfx-mist", 2, 2, (FxBlend)0), Fire = Sheet("fire", "vfx-fire", 2, 2, (FxBlend)0), Spark = Sheet("spark", "vfx-spark", 1, 1, (FxBlend)0) }; Bundle = bundle; Failure = ""; SpriteSheet Sheet(string item, string texture, int columns, int rows, FxBlend blend, bool sheddable = false) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) Texture2D val = default(Texture2D); if (!bundle.TryTexture(texture, ref val)) { throw new InvalidDataException("forge-ordnance-arsenal.bundle has no effect texture " + texture + "."); } return SpriteSheet.Register("NAinfini.ForgeOrdnanceArsenal", "Arsenal:" + item, val, columns, rows, blend, sheddable, 0) ?? throw new InvalidDataException("ForgeVisual refused the sprite sheet Arsenal:" + item + " (see its error above)."); } } catch (Exception ex) { Sheets = null; Failure = ex.ToString(); Plugin.Error("Arsenal art could not be loaded; strikes and heavy weapons work without their models and effect looks: " + ex); return; } try { StrikeBursts.Prepare(); } catch (Exception ex2) { Plugin.Error("Building the strike effects at level load failed; they are built at the first strike instead: " + ex2); } } internal static ModelHandle? Look(ShellLook look) { return (ModelHandle?)(look switch { ShellLook.Bomblet => Bomblet, ShellLook.Canister => Canister, ShellLook.Emitter => Emitter, _ => Shell, }); } internal static string? CheckWeaponModel(string id) { if (Weapons.ContainsKey(id)) { return null; } ModelHandle val = Models.Get(id); if (val == null) { return "no ForgeVisual model " + id + " is registered (its pack must be registered in its plugin's Load)."; } string[] array = new string[3] { "RightHand", "LeftHand", "SightLook" }; foreach (string text in array) { if ((Object)(object)Models.Find(val.Prefab.transform, text) == (Object)null) { return "the model " + id + " has no " + text + " child (a heavy weapon model needs RightHand, LeftHand and SightLook)."; } } Weapons.Add(id, val); return null; } internal static ModelHandle? Weapon(string id) { if (!Weapons.TryGetValue(id, out ModelHandle value)) { return null; } return value; } } internal sealed class ArsenalSheets { internal SpriteSheet Smoke; internal SpriteSheet Blast; internal SpriteSheet Fireball; internal SpriteSheet Flash; internal SpriteSheet Flame; internal SpriteSheet Flare; internal SpriteSheet Ring; internal SpriteSheet Scorch; internal SpriteSheet Streak; internal SpriteSheet Glow; internal SpriteSheet Mist; internal SpriteSheet Fire; internal SpriteSheet Spark; internal SpriteSheet[] All => (SpriteSheet[])(object)new SpriteSheet[13] { Smoke, Blast, Fireball, Flash, Flame, Flare, Ring, Scorch, Streak, Glow, Mist, Fire, Spark }; } internal static class ArsenalAudio { internal static class Cue { internal const string Incoming = "strike.incoming_shell"; internal const string SmallBoom = "strike.small_boom"; internal const string BigBoom = "strike.big_boom"; internal const string Debris = "strike.debris"; internal const string ClusterSplit = "strike.cluster_split"; internal const string FireIgnite = "strike.fire_ignite"; internal const string FireLoop = "strike.fire_loop"; internal const string GasRelease = "strike.gas_release"; internal const string GasLoop = "strike.gas_loop"; internal const string StasisPulse = "strike.stasis_pulse"; internal const string StasisLoop = "strike.stasis_loop"; internal const string BeamStart = "strike.beam_start"; internal const string BeamLoop = "strike.beam_loop"; internal const string BeamCutting = "strike.beam_cutting"; internal const string BeamEnd = "strike.beam_end"; internal const string Handover = "weapon.handover"; internal const string GrenadeFire = "weapon.grenade_fire"; internal const string GrenadeReload = "weapon.grenade_reload"; internal const string GrenadeBurst = "weapon.grenade_burst"; internal const string WeaponReturn = "weapon.return"; internal const string TurretDeploy = "turret.deploy"; internal const string TurretIdle = "turret.idle"; internal const string TurretExpire = "turret.expire"; } private static AudioLibrary? _sounds; internal static AudioLibrary? Sounds => _sounds; internal static void Register() { if (_sounds == null) { _sounds = AudioKit.Load("NAinfini.ForgeOrdnanceArsenal", (string)null); } } internal static void Dispose() { AudioLibrary? sounds = _sounds; if (sounds != null) { sounds.Dispose(); } _sounds = null; } internal static void PlayReturn(GameObject owner, int dimension) { //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) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) AudioLibrary? sounds = _sounds; if (sounds != null) { PlayOptions val = new PlayOptions(); val.set_IsSelf(true); val.set_Dimension((int?)dimension); sounds.Play("weapon.return", owner, val); } } internal static void PlayAt(string cue, Vector3 position) { //IL_000b: 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) AudioLibrary? sounds = _sounds; if (sounds != null) { sounds.Play(cue, position, (PlayOptions)null); } } internal static bool Prewarm() { AudioLibrary? sounds = _sounds; if (sounds == null) { return true; } return sounds.Prewarm(); } internal static void PlayAttached(string cue, GameObject owner, int dimension, bool isSelf = false) { //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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) AudioLibrary? sounds = _sounds; if (sounds != null) { PlayOptions val = new PlayOptions(); val.set_IsSelf(isSelf); val.set_Dimension((int?)dimension); sounds.Play(cue, owner, val); } } internal static void PlayOn(string cue, GameObject owner) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) AudioLibrary? sounds = _sounds; if (sounds != null) { sounds.Play(cue, owner, (PlayOptions)null); } } internal static void PlayLoop(string cue, GameObject owner) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) AudioLibrary? sounds = _sounds; if (sounds != null) { sounds.Play(cue, owner, (PlayOptions)null); } } } internal static class ArsenalKeys { internal static KeyAction Drop; internal static void Register() { Drop = UIKit.Mod("NAinfini.ForgeOrdnanceArsenal").AddKeyAction("DropHeavyWeapon", "keys.drop", "keys.group", "G", (KeyMode)0, "on-foot") ?? throw new InvalidOperationException("ForgeUI refused the key action DropHeavyWeapon; see its error."); } } internal static class ArsenalNetwork { private const int InboxLimit = 256; private static NetChannel? _channel; private static NetChannel Channel => _channel ?? throw new InvalidOperationException("Arsenal's network channel is not open."); internal static void Register() { _channel = Net.Open("NAinfini.ForgeOrdnanceArsenal", 256); _channel.On<LoanNotice>("Loan", (Action<ulong, LoanNotice>)HeavyWeapons.OnLoanNotice); _channel.On<GrenadeShot>("Grenade", (Action<ulong, GrenadeShot>)Grenades.OnShot); _channel.On<GrenadeBurst>("GrenadeBurst", (Action<ulong, GrenadeBurst>)Grenades.OnBurst); } internal static void Clear() { NetChannel? channel = _channel; if (channel != null) { channel.Clear(); } } internal static void Pump() { NetChannel? channel = _channel; if (channel != null) { channel.Pump(); } } internal static void ToHost<T>(string name, T message) where T : unmanaged { Channel.TryToHost<T>(name, message); } internal static void Broadcast<T>(string name, T message) where T : unmanaged { Channel.Broadcast<T>(name, message); } internal static bool IsPlayer(ulong lookup) { SNet_Player val = default(SNet_Player); if (SNet.TryGetPlayer(lookup, ref val) && (Object)(object)val != (Object)null) { return !val.IsBot; } return false; } } internal static class ArsenalText { private static readonly UIKitMod Ui = UIKit.Mod("NAinfini.ForgeOrdnanceArsenal"); private static UITexts? _definitions; private static readonly HashSet<string> NamedMarkers = new HashSet<string>(StringComparer.Ordinal); private static UITexts Definitions => _definitions ?? (_definitions = UIKit.Texts(Path.Combine(Path.GetDirectoryName(typeof(ArsenalText).Assembly.Location) ?? ".", "ForgeOrdnance", "lang"))); internal static int Version => UITexts.Version; internal static string T(string key) { return Ui.Text(key); } internal static string T(string key, params object?[] args) { return Ui.Text(key, args); } internal static string CallIn(string id) { string result = default(string); if (!Definitions.TryText(id + ".Name", ref result)) { return id; } return result; } internal static void NameHeavyWeapons() { string text3 = default(string); foreach (OrdnanceDefinition definition in OrdnanceApi.Definitions) { if (!(definition.Parameters is HeavyParameters heavyParameters)) { continue; } string text = HeavyModels.Marker(heavyParameters.Spec.ModelHash); if (!NamedMarkers.Add(text)) { continue; } string text2 = definition.Id + ".Name"; if (Definitions.TryText(text2, ref text3)) { UIKit.GearName(Definitions, text, text2); continue; } UIKit.GearName(text, (Func<string>)(() => OrdnanceApi.DisplayName(definition))); } } } internal static class ArsenalTurrets { internal const string Burst = "Arsenal:turret-burst"; internal const string Sniper = "Arsenal:turret-sniper"; internal const string Shotgun = "Arsenal:turret-shotgun"; private const string Prefix = "Arsenal:"; private const string Pack = "Arsenal"; private static readonly (string Id, string Model, float Scale)[] Looks = new(string, string, float)[3] { ("Arsenal:turret-burst", "turret-burst", 1.24f), ("Arsenal:turret-sniper", "turret-sniper", 1.14f), ("Arsenal:turret-shotgun", "turret-shotgun", 1.05f) }; private static readonly Dictionary<IntPtr, AudioSustain> Humming = new Dictionary<IntPtr, AudioSustain>(); internal static void Register(Func<string, ModelHandle> model) { //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_0040: Expected O, but got Unknown (string, string, float)[] looks = Looks; for (int i = 0; i < looks.Length; i++) { var (text, arg, worldScale) = looks[i]; OrdnanceTurrets.RegisterLook(text, model(arg), new TurretLookSpec { WorldScale = worldScale }); } OrdnanceTurrets.Deployed += OnDeployed; OrdnanceTurrets.Online += OnOnline; OrdnanceTurrets.Expiring += OnExpiring; } private static bool Ours(string lookId) { return lookId.StartsWith("Arsenal:", StringComparison.Ordinal); } private static void OnDeployed(string lookId, Transform shell) { if (Ours(lookId)) { ArsenalAudio.PlayOn("turret.deploy", ((Component)shell).gameObject); } } private static void OnOnline(string lookId, SentryGunInstance sentry, Transform at) { if (!Ours(lookId) || (Humming.TryGetValue(((Il2CppObjectBase)sentry).Pointer, out AudioSustain value) && value.IsActive)) { return; } AudioLibrary? sounds = ArsenalAudio.Sounds; string text = default(string); AudioSustain val = ((sounds != null) ? sounds.Sustain("turret.idle", ((Component)sentry).gameObject, (PlayOptions)null, (Func<bool>)(() => OrdnanceTurrets.TryLook(sentry, ref text))) : null); if (val == null || !val.IsActive) { return; } foreach (IntPtr item in new List<IntPtr>(Humming.Keys)) { if (!Humming[item].IsActive) { Humming.Remove(item); } } Humming[((Il2CppObjectBase)sentry).Pointer] = val; } private static void OnExpiring(string lookId, SentryGunInstance sentry, Vector3 at) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (Ours(lookId)) { ArsenalAudio.PlayAt("turret.expire", at); } } internal static void Clear() { Humming.Clear(); } } internal static class Grenades { private sealed class Flight { internal ulong Shooter; internal Guid Loan; internal uint Sequence; internal Vector3 Position; internal Vector3 Velocity; internal float Damage; internal float Radius; internal float Ends; internal GameObject? Look; } private const float Gravity = 9.81f; private const float Lifetime = 6f; private const float Spawn = 0.7f; private static bool _suppress; private static uint _nextShot; private static FxHandle? _explosion; private static readonly List<Flight> Flights = new List<Flight>(); private static readonly List<(GrenadeShot Shot, float At)> Pending = new List<(GrenadeShot, float)>(); private static readonly Dictionary<(ulong, Guid, uint), float> Settled = new Dictionary<(ulong, Guid, uint), float>(); private static readonly List<(ulong, Guid, uint)> Expired = new List<(ulong, Guid, uint)>(); internal static bool Suppressing => _suppress; internal static void BeforeFire(BulletWeapon weapon) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 if (!(HeavyWeapons.ActiveLauncher == null) && !((Object)(object)((Item)weapon).Owner == (Object)null) && ((Agent)((Item)weapon).Owner).IsLocallyOwned) { ItemDataBlock itemDataBlock = ((Item)weapon).ItemDataBlock; if (itemDataBlock != null && (int)itemDataBlock.inventorySlot == 2) { _suppress = true; } } } internal static void AfterFire(BulletWeapon weapon) { //IL_0076: 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_009a: 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_00be: 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) if (!_suppress) { return; } _suppress = false; HeavyParameters activeLauncher = HeavyWeapons.ActiveLauncher; PlayerAgent owner = ((Item)weapon).Owner; if (!(activeLauncher == null) && !((Object)(object)owner == (Object)null)) { Transform transform = ((Component)owner.FPSCamera).transform; GrenadeShot grenadeShot = new GrenadeShot { Shooter = SNet.LocalPlayer.Lookup, Loan = HeavyWeapons.ActiveLauncherIdentity, Sequence = ++_nextShot, OX = transform.position.x, OY = transform.position.y, OZ = transform.position.z, VX = transform.forward.x, VY = transform.forward.y, VZ = transform.forward.z }; if (SNet.IsMaster) { OnShot(SNet.LocalPlayer.Lookup, grenadeShot); return; } GrenadeShot s = grenadeShot; float speed = activeLauncher.Spec.Grenade.Speed; s.VX *= speed; s.VY = s.VY * speed + 1.5f; s.VZ *= speed; Launch(s); ArsenalNetwork.ToHost("Grenade", grenadeShot); } } internal static void OnShot(ulong sender, GrenadeShot shot) { if (SNet.IsMaster) { if (HeavyWeapons.AuthorizeGrenade(sender, ref shot, out float delay, out string _)) { if (delay > 0f) { Pending.Add((shot, Time.time + delay)); } else { LaunchHost(shot); } } } else if (!((Object)(object)SNet.Master == (Object)null) && sender == SNet.Master.Lookup) { RemoveFlight(shot.Shooter, shot.Loan, shot.Sequence); if (!Settled.ContainsKey((shot.Shooter, shot.Loan, shot.Sequence))) { Launch(shot); } } } private static void LaunchHost(GrenadeShot shot) { ArsenalNetwork.Broadcast("Grenade", shot); Launch(shot); } private static void Launch(GrenadeShot s) { //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_0059: 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_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_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_00fa: 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) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: 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_0163: 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_01aa: 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_017a: 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_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_012b: 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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) Flight flight = new Flight { Shooter = s.Shooter, Loan = s.Loan, Sequence = s.Sequence, Position = new Vector3(s.OX, s.OY, s.OZ), Velocity = new Vector3(s.VX, s.VY, s.VZ), Damage = s.Damage, Radius = s.Radius, Ends = Time.time + 6f }; if (!float.IsFinite(flight.Position.x + flight.Position.y + flight.Position.z + flight.Velocity.x + flight.Velocity.y + flight.Velocity.z)) { return; } Vector3 val = flight.Velocity - Vector3.up * 1.5f; Vector3 normalized = ((Vector3)(ref val)).normalized; RaycastHit val2 = default(RaycastHit); if (SNet.IsMaster && Physics.Raycast(flight.Position, normalized, ref val2, 0.7f, LayerManager.MASK_WORLD | LayerManager.MASK_ENEMY_DAMAGABLE, (QueryTriggerInteraction)1)) { Burst(flight, ((RaycastHit)(ref val2)).point + ((RaycastHit)(ref val2)).normal * 0.1f); return; } flight.Position += normalized * 0.7f; ModelHandle bomblet = ArsenalArt.Bomblet; if (bomblet != null) { flight.Look = bomblet.Spawn(flight.Position, Quaternion.LookRotation(flight.Velocity) * ArsenalArt.FrontToForward, (Transform)null); } Flights.Add(flight); ArsenalAudio.PlayAt("weapon.grenade_fire", flight.Position); } internal static void Tick(float now) { //IL_011d: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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_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_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: 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_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0274: 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_0237: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: 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_02d9: Unknown result type (might be due to invalid IL or missing references) int num = 0; while (num < Pending.Count) { (GrenadeShot, float) tuple = Pending[num]; if (now < tuple.Item2) { num++; continue; } Pending.RemoveAt(num); if (SNet.IsMaster) { LaunchHost(tuple.Item1); } } Expired.Clear(); foreach (KeyValuePair<(ulong, Guid, uint), float> item in Settled) { if (now >= item.Value) { Expired.Add(item.Key); } } foreach (var item2 in Expired) { Settled.Remove(item2); } if (Flights.Count == 0) { return; } float deltaTime = Time.deltaTime; int num2 = LayerManager.MASK_WORLD | LayerManager.MASK_ENEMY_DAMAGABLE; RaycastHit val4 = default(RaycastHit); for (int num3 = Flights.Count - 1; num3 >= 0; num3--) { Flight flight = Flights[num3]; try { Vector3 val = flight.Position + flight.Velocity * deltaTime; flight.Velocity += Vector3.down * (9.81f * deltaTime); Vector3 val2 = val - flight.Position; if (!SNet.IsMaster && now >= flight.Ends + 2f) { Flights.RemoveAt(num3); if ((Object)(object)flight.Look != (Object)null && !((Il2CppObjectBase)flight.Look).WasCollected) { Object.Destroy((Object)(object)flight.Look); } Plugin.Error("Grenade settlement timed out for " + flight.Shooter + "/" + flight.Sequence + "; projectile removed without a predicted explosion."); } else { bool flag = SNet.IsMaster && now >= flight.Ends; Vector3 val3 = val; if (SNet.IsMaster && !flag && Physics.Raycast(flight.Position, ((Vector3)(ref val2)).normalized, ref val4, ((Vector3)(ref val2)).magnitude, num2, (QueryTriggerInteraction)1)) { flag = true; val3 = ((RaycastHit)(ref val4)).point + ((RaycastHit)(ref val4)).normal * 0.1f; } flight.Position = val3; if ((Object)(object)flight.Look != (Object)null && !((Il2CppObjectBase)flight.Look).WasCollected) { flight.Look.transform.position = val3; if (((Vector3)(ref flight.Velocity)).sqrMagnitude > 0.01f) { flight.Look.transform.rotation = Quaternion.LookRotation(flight.Velocity) * ArsenalArt.FrontToForward; } } if (flag) { Burst(flight, val3); Flights.RemoveAt(num3); } } } catch (Exception ex) { Flights.RemoveAt(num3); if ((Object)(object)flight.Look != (Object)null && !((Il2CppObjectBase)flight.Look).WasCollected) { Object.Destroy((Object)(object)flight.Look); } Plugin.Error("A grenade failed: " + ex); } } } private static void Burst(Flight f, Vector3 at) { //IL_0026: 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_00b2: 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_00d0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)f.Look != (Object)null && !((Il2CppObjectBase)f.Look).WasCollected) { Object.Destroy((Object)(object)f.Look); } Combat.Explode(at, f.Radius, f.Damage, 600f); Settled[(f.Shooter, f.Loan, f.Sequence)] = Time.time + 6f + 2f; ArsenalNetwork.Broadcast("GrenadeBurst", new GrenadeBurst { Shooter = f.Shooter, Loan = f.Loan, Sequence = f.Sequence, X = at.x, Y = at.y, Z = at.z }); ShowBurst(at); } internal static void OnBurst(ulong sender, GrenadeBurst burst) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (!SNet.IsMaster && !((Object)(object)SNet.Master == (Object)null) && sender == SNet.Master.Lookup && burst.Shooter != 0L && !(burst.Loan == Guid.Empty) && burst.Sequence != 0 && float.IsFinite(burst.X) && float.IsFinite(burst.Y) && float.IsFinite(burst.Z)) { (ulong, Guid, uint) key = (burst.Shooter, burst.Loan, burst.Sequence); if (Settled.TryAdd(key, Time.time + 6f + 2f)) { RemoveFlight(burst.Shooter, burst.Loan, burst.Sequence); ShowBurst(new Vector3(burst.X, burst.Y, burst.Z)); } } } private static void RemoveFlight(ulong shooter, Guid loan, uint sequence) { for (int num = Flights.Count - 1; num >= 0; num--) { Flight flight = Flights[num]; if (flight.Shooter == shooter && !(flight.Loan != loan) && flight.Sequence == sequence) { if ((Object)(object)flight.Look != (Object)null && !((Il2CppObjectBase)flight.Look).WasCollected) { Object.Destroy((Object)(object)flight.Look); } Flights.RemoveAt(num); } } } private static void ShowBurst(Vector3 at) { //IL_0033: 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_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) if (_explosion == null) { _explosion = Fx.Find("Game:FX_Tripmine"); } if (_explosion != null) { Fx.Play(_explosion, at, Vector3.up); } ArsenalAudio.PlayAt("weapon.grenade_burst", at); } internal static void Clear() { foreach (Flight flight in Flights) { if ((Object)(object)flight.Look != (Object)null && !((Il2CppObjectBase)flight.Look).WasCollected) { Object.Destroy((Object)(object)flight.Look); } } Flights.Clear(); Pending.Clear(); Settled.Clear(); Expired.Clear(); _suppress = false; } } internal static class LauncherReload { internal static void Subscribe() { GameHooks.ReloadTriggered.Around<bool>((Func<ItemEquippable, bool>)((ItemEquippable item) => item.IsReloading), (Action<ItemEquippable, bool, bool>)delegate(ItemEquippable item, bool wasReloading, bool ran) { Postfix(item, ran, wasReloading); }, (Action<ItemEquippable, bool, Exception>)null); } private static void Postfix(ItemEquippable __instance, bool __runOriginal, bool __state) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected I4, but got Unknown PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack; if (!(!__runOriginal || __state) && __instance.IsReloading && !((Object)(object)((Item)__instance).Owner == (Object)null) && ((Agent)((Item)__instance).Owner).IsLocallyOwned) { ItemDataBlock itemDataBlock = ((Item)__instance).ItemDataBlock; BackpackItem val = default(BackpackItem); if (itemDataBlock != null && (int)itemDataBlock.inventorySlot == 2 && !(HeavyWeapons.ActiveLauncher == null) && localBackpack != null && localBackpack.TryGetBackpackItem((InventorySlot)2, ref val) && !((Object)(object)((val != null) ? val.Instance : null) != (Object)(object)__instance)) { ArsenalAudio.PlayAttached("weapon.grenade_reload", ((Component)__instance).gameObject, (int)((Agent)((Item)__instance).Owner).DimensionIndex, isSelf: true); } } } } internal static class LauncherFire { internal static void Subscribe() { Fire.BulletWeapon.Before((Action<BulletWeapon>)delegate(BulletWeapon weapon) { try { Grenades.BeforeFire(weapon); } catch (Exception ex) { Plugin.Error("Grenade launcher fire hook failed: " + ex); } }); Fire.BulletWeapon.After((Action<BulletWeapon, bool>)delegate(BulletWeapon weapon, bool _) { try { Grenades.AfterFire(weapon); } catch (Exception ex) { Plugin.Error("Grenade launcher fire hook failed: " + ex); } }); } } internal static class LauncherBullet { internal static void Subscribe() { GameHooks.BulletHit.Before((Action<BulletHitCall>)delegate(BulletHitCall call) { if (Grenades.Suppressing) { call.Skip(false); } }); } } internal sealed record HeavyParameters(HeavyWeaponSpec Spec, uint GearId); internal sealed class HeavyWeaponPayload : IOrdnancePayload, IOrdnancePayloadParser { public bool HasOwnArrival => true; public bool SupportsDirect => true; public object Parse(JsonElement payload) { //IL_001c: 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_00dd: 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_0143: 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_00fd: Invalid comparison between Unknown and I4 //IL_0161: Unknown result type (might be due to invalid IL or missing references) HeavyWeaponSpec heavyWeaponSpec = HeavyWeaponSpec.Parse(payload); string text = ArsenalArt.CheckWeaponModel(heavyWeaponSpec.Model); if (text != null) { throw new PayloadParameterException("Model", text); } PlayerOfflineGearDataBlock val = (heavyWeaponSpec.GearId.HasValue ? GameDataBlockBase<PlayerOfflineGearDataBlock>.GetBlock(heavyWeaponSpec.GearId.Value) : GameDataBlockBase<PlayerOfflineGearDataBlock>.GetBlock(heavyWeaponSpec.GearName)); if (val == null || ((Il2CppObjectBase)val).WasCollected) { throw new PayloadParameterException("Gear", "no offline gear block " + (heavyWeaponSpec.GearId.HasValue ? heavyWeaponSpec.GearId.Value.ToString() : ("'" + heavyWeaponSpec.GearName + "'")) + " in this install."); } if (string.IsNullOrEmpty(val.GearJSON)) { throw new PayloadParameterException("Gear", "the gear block has no GearJSON."); } uint compID = new GearIDRange(val.GearJSON).GetCompID((eGearComponent)3); ItemDataBlock block = GameDataBlockBase<ItemDataBlock>.GetBlock(compID); if (block == null || (int)block.inventorySlot != 2) { throw new PayloadParameterException("Gear", "gear block " + ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)val).persistentID + " is not a special slot weapon (base item " + compID + ")."); } string text2 = HeavyModels.Register(heavyWeaponSpec.Model); if (text2 != null) { throw new PayloadParameterException("Model", text2); } return new HeavyParameters(heavyWeaponSpec, ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)val).persistentID); } public void Execute(OrdnanceExecution execution) { HeavyWeapons.HostArrived(execution); } public void OnArrived(OrdnancePresentation presentation) { HeavyWeapons.ShowRack(presentation); } public void OnData(OrdnancePayloadData data) { HeavyWeapons.OnData(data); } } internal static class HeavyWeapons { private sealed class WornLook { internal Dressed Dressed; internal ItemEquippable? Gear; internal Transform? Sight; internal Transform? NativeHolderSight; internal Transform? NativeWeaponSight; } private sealed class Rack { internal ulong Summoner; internal uint ThrowId; internal HeavyParameters P; internal string Id = ""; internal OrdnanceDefinition? Definition; internal OrdnancePod? Pod; internal OrdnanceClaimable? Claim; internal int Bay; internal GameObject? Look; internal Vector3 Fallback; internal bool Presented; internal LauncherLoan? PendingLauncher; internal bool Taken { get { OrdnanceClaimable? claim = Claim; if (claim == null) { return false; } return claim.IsTaken; } } } private enum Phase { None, Equipping, AwaitingCommit, Active, Returning, Reconciling, Stashed, Suspended } private const float SwapTimeout = 6f; private const float SkinScanSeconds = 0.5f; private static readonly Dictionary<IntPtr, WornLook> Skins = new Dictionary<IntPtr, WornLook>(); private static readonly List<Rack> Racks = new List<Rack>(); private static readonly HashSet<(ulong Summoner, uint ThrowId)> UnavailableRacks = new HashSet<(ulong, uint)>(); private static readonly LoanBook Loans = new LoanBook(); private static readonly Dictionary<ulong, LauncherLoan> Launchers = new Dictionary<ulong, LauncherLoan>(); private static Guid _launcherIdentity; private static float _nextSkinScan; private static Rack? _promptRack; private static Phase _promptPhase; private static SpecialSlotLease? _promptRefusal; private static int _promptLanguage = -1; private static string _promptText = ""; private static string _promptKey = ""; private static Phase _phase; private static HeavyParameters? _lent; private static SpecialSlotLease? _lease; private static bool _suspendedInHand; private static bool _resumeInHand; private static GearIDRange? _expected; private static ClaimInstall? _claim; private static bool _returnRequested; private static HeavyLoan? _loan; private static float _phaseStarted; private static AmmoStash? _heavyStash; private static float _switchReadyAt; private const float SwitchCooldown = 0.5f; private static readonly PropertyInfo[] BlockProperties = (from p in typeof(ArchetypeDataBlock).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public) where p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0 select p).ToArray(); private const string LookName = "ForgeOrdnanceArsenal.WeaponLook"; internal const string SightSocket = "SightLook"; private static SpecialSlot Slot => Gear.SpecialSlot; internal static HeavyParameters? ActiveLauncher { get { if (_phase != Phase.Active || !(_lent?.Spec.Grenade != null)) { return null; } return _lent; } } internal static Guid ActiveLauncherIdentity => _launcherIdentity; internal static string Marker(HeavyWeaponSpec spec) { return spec.Marker; } private static bool TryMarker(string? name, out string model) { return HeavyModels.TryMarkerId(name, out model); } internal static bool AuthorizeGrenade(ulong sender, ref GrenadeShot shot, out float delay, out string reason) { //IL_0095: 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_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_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: 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_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_021f: 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_0230: Unknown result type (might be due to invalid IL or missing references) //IL_023a: 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_0244: 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) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) delay = 0f; reason = "sender is not the shooter or not a human player"; if (sender != shot.Shooter || !ArsenalNetwork.IsPlayer(sender)) { return false; } reason = "no active host launcher loan"; if (!Launchers.TryGetValue(sender, out LauncherLoan value)) { return false; } PlayerAgent val = Level.PlayerByLookup(sender); reason = "launcher is not held by a live borrower"; if (!((Object)(object)val == (Object)null) && ((Agent)val).Alive) { PlayerInventoryBase inventory = val.Inventory; if (inventory != null) { ItemEquippable wieldedItem = inventory.WieldedItem; InventorySlot? obj; if (wieldedItem == null) { obj = null; } else { ItemDataBlock itemDataBlock = ((Item)wieldedItem).ItemDataBlock; obj = ((itemDataBlock != null) ? new InventorySlot?(itemDataBlock.inventorySlot) : ((InventorySlot?)null)); } PlayerBackpack val2 = default(PlayerBackpack); BackpackItem val3 = default(BackpackItem); if (obj == (InventorySlot?)2 && PlayerBackpackManager.TryGetBackpack(val.Owner, ref val2) && val2 != null && val2.TryGetBackpackItem((InventorySlot)2, ref val3) && val3 != null && val3.IsLoaded) { GearIDRange gearIDRange = val3.GearIDRange; if (((gearIDRange != null) ? new uint?(gearIDRange.GetChecksum()) : ((uint?)null)) == value.GearChecksum && !(val3.GearIDRange.PublicGearName != Marker(value.Spec))) { Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(shot.VX, shot.VY, shot.VZ); reason = "invalid aim direction"; if (!float.IsFinite(((Vector3)(ref val4)).sqrMagnitude) || ((Vector3)(ref val4)).sqrMagnitude < 0.9f || ((Vector3)(ref val4)).sqrMagnitude > 1.1f) { return false; } Vector3 val5 = default(Vector3); ((Vector3)(ref val5))..ctor(shot.OX, shot.OY, shot.OZ); LauncherLoan launcherLoan = value; Guid loan = shot.Loan; uint sequence = shot.Sequence; float time = Time.time; Vector3 val6 = val5 - ((Agent)val).EyePosition; if (!launcherLoan.TrySchedule(loan, sequence, time, ((Vector3)(ref val6)).sqrMagnitude, out delay, out reason)) { return false; } shot.OX = ((Agent)val).EyePosition.x; shot.OY = ((Agent)val).EyePosition.y; shot.OZ = ((Agent)val).EyePosition.z; GrenadeSpec grenade = value.Spec.Grenade; Vector3 val7 = ((Vector3)(ref val4)).normalized * grenade.Speed + Vector3.up * 1.5f; shot.VX = val7.x; shot.VY = val7.y; shot.VZ = val7.z; shot.Damage = grenade.Damage; shot.Radius = grenade.Radius; return true; } } } } return false; } internal static void ShowRack(OrdnancePresentation p) { //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_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_00a9: 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_00b4: Unknown result type (might be due to invalid IL or missing references) if (!UnavailableRacks.Remove((p.SummonerLookup, p.ThrowId))) { Rack rack = new Rack { Summoner = p.SummonerLookup, ThrowId = p.ThrowId, P = (HeavyParameters)p.Parameters, Id = p.Definition.Id, Definition = p.Definition, Fallback = p.Position, Presented = true }; Racks.Add(rack); rack.Claim = AddClaimable(rack, rack.Pod = OrdnanceDelivery.StartPod(p), p.Position + Vector3.up * 0.4f, OrdnanceDelivery.PodContentsDelay(p.Arrival)); } } private static OrdnanceClaimable AddClaimable(Rack rack, OrdnancePod? pod, Vector3 position, float openAfter) { //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_0024: 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_0048: 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_007f: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) ClaimableSpec val = new ClaimableSpec { Prompt = () => RackPrompt(rack), HostCheck = (PlayerAgent agent) => HostCheck(rack, agent), Install = delegate(ClaimInstall claim) { Install(rack, claim); }, Cancelled = delegate { Phase phase = _phase; if ((uint)(phase - 1) <= 1u) { Abort(); } }, HostVerify = (PlayerAgent agent) => Verify(rack, agent), Committed = delegate(ClaimResult result) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Committed(rack, result); }, Opened = delegate { OpenRack(rack); }, Removed = delegate { RemoveRack(rack); } }; if (pod == null) { return OrdnanceDelivery.AddClaimable(rack.Summoner, rack.ThrowId, position, openAfter, val); } rack.Bay = (int)(rack.ThrowId % (uint)pod.WeaponBayCount); return pod.AddClaimable(rack.Bay, val); } private static void OpenRack(Rack rack) { //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_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_00b9: 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_0066: 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_008a: Unknown result type (might be due to invalid IL or missing references) if (rack.Taken || (Object)(object)rack.Look != (Object)null) { return; } ModelHandle val = ArsenalArt.Weapon(rack.P.Spec.Model); OrdnancePod? pod = rack.Pod; OrdnancePodBay? val2 = ((pod != null) ? pod.WeaponBayAt(rack.Bay) : ((OrdnancePodBay?)null)); if (val == null) { return; } if (val2.HasValue) { OrdnancePodBay valueOrDefault = val2.GetValueOrDefault(); GameObject val3 = val.Spawn(((OrdnancePodBay)(ref valueOrDefault)).Position, ((OrdnancePodBay)(ref valueOrDefault)).Rotation, (Transform)null); if (!((Object)(object)val3 == (Object)null)) { float num = default(float); float num2 = default(float); rack.Look = ((OrdnancePodBay)(ref valueOrDefault)).Fit(val3, ArsenalArt.FrontToForward, ref num, ref num2); } } else { GameObject val4 = val.Spawn(rack.Fallback + Vector3.up * 0.15f, ArsenalArt.FrontToForward, (Transform)null); if (!((Object)(object)val4 == (Object)null)) { ((Object)val4).name = "ForgeOrdnanceArsenal.Rack"; rack.Look = val4; } } } internal static void HostArrived(OrdnanceExecution e) { //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) //IL_004e: 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_005e: 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_0089: Unknown result type (might be due to invalid IL or missing references) ulong summoner = e.SummonerLookup; uint throwId = e.ThrowId; HeavyParameters heavyParameters = (HeavyParameters)e.Parameters; HeavyWeaponSpec spec = heavyParameters.Spec; uint gearId = heavyParameters.GearId; float x = e.Position.x; float y = e.Position.y; float z = e.Position.z; Quaternion rotation = e.Rotation; byte[] record = Wire.Rack(new RackRecord(spec, gearId, x, y, z, ((Quaternion)(ref rotation)).eulerAngles.y, e.Definition.Id)); OrdnanceDelivery.HostAfter(OrdnanceDelivery.PodContentsDelay(e.Arrival), (Action)delegate { if (!OrdnanceApi.SendState("arsenal.HeavyWeapon", summoner, throwId, (byte)7, record)) { OrdnanceApi.SendData("arsenal.HeavyWeapon", summoner, throwId, (byte)10, Array.Empty<byte>()); OrdnanceDelivery.HostReportPodEmpty(summoner, throwId); } else { OrdnanceDelivery.HostOpenClaim(summoner, throwId); } }); } private static string? HostCheck(Rack rack, PlayerAgent agent) { if (HasBorrowedGear(agent) || ((Object)(object)agent.Owner != (Object)null && Loans.HasLoan(agent.Owner.Lookup))) { return "the requester is already borrowing a heavy weapon"; } try { LoanedGun.Require(BorrowedRange(rack.P)); } catch (Exception ex) { Plugin.Error("Host refused unloaded heavy weapon effects: " + ex); return "the host has not loaded the heavy weapon's effects"; } return null; } private static bool HasBorrowedGear(PlayerAgent agent) { PlayerBackpack val = default(PlayerBackpack); BackpackItem val2 = default(BackpackItem); if ((Object)(object)agent.Owner != (Object)null && PlayerBackpackManager.TryGetBackpack(agent.Owner, ref val) && val != null && val.TryGetBackpackItem((InventorySlot)2, ref val2) && val2 != null) { GearIDRange gearIDRange = val2.GearIDRange; string model; return TryMarker((gearIDRange != null) ? gearIDRange.PublicGearName : null, out model); } return false; } private static void Install(Rack rack, ClaimInstall claim) { if (_phase != Phase.None) { claim.Failed(); return; } _claim = claim; try { BeginLoan(rack.P); } catch (Exception ex) { Plugin.Error("Heavy weapon installation refused: " + ex); Abort(); } } private static ClaimVerdict Verify(Rack rack, PlayerAgent agent) { //IL_006c: 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_00d2: 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_00eb: Expected I4, but got Unknown //IL_01f5: 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_01b2: Unknown result type (might be due to invalid IL or missing references) PlayerBackpack val = default(PlayerBackpack); BackpackItem val2 = default(BackpackItem); if (PlayerBackpackManager.TryGetBackpack(agent.Owner, ref val) && val != null && val.TryGetBackpackItem((InventorySlot)2, ref val2) && val2 != null && val2.IsLoaded && !((Object)(object)val2.Instance == (Object)null) && !((Il2CppObjectBase)val2.Instance).WasCollected) { GearIDRange gearIDRange = val2.GearIDRange; if (!(((gearIDRange != null) ? gearIDRange.PublicGearName : null) != Marker(rack.P.Spec))) { GearIDRange val3 = BorrowedRange(rack.P); if (val2.GearIDRange.GetChecksum() != val3.GetChecksum()) { return ClaimVerdict.Wait; } LauncherLoan launcherLoan = null; if (rack.P.Spec.Grenade != null) { GearCategoryDataBlock block = GameDataBlockBase<GearCategoryDataBlock>.GetBlock(val3.GetCompID((eGearComponent)2)); uint num; if (block == null) { num = 0u; } else { eWeaponFireMode val4 = (eWeaponFireMode)val3.GetCompID((eGearComponent)1); num = (int)val4 switch { 0 => block.SemiArchetype, 1 => block.BurstArchetype, 2 => block.AutoArchetype, 3 => block.SemiBurstArchetype, _ => 0u, }; } ArchetypeDataBlock block2 = GameDataBlockBase<ArchetypeDataBlock>.GetBlock(num); InventorySlotAmmo specialAmmo = val.AmmoStorage.SpecialAmmo; ArchetypeTuning archetypeTuning = ((block2 == null) ? null : rack.P.Spec.Tuning.Over(Readings(block2))); if (archetypeTuning == null || !archetypeTuning.Valid()) { return ClaimVerdict.Refuse("host gear has invalid ammunition or cadence"); } double num2 = archetypeTuning.Rounds(rack.P.Spec.AmmoRatio, specialAmmo.AmmoMaxCap); if (!(num2 > 0.0) || !(num2 <= 2147483647.0)) { return ClaimVerdict.Refuse("host gear has invalid ammunition or cadence"); } launcherLoan = new LauncherLoan(rack.P.Spec, val3.GetChecksum(), (int)num2, archetypeTuning.ShotDelay, Time.time); } rack.PendingLauncher = launcherLoan; return ClaimVerdict.Accept(launcherLoan?.Identity ?? Guid.Empty); } } return ClaimVerdict.Wait; } private static void Committed(Rack rack, ClaimResult result) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected I4, but got Unknown if (SNet.IsMaster) { Loans.Commit(rack.Summoner, rack.ThrowId, ((ClaimResult)(ref result)).Player, ((ClaimResult)(ref result)).Attempt); if (rack.PendingLauncher != null) { Launchers[((ClaimResult)(ref result)).Player] = rack.PendingLauncher; } rack.PendingLauncher = null; OrdnanceApi.ClearState("arsenal.HeavyWeapon", rack.Summoner, rack.ThrowId); OrdnanceDelivery.HostReportPodEmpty(rack.Summoner, rack.ThrowId); } Destroy(rack.Look); rack.Look = null; if (((ClaimResult)(ref result)).Ours && _phase == Phase.AwaitingCommit) { _launcherIdentity = ((ClaimResult)(ref result)).Token; _phase = Phase.Active; _loan = new HeavyLoan(Time.time); PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent(); if ((Object)(object)localPlayerAgent != (Object)null) { ArsenalAudio.PlayAttached("weapon.handover", ((Component)localPlayerAgent).gameObject, (int)((Agent)localPlayerAgent).DimensionIndex, ((Agent)localPlayerAgent).IsLocallyOwned); } } } internal static void OnLoanNotice(ulong sender, LoanNotice m) { if (SNet.IsMaster && ArsenalNetwork.IsPlayer(sender)) { if (m.Action == LoanAction.Stashed) { Loans.Stash(m.Summoner, m.ThrowId, sender, m.Attempt); } else if (Loans.Release(m.Summoner, m.ThrowId, sender, m.Attempt)) { Launchers.Remove(sender); } } } internal static void OnData(OrdnancePayloadData d) { if (d.Tag == 10) { if (d.Data.Length != 0) { return; } bool flag = true; for (int num = Racks.Count - 1; num >= 0; num--) { if (Racks[num].Summoner == d.SummonerLookup && Racks[num].ThrowId == d.ThrowId) { Rack rack = Racks[num]; flag &= !rack.Presented; OrdnanceClaimable? claim = rack.Claim; if (claim != null) { claim.Withdraw(); } RemoveRack(rack); } } if (flag) { UnavailableRacks.Add((d.SummonerLookup, d.ThrowId)); } } else { if (d.Tag != 7) { return; } if (!Wire.TryRack(d.Data, out var r)) { if (Wire.UnknownRackModel(d.Data, out var hash)) { Plugin.Report("A heavy weapon rack was dropped: its model hash " + hash.ToString("x8") + " is not one of this install's heavy weapon models (the host's heavy weapon packs must be installed here too)."); } } else if (!Racks.Exists((Rack rack2) => rack2.Summoner == d.SummonerLookup && rack2.ThrowId == d.ThrowId)) { RackFromState(d, in r); } } } private static void RemoveRack(Rack rack) { Destroy(rack.Look); rack.Look = null; Racks.Remove(rack); } private static void RackFromState(OrdnancePayloadData d, in RackRecord record) { //IL_005a: 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_0088: 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_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) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(record.X, record.Y, record.Z); Rack rack = new Rack { Summoner = d.SummonerLookup, ThrowId = d.ThrowId, P = new HeavyParameters(record.Spec, record.GearId), Id = record.Id, Fallback = val }; Racks.Add(rack); OrdnancePod val2 = (rack.Pod = OrdnanceDelivery.FindPod(d.SummonerLookup, d.ThrowId)); rack.Claim = AddClaimable(rack, val2, val + Vector3.up * 0.4f, 0f); if (val2 == null) { OpenRack(rack); } } internal static void Tick(float now) { if (SNet.IsMaster && Loans.Any) { Loans.ReconcileLoans(HostLoanStillPresent, ReleaseHostLoan); } try { LocalLoan(now); } catch (Exception ex) { Plugin.Error("Heavy weapon loan failed: " + ex); Abort(); } if (now >= _nextSkinScan) { _nextSkinScan = now + 0.5f; try { ScanSkins(); } catch (E