using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FishNet; using FishNet.Managing; using FishNet.Managing.Object; using FishNet.Object; using HarmonyLib; using HowToFish.ModKit; using HowToFish.WeaponArsenal.Arsenal; using HowToFish.WeaponArsenal.Assets; using HowToFish.WeaponArsenal.Patches; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("HowToFish.WeaponArsenal")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+6cb5338874bba59a68beef237a2c7fbf6e227e13")] [assembly: AssemblyProduct("HowToFish.WeaponArsenal")] [assembly: AssemblyTitle("HowToFish.WeaponArsenal")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 HowToFish.WeaponArsenal { internal sealed class ModConfig { public readonly ConfigEntry Enabled; public readonly ConfigEntry VerboseLogging; public readonly ConfigEntry PrefabCollectionId; public readonly ConfigEntry ShopIslandName; public readonly ConfigEntry ShopIslandIndex; public readonly ConfigEntry ShopFallbackSpacing; public readonly ConfigEntry LiveTuning; public readonly ConfigEntry SourceWeaponsFolder; public ModConfig(ConfigFile f) { Enabled = f.Bind("01 - General", "Enabled", true, "Master switch. When off no custom weapons are built or registered, and the game behaves exactly as it does without the mod installed."); VerboseLogging = f.Bind("01 - General", "VerboseLogging", false, "Log every base weapon prefab found and every stat applied. Worth turning on once while authoring a new weapon def, and off again afterwards."); PrefabCollectionId = f.Bind("02 - Multiplayer", "PrefabCollectionId", (ushort)4100, "FishNet spawnable-prefab collection the mod's weapons are registered into. The mod deliberately uses its own collection rather than appending to the game's, so vanilla prefab indices never shift.\n\nEvery player in a lobby must run the same mod version with the same weapons folder: a networked prefab is identified by its index within the collection, so a different arsenal on another client resolves to a different weapon. Compare the fingerprint from /wa status between players to confirm they match."); ShopIslandName = f.Bind("03 - Shop", "ShopIslandName", "", "Island scene name, or any part of it, that sells the mod's weapons. Takes precedence over ShopIslandIndex when it matches. Run /wa islands in game to see the real scene names - the last island by index is not the volcano."); ShopIslandIndex = f.Bind("03 - Shop", "ShopIslandIndex", -1, "Island index that sells the mod's weapons, used when ShopIslandName is empty or does not match. -1 means the last playable island, skipping DevIsland, which sits at the highest index but is not part of the game."); ShopFallbackSpacing = f.Bind("03 - Shop", "ShopFallbackSpacing", 1f, "Metres between stands, used only when the island has a single weapon stand to measure against. With two or more the spacing is taken from the real gap between them, so the new stands line up with the existing rack."); SourceWeaponsFolder = f.Bind("04 - Development", "SourceWeaponsFolder", "", "Repository weapons folder, if you develop this mod from source. '/wa fit save' normally writes only to the deployed plugin folder, where the next build overwrites it from the repo copy - silently losing tuned values. Set this and save writes to both. Leave empty if you only installed the mod."); LiveTuning = f.Bind("04 - Development", "LiveTuning", true, "Enable the /wa fit commands, which rebake a weapon's mesh alignment in game without a rebuild. This is how the scale, position and rotation numbers in a weapon def are meant to be found - by eye, on screen, rather than by guessing and recompiling."); } } [BepInPlugin("com.zpaulin.howtofish.weaponarsenal", "zPaulin's Weapon Arsenal", "1.0.1")] [BepInProcess("How to Fish.exe")] public sealed class Plugin : BaseUnityPlugin { private Harmony _harmony; private GameObject _host; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ModConfig Cfg { get; private set; } internal static WeaponRegistry Registry { get; private set; } internal static ArsenalRuntime Runtime { get; private set; } internal static string WeaponsFolder { get; private set; } private void Awake() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Cfg = new ModConfig(((BaseUnityPlugin)this).Config); WeaponsFolder = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "weapons"); Registry = new WeaponRegistry(); Registry.Load(WeaponsFolder); _harmony = new Harmony("com.zpaulin.howtofish.weaponarsenal"); _harmony.PatchAll(typeof(Plugin).Assembly); _host = new GameObject("HowToFish.WeaponArsenal.Runtime") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)_host); Runtime = _host.AddComponent(); try { string location = typeof(Plugin).Assembly.Location; Log.LogInfo((object)("BUILD STAMP: " + File.GetLastWriteTime(location).ToString("yyyy-MM-dd HH:mm:ss") + " from " + location)); } catch (Exception ex) { Log.LogWarning((object)("could not stamp build: " + ex.Message)); } Log.LogInfo((object)("zPaulin's Weapon Arsenal v1.0.1 loaded - " + Registry.Defs.Count + " weapon def(s), fingerprint " + Registry.Fingerprint)); } private void OnDestroy() { if ((Object)(object)_host != (Object)null) { Object.Destroy((Object)(object)_host); } if (_harmony != null) { _harmony.UnpatchSelf(); } } } public static class PluginInfo { public const string Guid = "com.zpaulin.howtofish.weaponarsenal"; public const string Name = "zPaulin's Weapon Arsenal"; public const string Version = "1.0.1"; public const string CommandRoot = "wa"; } internal static class Refl { private static readonly Dictionary FieldCache = new Dictionary(); private static readonly HashSet Warned = new HashSet(); public static FieldInfo Field(Type type, string name) { string text = type.FullName + "." + name; if (FieldCache.TryGetValue(text, out var value)) { return value; } value = AccessTools.Field(type, name); FieldCache[text] = value; if (value == null && Warned.Add(text)) { Plugin.Log.LogWarning((object)("Field not found: " + text + " - the game may have changed. That value will be left alone.")); } return value; } public static bool Set(object target, string name, T? value) where T : struct { if (!value.HasValue || target == null) { return false; } return SetRaw(target, name, value.Value); } public static bool SetRaw(object target, string name, object value) { if (target == null) { return false; } FieldInfo fieldInfo = Field(target.GetType(), name); if (fieldInfo == null) { return false; } try { fieldInfo.SetValue(target, value); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to set " + target.GetType().Name + "." + name + ": " + ex.Message)); return false; } } public static object Get(object target, string name) { if (target == null) { return null; } FieldInfo fieldInfo = Field(target.GetType(), name); if (fieldInfo == null) { return null; } try { return fieldInfo.GetValue(target); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to read " + target.GetType().Name + "." + name + ": " + ex.Message)); return null; } } public static T GetAs(object target, string name) where T : class { return Get(target, name) as T; } public static bool SetProperty(object target, string name, object value) { if (target == null) { return false; } PropertyInfo propertyInfo = AccessTools.Property(target.GetType(), name); if (propertyInfo == null || !propertyInfo.CanWrite) { string text = target.GetType().FullName + "::" + name; if (Warned.Add(text)) { Plugin.Log.LogWarning((object)("Property not writable: " + text)); } return false; } try { propertyInfo.SetValue(target, value, null); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to set property " + target.GetType().Name + "." + name + ": " + ex.Message)); return false; } } } } namespace HowToFish.WeaponArsenal.Patches { [HarmonyPatch(typeof(Attachments), "InitAttachments")] internal static class AttachmentsInitPatch { [HarmonyPostfix] private static void Postfix(Attachments __instance) { if (Plugin.Cfg == null || !Plugin.Cfg.Enabled.Value) { return; } ArsenalWeapon componentInParent = ((Component)__instance).GetComponentInParent(true); if ((Object)(object)componentInParent == (Object)null) { return; } WeaponDef def = componentInParent.Def; if (def == null || def.Attachments == null || !(Refl.Get(__instance, "_attachmentCosts") is Dictionary dictionary)) { return; } int num = 0; AttachmentsDef attachments = def.Attachments; if (!attachments.Sights) { num += RemoveList(dictionary, Refl.Get(__instance, "_sights") as IEnumerable, 1); } if (!attachments.Barrels) { num += RemoveList(dictionary, Refl.Get(__instance, "_barrelAttachments") as IEnumerable, 1); } if (!attachments.Laser) { object obj = Refl.Get(__instance, "_laserSight"); LaserSight val = (LaserSight)((obj is LaserSight) ? obj : null); if ((Object)(object)val != (Object)null && (Object)(object)((Attachment)val).Info != (Object)null && dictionary.Remove(((Attachment)val).Info)) { num++; } } if (!attachments.ExtendedMag) { object obj2 = Refl.Get(__instance, "_extendedMagInfo"); AttachmentInfo val2 = (AttachmentInfo)((obj2 is AttachmentInfo) ? obj2 : null); if ((Object)(object)val2 != (Object)null && dictionary.Remove(val2)) { num++; } } if (num > 0 && Plugin.Cfg.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Blocked " + num + " attachment(s) on " + def.Id + ".")); } } private static int RemoveList(Dictionary costs, IEnumerable items, int skip) where T : Attachment { if (items == null) { return 0; } int num = 0; int num2 = 0; foreach (T item in items) { if (num2++ >= skip && !((Object)(object)item == (Object)null) && !((Object)(object)((Attachment)item).Info == (Object)null) && costs.Remove(((Attachment)item).Info)) { num++; } } return num; } } [HarmonyPatch(typeof(AudioManager), "Start")] internal static class AudioManagerStartPatch { [HarmonyPostfix] private static void Postfix() { SoundLibrary.ReapplyAll(); } } [HarmonyPatch(typeof(DazedCommands), "IsServerCommand")] internal static class CommandPatches { [HarmonyPrefix] private static bool Prefix(string __0, ref bool __result) { if (string.IsNullOrEmpty(__0)) { return true; } string text = __0.Trim(); if (text.StartsWith("/")) { text = text.Substring(1); } string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return true; } if (!string.Equals(array[0], "wa", StringComparison.OrdinalIgnoreCase)) { return true; } Plugin.Log.LogInfo((object)("command: " + text)); try { Dispatch(array); } catch (Exception ex) { Say("error: " + ex.Message); Plugin.Log.LogError((object)("Command '" + __0 + "' threw: " + ex)); } __result = true; return false; } private static void Dispatch(string[] parts) { string text = ((parts.Length > 1) ? parts[1].ToLowerInvariant() : "status"); switch (text) { case "status": Status(); break; case "list": List(); break; case "bases": Bases(); break; case "give": Give(parts); break; case "inspect": Inspect(parts); break; case "shop": Shop(); break; case "islands": Islands(); break; case "prop": Prop(parts); break; case "bones": Bones(parts); break; case "part": Part(parts); break; case "anchors": Anchors(parts); break; case "ik": Ik(parts); break; case "pose": Pose(parts); break; case "grip": Grip(parts); break; case "slide": Slide(parts); break; case "paths": Paths(parts); break; case "charge": Charge(parts); break; case "forge": Forge(parts); break; case "ads": Ads(parts); break; case "auto": Auto(parts); break; case "reload": Reload(); break; case "fit": Fit(parts); break; case "help": Help(); break; default: Say("unknown subcommand '" + text + "'."); Help(); break; } } private static void Status() { WeaponRegistry registry = Plugin.Registry; Say("zPaulin's Weapon Arsenal v1.0.1" + (Plugin.Cfg.Enabled.Value ? "" : " [DISABLED]")); Say("defs: " + registry.Defs.Count + " | fingerprint: " + registry.Fingerprint); Say("prefabs: " + ModPrefabRegistry.Status()); Say(BaseWeaponIndex.Ready ? ("bases: " + BaseWeaponIndex.WeaponNames.Count + " indexed") : "bases: not indexed yet"); if (registry.LoadErrors.Count > 0) { Say(registry.LoadErrors.Count + " def(s) rejected:"); foreach (string loadError in registry.LoadErrors) { Say(" " + loadError); } } Say("compare the fingerprint with other players - it must match to play together."); } private static void List() { ArsenalRuntime runtime = Plugin.Runtime; if (Plugin.Registry.Defs.Count == 0) { Say("no weapon defs loaded."); return; } foreach (WeaponDef def in Plugin.Registry.Defs) { BuiltWeapon builtWeapon = (((Object)(object)runtime == (Object)null) ? null : runtime.Find(def.Id)); Say(((builtWeapon != null) ? "[ok] " : "[--] ") + def.Describe() + ((builtWeapon != null) ? (" | scale " + def.Model.Scale.ToString("F3", CultureInfo.InvariantCulture)) : "")); } } private static void Bases() { if (!BaseWeaponIndex.Ready) { Say("base weapon index not built yet - load into a game first."); return; } Say(BaseWeaponIndex.Summary()); Say("use one of these names as \"basePrefab\" in a weapon def."); } private static void Inspect(string[] parts) { if (parts.Length < 3) { Say("usage: /wa inspect "); Bases(); return; } string text = JoinRest(parts, 2); BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(text)); if (builtWeapon != null) { string text2 = PrefabInspector.Dump(builtWeapon.Prefab, (Item)(object)builtWeapon.Weapon, "built:" + text); Say("dumped built '" + text + "' to the BepInEx log - " + text2); return; } NetworkObject val = BaseWeaponIndex.Find(text); if ((Object)(object)val == (Object)null) { Say("no base prefab or built weapon called '" + text + "'."); Bases(); } else { Item componentInChildren = ((Component)val).GetComponentInChildren(true); string text3 = PrefabInspector.Dump(((Component)val).gameObject, componentInChildren, "base:" + text); Say("dumped base '" + text + "' to the BepInEx log - " + text3); } } private static void Auto(string[] parts) { if (parts.Length < 3) { Say("usage: /wa auto [align|hands] - solves both and saves when given neither"); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } string text = ((parts.Length > 3) ? parts[3].ToLowerInvariant() : null); bool alignModel = text == null || text == "align"; bool snapHands = text == null || text == "hands"; Say(AutoSolver.Solve(builtWeapon, alignModel, snapHands)); if (text == null) { Save(builtWeapon.Def); Say("solved and saved. respawn the weapon if it is already in your hands."); } else { Say("looks right? /wa fit " + builtWeapon.Def.Id + " save"); } } private static void Ads(string[] parts) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 3) { Say("usage: /wa ads nudge up|down|left|right|forward|back | set | show | reset | save"); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } string text = ((parts.Length > 3) ? parts[3].ToLowerInvariant() : "show"); switch (text) { case "save": Save(builtWeapon.Def); return; case "show": Say(builtWeapon.Def.Id + " ads " + Vec3(WeaponBuilder.CurrentAds(builtWeapon)) + ((builtWeapon.Def.Ads == null) ? " (the base weapon's own)" : " (from the def)")); return; case "reset": builtWeapon.Def.Ads = null; Say("def override cleared - respawn the weapon to get the base value back."); return; } Vector3 val = WeaponBuilder.CurrentAds(builtWeapon); Vector3 value; if (text == "set") { if (!TryParseVector(parts, 4, out value)) { Say("usage: /wa ads " + builtWeapon.Def.Id + " set "); return; } } else { if (!(text == "nudge")) { Say("unknown ads option '" + text + "'."); return; } if (parts.Length < 6 || !TryParse(parts[5], out var value2)) { Say("usage: /wa ads " + builtWeapon.Def.Id + " nudge up|down|left|right|forward|back "); return; } Vector3 val2; switch (parts[4].ToLowerInvariant()) { case "right": val2 = Vector3.right; break; case "left": val2 = Vector3.left; break; case "up": val2 = Vector3.up; break; case "down": val2 = Vector3.down; break; case "forward": val2 = Vector3.forward; break; case "back": val2 = Vector3.back; break; default: Say("direction must be up, down, left, right, forward or back."); return; } value = val + val2 * value2; } builtWeapon.Def.Ads = new float[3] { value.x, value.y, value.z }; WeaponBuilder.ApplyAds(builtWeapon); Say("ads " + Vec3(val) + " -> " + Vec3(value) + ". aim to check; /wa ads " + builtWeapon.Def.Id + " save"); } private static void Forge(string[] parts) { if (parts.Length < 3) { Say("usage: /wa forge [charge] | restore"); Say(" plain rebuilds the clip exactly as recorded - use it to check the rebuild itself."); Say(" 'charge' additionally rewrites the racking segment. 'restore' puts the game's clip back."); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } string text = ((parts.Length > 3) ? parts[3].ToLowerInvariant() : ""); if (text == "restore") { Say(ClipForge.Restore() ? "the weapon's own clip is back." : "nothing to restore - the clip in use is already the game's."); return; } ClipForge.ApplyCharge = text == "charge"; if (ClipForge.ApplyCharge && (builtWeapon.Def.Ik == null || builtWeapon.Def.Ik.ChargeLeft == null)) { Say("measure the handle first: /wa charge " + builtWeapon.Def.Id + ", then a full reload."); return; } HandDriver handDriver = null; HandDriver[] array = Resources.FindObjectsOfTypeAll(); foreach (HandDriver handDriver2 in array) { if (!((Object)(object)handDriver2 == (Object)null)) { ArsenalWeapon componentInChildren = ((Component)handDriver2).GetComponentInChildren(true); if (!((Object)(object)componentInChildren == (Object)null) && string.Equals(componentInChildren.WeaponId, builtWeapon.Def.Id, StringComparison.OrdinalIgnoreCase) && ((Component)handDriver2).gameObject.activeInHierarchy) { handDriver = handDriver2; break; } } } if ((Object)(object)handDriver == (Object)null || (Object)(object)handDriver.Anim == (Object)null) { Say("hold the weapon first - the clip is rebuilt from the one that is in your hands."); return; } ClipForge.Begin(builtWeapon, handDriver.Anim, ((Component)handDriver).transform); Say("do a FULL reload now - recording" + (ClipForge.ApplyCharge ? " and rewriting the charge." : " a faithful copy.")); } private static void Charge(string[] parts) { if (parts.Length < 3) { Say("usage: /wa charge [show|clear] - measure where this model's charging"); Say("handle is and steer the hand onto it during the racking frames of the reload."); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } string text = ((parts.Length > 3) ? parts[3].ToLowerInvariant() : "learn"); IkDef ik = builtWeapon.Def.Ik; if (text == "show") { if (ik == null || ik.ChargeLeft == null) { Say("no charge offset measured."); return; } Say("charge " + Vec(ik.ChargeLeft) + " over " + Num(ik.ChargeFrom) + "-" + Num(ik.ChargePeak) + "-" + Num(ik.ChargeTo) + " of '" + ik.ChargeClip + "' | grip returns at " + Num(ik.GripReturnAt)); } else if (text == "clear") { if (ik != null) { ik.ChargeLeft = null; } WeaponBuilder.SyncIkOnLiveInstances(builtWeapon); Say("charge offset cleared; the clip racks wherever the base weapon does."); } else { HandDriver.LearningCharge = true; Say("hold the weapon and do a FULL reload now - watching where it racks."); } } private static void Paths(string[] parts) { if (parts.Length < 3) { Say("usage: /wa paths "); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); } else { Say(AnimationLibrary.DumpPaths(builtWeapon)); } } private static void Slide(string[] parts) { //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 3) { Say("usage: /wa slide learn|keep|clear|travel |time |show|save"); Say(" learn watches the next reload and copies the rack it performs."); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } if (builtWeapon.Def.Slide == null) { builtWeapon.Def.Slide = new SlideDef(); } SlideDef slide = builtWeapon.Def.Slide; string text = ((parts.Length > 3) ? parts[3].ToLowerInvariant() : "show"); switch (text) { case "save": Save(builtWeapon.Def); return; case "show": Say(builtWeapon.Def.Id + ": travel " + Num(slide.Travel) + " | time " + Num(slide.Time) + ((slide.Offset == null) ? "" : (" | offset " + Vec(slide.Offset)))); return; case "learn": SlideDriver.Learning = true; Say("watching the next reload - reload now, then /wa slide " + builtWeapon.Def.Id + " keep"); return; case "keep": { SlideDriver slideDriver = FindDriver(builtWeapon); if ((Object)(object)slideDriver == (Object)null || !slideDriver.Captured(out var travel, out var duration)) { Say("nothing measured yet - run /wa slide " + builtWeapon.Def.Id + " learn and reload."); return; } slide.Offset = new float[3] { travel.x, travel.y, travel.z }; slide.Time = duration; WeaponBuilder.ApplySlide(builtWeapon); WeaponBuilder.SyncLiveInstances(builtWeapon); Say("kept " + Vec(slide.Offset) + " over " + Num(slide.Time) + "s. fire to compare; /wa slide " + builtWeapon.Def.Id + " save"); return; } case "clear": slide.Offset = null; WeaponBuilder.ApplySlide(builtWeapon); WeaponBuilder.SyncLiveInstances(builtWeapon); Say("measured offset cleared; back to the fire-point direction."); return; } if (parts.Length < 5 || !TryParse(parts[4], out var value)) { Say("usage: /wa slide " + builtWeapon.Def.Id + " " + text + " "); return; } switch (text) { case "travel": slide.Travel = value; break; case "offsetx": slide.Offset = Store(slide.Offset, 0, value); break; case "offsety": slide.Offset = Store(slide.Offset, 1, value); break; case "offsetz": slide.Offset = Store(slide.Offset, 2, value); break; case "time": slide.Time = Mathf.Max(0.01f, value); break; default: Say("unknown slide option '" + text + "'."); return; } WeaponBuilder.ApplySlide(builtWeapon); WeaponBuilder.SyncLiveInstances(builtWeapon); Say(builtWeapon.Def.Id + ": travel " + Num(slide.Travel) + " | time " + Num(slide.Time) + ". fire once to see it; /wa slide " + builtWeapon.Def.Id + " save"); } private static SlideDriver FindDriver(BuiltWeapon built) { SlideDriver[] array = Resources.FindObjectsOfTypeAll(); foreach (SlideDriver slideDriver in array) { if (!((Object)(object)slideDriver == (Object)null)) { ArsenalWeapon componentInChildren = ((Component)slideDriver).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && string.Equals(componentInChildren.WeaponId, built.Def.Id, StringComparison.OrdinalIgnoreCase)) { return slideDriver; } } } return null; } private static float[] Store(float[] existing, int index, float value) { float[] obj = ((existing != null && existing.Length >= 3) ? existing : new float[3]); obj[index] = value; return obj; } private static void Grip(string[] parts) { if (parts.Length < 3) { Say("usage: /wa grip [left|right] [save]"); Say("wraps the fingers onto the weapon's real surface, measured from the live skeleton."); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } bool flag = true; bool flag2 = false; for (int i = 3; i < parts.Length; i++) { switch (parts[i].ToLowerInvariant()) { case "right": flag = false; break; case "left": flag = true; break; case "save": flag2 = true; break; } } Say(GripSolver.Solve(builtWeapon, flag, apply: true, out var pose)); if (pose.Count != 0) { WeaponBuilder.SyncLiveInstances(builtWeapon); if (flag2) { Save(builtWeapon.Def); } else { Say("looks right? /wa grip " + builtWeapon.Def.Id + (flag ? "" : " right") + " save"); } } } private static void Pose(string[] parts) { //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 4) { Say("usage: /wa pose | show | bones [filter] | clear | save"); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } string text = parts[3]; switch (text.ToLowerInvariant()) { case "save": Save(builtWeapon.Def); return; case "clear": builtWeapon.Def.Pose = null; WeaponBuilder.ApplyPose(builtWeapon); Say("pose cleared; the base hand pose is back. respawn the weapon to be sure."); return; case "show": if (builtWeapon.Def.Pose == null || builtWeapon.Def.Pose.Count == 0) { Say("no pose overrides."); return; } { foreach (KeyValuePair item in builtWeapon.Def.Pose) { Say(" " + item.Key + " " + Vec(item.Value)); } return; } case "bones": { string text2 = ((parts.Length > 4) ? parts[4].ToLowerInvariant() : null); List list = WeaponBuilder.BoneNames(builtWeapon); int num = 0; foreach (string item2 in list) { if (text2 == null || item2.ToLowerInvariant().IndexOf(text2) >= 0) { Say(" " + item2); if (++num >= 20) { Say(" ... " + list.Count + " total; pass a filter to narrow."); break; } } } if (num == 0) { Say("no bone matched. " + list.Count + " bones total."); } return; } } if (!TryParseVector(parts, 4, out var value)) { Say("usage: /wa pose " + builtWeapon.Def.Id + " " + text + " "); Say("current: " + Vec3(WeaponBuilder.CurrentLocalEuler(builtWeapon, text))); return; } if (builtWeapon.Def.Pose == null) { builtWeapon.Def.Pose = new Dictionary(); } builtWeapon.Def.Pose[text] = new float[3] { value.x, value.y, value.z }; WeaponBuilder.ApplyPose(builtWeapon); Say(text + " -> " + Vec3(value) + ". looks right? /wa pose " + builtWeapon.Def.Id + " save"); } private static void Ik(string[] parts) { //IL_00f1: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 4) { Say("usage: /wa ik left|right (or 'show', or 'save')"); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } string text = parts[3].ToLowerInvariant(); int num; switch (text) { case "save": Save(builtWeapon.Def); return; case "show": { bool[] array = new bool[2] { true, false }; foreach (bool flag in array) { Transform val = WeaponBuilder.FindIkTarget(builtWeapon, flag); if ((Object)(object)val == (Object)null) { Say((flag ? "l_IK " : "r_IK ") + "(missing)"); continue; } string[] obj = new string[5] { flag ? "l_IK " : "r_IK ", "pos ", Vec3(val.localPosition), " | rot ", null }; Quaternion localRotation = val.localRotation; obj[4] = Vec3(((Quaternion)(ref localRotation)).eulerAngles); Say(string.Concat(obj)); } return; } case "chargenudge": ChargeNudge(builtWeapon, parts); return; case "chargewindow": case "gripreturn": ChargeWindow(builtWeapon, text, parts); return; default: num = ((text == "reloadleftrot") ? 1 : 0); break; case "leftrot": case "rightrot": num = 1; break; } int num2; switch (text) { default: num2 = ((text == "chargeleft") ? 1 : 0); break; case "left": case "right": case "reloadleft": num2 = 1; break; } bool flag2 = (byte)num2 != 0; if (num == 0 && !flag2) { Say("usage: /wa ik left|right|leftrot|rightrot|reloadleft|reloadleftrot "); Say(" reloadleft steers the hand during the reload clip only - it is a delta on top"); Say(" of the animation, so 0 0 0 means 'play it exactly as the developers made it'."); return; } if (!TryParseVector(parts, 4, out var value)) { Say("usage: /wa ik " + builtWeapon.Def.Id + " " + text + " "); return; } if (builtWeapon.Def.Ik == null) { builtWeapon.Def.Ik = new IkDef(); } float[] array2 = new float[3] { value.x, value.y, value.z }; switch (text) { case "left": builtWeapon.Def.Ik.Left = array2; break; case "right": builtWeapon.Def.Ik.Right = array2; break; case "leftrot": builtWeapon.Def.Ik.LeftRotation = array2; break; case "reloadleft": builtWeapon.Def.Ik.ReloadLeft = array2; break; case "reloadleftrot": builtWeapon.Def.Ik.ReloadLeftRotation = array2; break; case "chargeleft": builtWeapon.Def.Ik.ChargeLeft = array2; break; default: builtWeapon.Def.Ik.RightRotation = array2; break; } WeaponBuilder.ApplyIk(builtWeapon); WeaponBuilder.SyncIkOnLiveInstances(builtWeapon); Say(text + " -> " + Vec3(value) + ". looks right? /wa ik " + builtWeapon.Def.Id + " save"); } private static void ChargeWindow(BuiltWeapon built, string op, string[] parts) { if (built.Def.Ik == null) { built.Def.Ik = new IkDef(); } IkDef ik = built.Def.Ik; if (op == "gripreturn") { if (parts.Length < 5 || !TryParse(parts[4], out var value)) { Say("usage: /wa ik " + built.Def.Id + " gripreturn <0..1> (now " + Num(ik.GripReturnAt) + ")"); return; } ik.GripReturnAt = Mathf.Clamp01(value); } else { if (parts.Length < 7 || !TryParse(parts[4], out var value2) || !TryParse(parts[5], out var value3) || !TryParse(parts[6], out var value4)) { Say("usage: /wa ik " + built.Def.Id + " chargewindow "); Say(" now " + Num(ik.ChargeFrom) + " " + Num(ik.ChargePeak) + " " + Num(ik.ChargeTo)); return; } ik.ChargeFrom = Mathf.Clamp01(value2); ik.ChargePeak = Mathf.Clamp01(value3); ik.ChargeTo = Mathf.Clamp01(value4); } WeaponBuilder.SyncIkOnLiveInstances(built); Say("window " + Num(ik.ChargeFrom) + "-" + Num(ik.ChargePeak) + "-" + Num(ik.ChargeTo) + " | grip returns at " + Num(ik.GripReturnAt) + ". reload to check; /wa ik " + built.Def.Id + " save"); } private static void ChargeNudge(BuiltWeapon built, string[] parts) { //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_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: 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_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: 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_022c: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 6 || !TryParse(parts[5], out var value)) { Say("usage: /wa ik " + built.Def.Id + " chargenudge left|right|up|down|forward|back "); return; } Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.CamObject == (Object)null) { Say("no local player to take directions from."); return; } Transform val = WeaponBuilder.FindIkTarget(built, left: true); if ((Object)(object)val == (Object)null || (Object)(object)val.parent == (Object)null) { Say("no l_IK on this weapon."); return; } Transform camObject = localPlayer.CamObject; Vector3 val2; switch (parts[4].ToLowerInvariant()) { case "right": val2 = camObject.right; break; case "left": val2 = -camObject.right; break; case "up": val2 = camObject.up; break; case "down": val2 = -camObject.up; break; case "forward": val2 = camObject.forward; break; case "back": val2 = -camObject.forward; break; default: Say("direction must be left, right, up, down, forward or back."); return; } Vector3 val3 = val.parent.InverseTransformDirection(val2); Vector3 val4 = ((Vector3)(ref val3)).normalized * value; if (built.Def.Ik == null) { built.Def.Ik = new IkDef(); } IkDef ik = built.Def.Ik; Vector3 val5 = (Vector3)((ik.ChargeLeft != null && ik.ChargeLeft.Length >= 3) ? new Vector3(ik.ChargeLeft[0], ik.ChargeLeft[1], ik.ChargeLeft[2]) : Vector3.zero); Vector3 val6 = val5 + val4; ik.ChargeLeft = new float[3] { val6.x, val6.y, val6.z }; WeaponBuilder.SyncIkOnLiveInstances(built); bool flag = ClipForge.HasRecording && ClipForge.ApplyCharge && ClipForge.Rebake(); Say("charge " + Vec3(val5) + " -> " + Vec3(val6) + " (" + parts[4] + " " + Num(value) + ")"); Say(flag ? ("clip re-baked - reload to see it; /wa ik " + built.Def.Id + " save") : ("reload to check; /wa ik " + built.Def.Id + " save")); } private static void Anchors(string[] parts) { //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0242: 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_024b: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 3) { Say("usage: /wa anchors "); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } if (builtWeapon.Targets.Count == 0) { Say("weapon has no model target."); return; } ModelSwapTarget modelSwapTarget = builtWeapon.Targets[0]; Transform val = (((Object)(object)modelSwapTarget.Skinned != (Object)null && (Object)(object)modelSwapTarget.Skinned.rootBone != (Object)null) ? modelSwapTarget.Skinned.rootBone : builtWeapon.Prefab.transform); Plugin.Log.LogInfo((object)("=== anchors: " + builtWeapon.Def.Id + " (space = '" + ((Object)val).name + "') ===")); Transform[] componentsInChildren = builtWeapon.Prefab.GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { string name = ((Object)val2).name; if (name.EndsWith("_IK") || name == "Gun" || name == "Mag" || name == "Slide") { Plugin.Log.LogInfo((object)(" " + name + " at " + Vec3(val.InverseTransformPoint(val2.position)))); } } string[] array = new string[3] { "_firePoint", "_adsPos", "_aimPos" }; foreach (string text in array) { object obj = Refl.Get(builtWeapon.Weapon, text); Transform val3 = (Transform)((obj is Transform) ? obj : null); if (!((Object)(object)val3 == (Object)null)) { Plugin.Log.LogInfo((object)(" " + text + " at " + Vec3(val.InverseTransformPoint(val3.position)))); } } Mesh fittedMesh = modelSwapTarget.FittedMesh; if ((Object)(object)fittedMesh != (Object)null) { ManualLogSource log = Plugin.Log; Bounds bounds = fittedMesh.bounds; string text2 = Vec3(((Bounds)(ref bounds)).center); bounds = fittedMesh.bounds; log.LogInfo((object)(" fitted mesh centre " + text2 + ", size " + Vec3(((Bounds)(ref bounds)).size))); } Say("dumped anchors for '" + builtWeapon.Def.Id + "' to the BepInEx log."); } private static string Vec3(Vector3 v) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; return "(" + v.x.ToString("F2", invariantCulture) + ", " + v.y.ToString("F2", invariantCulture) + ", " + v.z.ToString("F2", invariantCulture) + ")"; } private static string JoinRest(string[] parts, int start) { return string.Join(" ", parts, start, parts.Length - start).Trim().Trim(new char[1] { '"' }); } private static void Part(string[] parts) { //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 4) { Say("usage: /wa part "); return; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(parts[2])); if (builtWeapon == null) { Say("no built weapon '" + parts[2] + "'."); return; } int num = 0; int[] array = ((builtWeapon.Model == null) ? null : builtWeapon.Model.GroupIds); if (array != null) { int[] array2 = array; foreach (int num2 in array2) { if (num2 + 1 > num) { num = num2 + 1; } } } if (num == 0) { Say("model has no part information."); return; } string text = parts[3].ToLowerInvariant(); if (text == "all") { builtWeapon.IsolatePart = -1; } else if (text == "next") { builtWeapon.IsolatePart = (builtWeapon.IsolatePart + 1) % num; } else { if (!int.TryParse(text, out var result) || result < 0 || result >= num) { Say("index must be 0.." + (num - 1) + ", 'next' or 'all'."); return; } builtWeapon.IsolatePart = result; } WeaponBuilder.Refit(builtWeapon); WeaponBuilder.SyncLiveInstances(builtWeapon); if (builtWeapon.IsolatePart < 0) { Say("showing the whole model again (" + num + " parts)"); return; } Say("showing ONLY part " + builtWeapon.IsolatePart + " of " + (num - 1) + " - is this the magazine?"); if (builtWeapon.Targets.Count > 0 && (Object)(object)builtWeapon.Targets[0].FittedMesh != (Object)null) { Bounds bounds = builtWeapon.Targets[0].FittedMesh.bounds; int num3 = builtWeapon.Targets[0].FittedMesh.triangles.Length / 3; string text2 = "part " + builtWeapon.IsolatePart + ": " + num3 + " tris, centre " + Vec3(((Bounds)(ref bounds)).center) + ", size " + Vec3(((Bounds)(ref bounds)).size); Say(text2); Plugin.Log.LogInfo((object)text2); } } private static void Bones(string[] parts) { float value = 6f; if (parts.Length > 2) { TryParse(parts[2], out value); } value = Mathf.Clamp(value, 1f, 30f); Say(BoneRecorder.Start(value)); } private static void Prop(string[] parts) { //IL_05b6: Unknown result type (might be due to invalid IL or missing references) //IL_05c0: Unknown result type (might be due to invalid IL or missing references) //IL_05ca: Unknown result type (might be due to invalid IL or missing references) //IL_05f2: Unknown result type (might be due to invalid IL or missing references) //IL_05fc: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_0647: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_064c: Unknown result type (might be due to invalid IL or missing references) //IL_064e: Unknown result type (might be due to invalid IL or missing references) //IL_0650: Unknown result type (might be due to invalid IL or missing references) //IL_0652: Unknown result type (might be due to invalid IL or missing references) //IL_0657: Unknown result type (might be due to invalid IL or missing references) //IL_0662: Unknown result type (might be due to invalid IL or missing references) //IL_066c: Unknown result type (might be due to invalid IL or missing references) //IL_0676: Unknown result type (might be due to invalid IL or missing references) //IL_0640: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) if (parts.Length < 3 || string.Equals(parts[2], "list", StringComparison.OrdinalIgnoreCase)) { if (PropPlacer.All.Count == 0) { Say("no props defined - add weapons/props.json"); return; } foreach (PropDef item in PropPlacer.All) { GameObject val = PropPlacer.LiveObject(item.Id); Say(item.Id + (item.Enabled ? "" : " [disabled]") + " scale " + item.Scale + (((Object)(object)val != (Object)null) ? " [placed]" : " [not here]")); } Say("/wa prop pos|rot | height | scale | nudge | here | show | save"); return; } string text = parts[2]; PropDef propDef = PropPlacer.Find(text); if (propDef == null) { Say("no prop '" + text + "' - /wa prop list"); return; } string text2 = ((parts.Length > 3) ? parts[3].ToLowerInvariant() : "show"); switch (text2) { case "show": Say(propDef.Id + " pos " + VecText(propDef.Position) + " rot " + VecText(propDef.Rotation) + (propDef.TargetHeight.HasValue ? (" height " + propDef.TargetHeight.Value + " m") : (" scale " + propDef.Scale))); break; case "reload": PropPlacer.Load(); Say(PropPlacer.PlaceNow()); break; case "save": Say(PropPlacer.Save()); break; case "here": { Player localPlayer = Player.LocalPlayer; Camera val3 = (((Object)(object)localPlayer != (Object)null) ? localPlayer.CurCam : null); if ((Object)(object)val3 == (Object)null) { Say("no local player camera - load into a game first"); break; } Transform transform = ((Component)val3).transform; Vector3 val4 = transform.position + transform.forward * 2.5f; RaycastHit val5 = default(RaycastHit); if (Physics.Raycast(val4 + Vector3.up * 3f, Vector3.down, ref val5, 30f)) { val4.y = ((RaycastHit)(ref val5)).point.y; } propDef.Position = new float[3] { val4.x, val4.y, val4.z }; Vector3 val6 = transform.position - val4; val6.y = 0f; if (((Vector3)(ref val6)).sqrMagnitude > 0.0001f) { float[] array = new float[3]; Quaternion val7 = Quaternion.LookRotation(val6, Vector3.up); array[1] = ((Quaternion)(ref val7)).eulerAngles.y; propDef.Rotation = array; } Say("moved " + propDef.Id + " to " + VecText(propDef.Position) + " rot " + VecText(propDef.Rotation)); Say(PropPlacer.PlaceNow()); Say("/wa prop " + propDef.Id + " save to keep it"); break; } case "scale": { if (parts.Length < 5 || !TryParse(parts[4], out var value2)) { Say("/wa prop " + propDef.Id + " scale (or: height )"); break; } propDef.TargetHeight = null; propDef.Scale = value2; Say(PropPlacer.PlaceNow()); break; } case "height": { if (parts.Length < 5 || !TryParse(parts[4], out var value3)) { Say("/wa prop " + propDef.Id + " height "); break; } propDef.TargetHeight = value3; Say(propDef.Id + " target height " + value3 + " m"); Say(PropPlacer.PlaceNow()); break; } case "nudge": case "pos": case "rot": { if (!TryParseVector(parts, 4, out var value)) { Say("/wa prop " + propDef.Id + " " + text2 + " "); break; } if (text2 == "pos") { propDef.Position = new float[3] { value.x, value.y, value.z }; } else if (text2 == "rot") { propDef.Rotation = new float[3] { value.x, value.y, value.z }; } else { Vector3 val2 = (Vector3)((propDef.Position == null || propDef.Position.Length < 3) ? Vector3.zero : new Vector3(propDef.Position[0], propDef.Position[1], propDef.Position[2])); val2 += value; propDef.Position = new float[3] { val2.x, val2.y, val2.z }; } Say(propDef.Id + " pos " + VecText(propDef.Position) + " rot " + VecText(propDef.Rotation)); Say(PropPlacer.PlaceNow()); break; } default: Say("/wa prop pos|rot | height | scale | nudge | here | show | save | reload"); break; } } private static string VecText(float[] v) { if (v != null && v.Length >= 3) { return "(" + v[0].ToString("0.##") + ", " + v[1].ToString("0.##") + ", " + v[2].ToString("0.##") + ")"; } return "(0, 0, 0)"; } private static void Islands() { if (IslandCatalog.Total <= 0) { Say("island list not available - load into a game first."); return; } Say("islands (> = current):"); foreach (string item in IslandCatalog.Describe()) { Say(item); Plugin.Log.LogInfo((object)("island " + item)); } int islandIndex = IslandCatalog.Resolve(Plugin.Cfg.ShopIslandName.Value, Plugin.Cfg.ShopIslandIndex.Value); Say("shop island is " + islandIndex + " (" + (IslandCatalog.SceneName(islandIndex) ?? "?") + ")"); Say("set ShopIslandName in the config to pick by scene name."); } private static void Shop() { OnlineIslandManager instance = OnlineIslandManager.Instance; if ((Object)(object)instance == (Object)null) { Say("OnlineIslandManager not ready - load into a game first."); return; } if (!InstanceFinder.IsServerStarted) { Say("only the host can change islands."); return; } int total = IslandCatalog.Total; int num = IslandCatalog.Resolve(Plugin.Cfg.ShopIslandName.Value, Plugin.Cfg.ShopIslandIndex.Value); if (num < 0 || num >= total) { Say("island " + num + " is out of range (0.." + (total - 1) + ")."); } else if (IslandCatalog.Current() == num) { Say(ShopPlacer.PlaceNow()); } else { instance.UnlockIsland((byte)num); OnlineIslandManager.TpToSpecificIsland((byte)num); Say("unlocking and travelling to island " + num + " (" + (IslandCatalog.SceneName(num) ?? "?") + ")."); Say("stands are placed when the island finishes loading - check the gun rack."); } } private static void Give(string[] parts) { if (parts.Length < 3) { Say("usage: /wa give "); List(); return; } string text = parts[2]; BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(text)); string error; if (builtWeapon == null) { Say("no built weapon with id '" + text + "'. Try /wa list."); } else if (WeaponSpawner.TrySpawn(builtWeapon, out error)) { Say("spawned " + (builtWeapon.Def.DisplayName ?? text) + " in front of you."); Say("align it with /wa fit " + text + " scale|pos|rot, then /wa fit " + text + " save"); } else { Say("could not spawn: " + error); } } private static void Reload() { if ((Object)(object)Plugin.Runtime == (Object)null) { Say("runtime not ready."); return; } Plugin.Runtime.Rebuild(); Say("reloading weapon defs from " + Plugin.WeaponsFolder); } private static void Fit(string[] parts) { //IL_04eb: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0489: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_04ad: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b4: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Cfg.LiveTuning.Value) { Say("live tuning is disabled in the config."); return; } if (parts.Length < 3) { Say("usage: /wa fit auto|flip|roll|reverse|scale|pos|rot|show|save [values]"); return; } string text = parts[2]; BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(text)); if (builtWeapon == null) { Say("no built weapon with id '" + text + "'. Try /wa list."); return; } string text2 = ((parts.Length > 3) ? parts[3].ToLowerInvariant() : "show"); ModelDef model = builtWeapon.Def.Model; switch (text2) { case "show": Say(text + ": scale " + Num(model.Scale) + " | pos " + Vec(model.Position) + " | rot " + Vec(model.Rotation) + " | fitToBase " + model.FitToBase); return; case "scale": { if (parts.Length < 5 || !TryParse(parts[4], out var value4)) { Say("usage: /wa fit " + text + " scale "); return; } model.Scale = value4; break; } case "pos": { if (!TryParseVector(parts, 4, out var value3)) { Say("usage: /wa fit " + text + " pos "); return; } model.Position = new float[3] { value3.x, value3.y, value3.z }; break; } case "rot": { if (!TryParseVector(parts, 4, out var value2)) { Say("usage: /wa fit " + text + " rot "); return; } model.Rotation = new float[3] { value2.x, value2.y, value2.z }; break; } case "auto": { Vector3 val3 = WeaponBuilder.SuggestRotation(builtWeapon); model.Rotation = new float[3] { val3.x, val3.y, val3.z }; Say("aligned the model's long axis to the base weapon's."); Say("roll around the barrel is not derivable from bounds - nudge it by hand if needed."); break; } case "flip": { Vector3 val4 = WeaponBuilder.RotateAboutBarrel(builtWeapon, 180f); model.Rotation = new float[3] { val4.x, val4.y, val4.z }; Say("flipped 180 around the barrel."); break; } case "roll": { if (parts.Length < 5 || !TryParse(parts[4], out var value5)) { Say("usage: /wa fit " + text + " roll "); return; } Vector3 val5 = WeaponBuilder.RotateAboutBarrel(builtWeapon, value5); model.Rotation = new float[3] { val5.x, val5.y, val5.z }; break; } case "nudge": { if (!TryParseVector(parts, 4, out var value)) { Say("usage: /wa fit " + text + " nudge "); return; } Vector3 val = (Vector3)((model.Position != null && model.Position.Length >= 3) ? new Vector3(model.Position[0], model.Position[1], model.Position[2]) : Vector3.zero) + value; model.Position = new float[3] { val.x, val.y, val.z }; break; } case "reverse": { Vector3 val2 = WeaponBuilder.RotateAboutPerpendicular(builtWeapon, 180f); model.Rotation = new float[3] { val2.x, val2.y, val2.z }; Say("turned the model end for end."); break; } case "material": { string text3 = ((parts.Length > 4) ? parts[4].ToLowerInvariant() : null); if (text3 != "vanilla" && text3 != "model" && text3 != "colors") { Say("usage: /wa fit " + text + " material vanilla|model|colors"); Say("current: " + model.Material); } else if (WeaponBuilder.SwitchMaterial(builtWeapon, text3, Plugin.Registry.WeaponsFolder)) { Say("material set to '" + text3 + "'. See the log for the shader used."); } else { Say("could not switch material; check the log."); } return; } case "save": Save(builtWeapon.Def); return; default: Say("unknown fit operation '" + text2 + "'."); return; } WeaponBuilder.Refit(builtWeapon); WeaponBuilder.SyncLiveInstances(builtWeapon); Say(text + ": scale " + Num(model.Scale) + " | pos " + Vec(model.Position) + " | rot " + Vec(model.Rotation)); Say("looks right? /wa fit " + text + " save"); } private static void Save(WeaponDef def) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown if (string.IsNullOrEmpty(def.SourcePath)) { Say("no source file recorded for '" + def.Id + "'."); return; } try { JsonSerializerSettings val = new JsonSerializerSettings { NullValueHandling = (NullValueHandling)1 }; string contents = JsonConvert.SerializeObject((object)def, (Formatting)1, val); File.WriteAllText(def.SourcePath, contents); string text = MirrorPath(def); if (text != null) { File.WriteAllText(text, contents); Say("saved " + Path.GetFileName(def.SourcePath) + " (and mirrored to the repo)"); Plugin.Log.LogInfo((object)("Mirrored tuned def to " + text)); } else { Say("saved " + Path.GetFileName(def.SourcePath)); Say("WARNING: not mirrored - the next plugin build will overwrite this."); Plugin.Log.LogWarning((object)"Tuned def was NOT mirrored. Set SourceWeaponsFolder in the config to this mod's repository weapons folder, or every rebuild discards what you tune in game."); } Plugin.Log.LogInfo((object)("Wrote tuned def to " + def.SourcePath + " | scale " + Num(def.Model.Scale) + " | pos " + Vec(def.Model.Position) + " | rot " + Vec(def.Model.Rotation) + " | pose " + ((def.Pose != null) ? def.Pose.Count : 0) + " bone(s)")); } catch (Exception ex) { Say("save failed: " + ex.Message); } } private static string MirrorPath(WeaponDef def) { string value = Plugin.Cfg.SourceWeaponsFolder.Value; if (string.IsNullOrEmpty(value) || !Directory.Exists(value)) { return null; } string text = Path.Combine(value, Path.GetFileName(def.SourcePath)); if (!(Path.GetFullPath(text) == Path.GetFullPath(def.SourcePath))) { return text; } return null; } private static void Help() { Say("/wa status - version, def count, fingerprint, registration state"); Say("/wa list - weapon defs and whether they built"); Say("/wa bases - vanilla weapon prefabs available as basePrefab"); Say("/wa give - spawn a custom weapon in front of you (host only)"); Say("/wa inspect - dump a prefab's renderer hierarchy to the BepInEx log"); Say("/wa shop - unlock and travel to the shop island (host only)"); Say("/wa islands - list island indices and their scene names"); Say("/wa prop [id] ... - place and move scenery props; list|pos|rot|scale|nudge|here|show|save"); Say("/wa bones [seconds] - record what the weapon's own animation moves, hand IK targets included"); Say(" (the mod's hand override is suspended while it runs - reload while it does)"); Say("/wa anchors - log hand IK targets, fire point and ADS pose in mesh space"); Say("/wa ik left|right|leftrot|rightrot - hand pos/rot; show|save"); Say("/wa ik reloadleft - steer the hand during the reload clip only"); Say("/wa auto - solve alignment AND hand placement, then save"); Say("/wa pose - rotate any bone (finger curl); bones|show|clear|save"); Say("/wa grip [left|right] [save] - wrap the fingers onto the model, solved from geometry"); Say("/wa slide learn -> reload -> keep - copy the rack from the reload clip"); Say("/wa slide travel |time - charging handle throw and speed; show|clear|save"); Say("/wa charge - MEASURE the charging handle offset from a full reload; show|clear"); Say("/wa forge [charge]|restore - rebuild ReloadLast as a real clip; restore undoes it"); Say("/wa ads nudge up|down|left|right|forward|back - line the iron sights up; show|save"); Say("/wa ik chargenudge left|right|up|down|forward|back - nudge it as you see it"); Say("/wa ik chargewindow | gripreturn - when the racking happens"); Say("/wa ik chargeleft - the same offset by hand, if the measurement misses"); Say(" during the racking frames of the reload only"); Say("/wa paths - transform paths an authored AnimationClip must bind to"); Say("/wa fit nudge - move the model by a small delta"); Say("/wa part next - show one model part at a time to identify it"); Say("/wa fit show - current alignment numbers"); Say("/wa fit auto - guess a rotation from the base weapon's proportions"); Say("/wa fit flip - 180 around the barrel, for an upside-down model"); Say("/wa fit roll - any angle around the barrel"); Say("/wa fit reverse - end for end, when the barrel points backwards"); Say("/wa fit scale "); Say("/wa fit pos "); Say("/wa fit rot "); Say("/wa fit save - write the tuned numbers back to the def"); Say("/wa reload - reload defs from disk and rebuild"); } private static bool TryParse(string text, out float value) { return float.TryParse((text ?? "").Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out value); } private static bool TryParseVector(string[] parts, int start, out Vector3 value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) value = Vector3.zero; if (parts.Length < start + 3) { return false; } if (!TryParse(parts[start], out var value2)) { return false; } if (!TryParse(parts[start + 1], out var value3)) { return false; } if (!TryParse(parts[start + 2], out var value4)) { return false; } value = new Vector3(value2, value3, value4); return true; } private static string Num(float value) { return value.ToString("F3", CultureInfo.InvariantCulture); } private static string Vec(float[] values) { if (values == null || values.Length < 3) { return "0 0 0"; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(Num(values[0])).Append(' ').Append(Num(values[1])) .Append(' ') .Append(Num(values[2])); return stringBuilder.ToString(); } private static void Say(string message) { try { ChatManager.ChatMessage("[WA] " + message); } catch { Plugin.Log.LogInfo((object)("[WA] " + message)); } } } [HarmonyPatch(typeof(InventorySlot), "SetItem")] internal static class InventorySlotSetItemPatch { private sealed class SlotState { public Material[] Original; public Material[] Wrote; } private static readonly Dictionary States = new Dictionary(); private static bool _logged; [HarmonyPostfix] private static void Postfix(InventorySlot __instance, Item item) { if (Plugin.Cfg == null || !Plugin.Cfg.Enabled.Value || (Object)(object)__instance == (Object)null) { return; } object obj = Refl.Get(__instance, "_renderer"); Renderer val = (Renderer)((obj is Renderer) ? obj : null); if ((Object)(object)val == (Object)null) { return; } Material[] array = MaterialsFor(item); if (array == null) { Revert(__instance, val); return; } if (!States.TryGetValue(__instance, out var value)) { value = new SlotState(); States[__instance] = value; } if (!Same(val.sharedMaterials, value.Wrote)) { value.Original = val.sharedMaterials; } val.sharedMaterials = array; value.Wrote = array; LogOnce(__instance, val, array); } private static bool Same(Material[] a, Material[] b) { if (a == null || b == null) { return a == b; } if (a.Length != b.Length) { return false; } for (int i = 0; i < a.Length; i++) { if ((Object)(object)a[i] != (Object)(object)b[i]) { return false; } } return true; } private static void LogOnce(InventorySlot slot, Renderer renderer, Material[] applied) { if (!_logged && Plugin.Cfg != null && Plugin.Cfg.VerboseLogging.Value) { _logged = true; object obj = Refl.Get(slot, "_filter"); MeshFilter val = (MeshFilter)((obj is MeshFilter) ? obj : null); Mesh val2 = (((Object)(object)val != (Object)null) ? val.sharedMesh : null); Plugin.Log.LogInfo((object)("Hotbar slot: mesh '" + (((Object)(object)val2 == (Object)null) ? "" : ((Object)val2).name) + "' submeshes=" + ((!((Object)(object)val2 == (Object)null)) ? val2.subMeshCount : 0) + ", applied " + applied.Length + " material(s).")); } } private static Material[] MaterialsFor(Item item) { if ((Object)(object)item == (Object)null) { return null; } ArsenalWeapon componentInParent = ((Component)item).GetComponentInParent(true); if ((Object)(object)componentInParent == (Object)null) { return null; } BuiltWeapon builtWeapon = (((Object)(object)Plugin.Runtime == (Object)null) ? null : Plugin.Runtime.Find(componentInParent.WeaponId)); if (builtWeapon == null) { return null; } for (int i = 0; i < builtWeapon.Targets.Count; i++) { ModelSwapTarget modelSwapTarget = builtWeapon.Targets[i]; if (modelSwapTarget != null && !((Object)(object)modelSwapTarget.Renderer == (Object)null)) { Material[] sharedMaterials = modelSwapTarget.Renderer.sharedMaterials; if (sharedMaterials != null && sharedMaterials.Length != 0 && (Object)(object)sharedMaterials[0] != (Object)null) { return sharedMaterials; } } } return null; } private static void Revert(InventorySlot slot, Renderer renderer) { if (States.TryGetValue(slot, out var value)) { if (value.Wrote != null && Same(renderer.sharedMaterials, value.Wrote) && value.Original != null) { renderer.sharedMaterials = value.Original; } States.Remove(slot); } } public static void ClearCache() { States.Clear(); } } [HarmonyPatch(typeof(Item), "GetName")] internal static class ItemGetNamePatch { [HarmonyPostfix] private static void Postfix(Item __instance, ref string __result) { if (Plugin.Cfg == null || !Plugin.Cfg.Enabled.Value) { return; } ArsenalWeapon componentInParent = ((Component)__instance).GetComponentInParent(true); if (!((Object)(object)componentInParent == (Object)null)) { WeaponDef def = componentInParent.Def; if (def != null && !string.IsNullOrEmpty(def.DisplayName)) { __result = def.DisplayName; } } } } [HarmonyPatch(typeof(Weapon), "Awake")] internal static class WeaponAwakePatch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(Weapon __instance) { if (Plugin.Cfg == null || !Plugin.Cfg.Enabled.Value) { return; } ArsenalWeapon componentInParent = ((Component)__instance).GetComponentInParent(true); if ((Object)(object)componentInParent == (Object)null || componentInParent.RuntimeStatsApplied) { return; } WeaponDef def = componentInParent.Def; if (def != null) { WeaponBuilder.ApplyRuntimeStats(__instance, def); componentInParent.RuntimeStatsApplied = true; if (Plugin.Cfg.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Applied runtime stats to " + def.Id + " instance.")); } } } } } namespace HowToFish.WeaponArsenal.Assets { internal static class BundleSource { public static AssetBundle Resolve(string weaponsFolder, string bundleFile) { if (string.IsNullOrEmpty(bundleFile)) { return null; } BundleLoader.Log = Plugin.Log; return BundleLoader.LoadFrom(Path.Combine(weaponsFolder, bundleFile)); } private static void StripRig(Mesh mesh) { if ((mesh.bindposes != null && mesh.bindposes.Length != 0) || (mesh.boneWeights != null && mesh.boneWeights.Length != 0)) { Plugin.Log.LogInfo((object)("Dropped the imported rig from '" + ((Object)mesh).name + "' (" + mesh.bindposes.Length + " bindposes); the game's own rig is bound instead.")); mesh.boneWeights = (BoneWeight[])(object)new BoneWeight[0]; mesh.bindposes = (Matrix4x4[])(object)new Matrix4x4[0]; } } private static void ApplyAxisFix(Mesh mesh) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) Vector3[] vertices = mesh.vertices; for (int i = 0; i < vertices.Length; i++) { vertices[i] = new Vector3(0f - vertices[i].x, vertices[i].z, vertices[i].y); } mesh.vertices = vertices; Vector3[] normals = mesh.normals; if (normals != null && normals.Length == vertices.Length) { for (int j = 0; j < normals.Length; j++) { normals[j] = new Vector3(0f - normals[j].x, normals[j].z, normals[j].y); } mesh.normals = normals; } mesh.RecalculateBounds(); mesh.RecalculateTangents(); } public static LoadedModel LoadModel(AssetBundle bundle, string assetName, bool wantTextures, bool axisFix) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) Object obj = bundle.LoadAsset(assetName); if (obj == (Object)null) { throw new Exception("Asset '" + assetName + "' not found in bundle. Available: " + string.Join(", ", bundle.GetAllAssetNames())); } ReadSource(obj, out var mesh, out var materials); if ((Object)(object)mesh == (Object)null) { throw new Exception("Asset '" + assetName + "' carries no mesh."); } Mesh val = Object.Instantiate(mesh); ((Object)val).name = "WA_" + assetName; ((Object)val).hideFlags = (HideFlags)52; StripRig(val); if (axisFix) { ApplyAxisFix(val); } ManualLogSource log = Plugin.Log; string[] obj2 = new string[10] { "Bundle mesh '", assetName, "' axisFix=", axisFix.ToString(), " submeshes=", val.subMeshCount.ToString(), " bounds center=", null, null, null }; Bounds bounds = val.bounds; Vector3 val2 = ((Bounds)(ref bounds)).center; obj2[7] = ((Vector3)(ref val2)).ToString("F3"); obj2[8] = " size="; bounds = val.bounds; val2 = ((Bounds)(ref bounds)).size; obj2[9] = ((Vector3)(ref val2)).ToString("F3"); log.LogInfo((object)string.Concat(obj2)); LoadedModel loadedModel = new LoadedModel { Mesh = val, SourceFile = assetName, GroupIds = GroupIdsFromSubmeshes(val), SubmeshColors = SubmeshColors(materials, val.subMeshCount) }; if (wantTextures && materials != null && materials.Length != 0 && (Object)(object)materials[0] != (Object)null) { ShaderFix.Apply(materials[0]); loadedModel.Albedo = (Texture2D)(((object)Texture(materials[0], "_BaseMap", "baseColorTexture")) ?? ((object)/*isinst with value type is only supported in some contexts*/)); loadedModel.Normal = Texture(materials[0], "_BumpMap", "normalTexture"); } return loadedModel; } public static AudioClip LoadClip(AssetBundle bundle, string assetName) { AudioClip obj = bundle.LoadAsset(assetName); if ((Object)(object)obj == (Object)null) { Plugin.Log.LogWarning((object)("AudioClip '" + assetName + "' not found in bundle. Available: " + string.Join(", ", bundle.GetAllAssetNames()))); } return obj; } private static Texture2D Texture(Material material, params string[] properties) { foreach (string text in properties) { if (material.HasProperty(text)) { Texture texture = material.GetTexture(text); Texture2D val = (Texture2D)(object)((texture is Texture2D) ? texture : null); if ((Object)(object)val != (Object)null) { return val; } } } return null; } private static bool TryColor(Material material, out Color color) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[3] { "_BaseColor", "baseColorFactor", "_Color" }; foreach (string text in array) { if (material.HasProperty(text)) { color = material.GetColor(text); return true; } } color = Color.white; return false; } private static void ReadSource(Object source, out Mesh mesh, out Material[] materials) { mesh = (Mesh)(object)((source is Mesh) ? source : null); materials = null; if ((Object)(object)mesh != (Object)null) { return; } GameObject val = (GameObject)(object)((source is GameObject) ? source : null); if ((Object)(object)val == (Object)null) { return; } SkinnedMeshRenderer componentInChildren = val.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { mesh = componentInChildren.sharedMesh; materials = ((Renderer)componentInChildren).sharedMaterials; return; } MeshFilter componentInChildren2 = val.GetComponentInChildren(true); if (!((Object)(object)componentInChildren2 == (Object)null)) { mesh = componentInChildren2.sharedMesh; MeshRenderer component = ((Component)componentInChildren2).GetComponent(); if ((Object)(object)component != (Object)null) { materials = ((Renderer)component).sharedMaterials; } } } private static int[] GroupIdsFromSubmeshes(Mesh mesh) { if (mesh.subMeshCount <= 1) { return null; } int[] array = new int[mesh.vertexCount]; for (int i = 0; i < mesh.subMeshCount; i++) { int[] triangles = mesh.GetTriangles(i); foreach (int num in triangles) { if (num >= 0 && num < array.Length) { array[num] = i; } } } return array; } private static Color[] SubmeshColors(Material[] materials, int subMeshCount) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (materials == null || materials.Length == 0 || subMeshCount <= 0) { return null; } Color[] array = (Color[])(object)new Color[subMeshCount]; bool flag = false; for (int i = 0; i < subMeshCount; i++) { array[i] = Color.white; Material val = ((i < materials.Length) ? materials[i] : null); if (!((Object)(object)val == (Object)null) && TryColor(val, out var color)) { array[i] = color; flag = true; } } if (!flag) { return null; } return array; } } internal sealed class GltfAssetExtras { [JsonProperty("title")] public string Title; [JsonProperty("author")] public string Author; [JsonProperty("license")] public string License; [JsonProperty("source")] public string Source; } internal sealed class GltfAsset { [JsonProperty("version")] public string Version; [JsonProperty("generator")] public string Generator; [JsonProperty("extras")] public GltfAssetExtras Extras; } internal sealed class GltfScene { [JsonProperty("name")] public string Name; [JsonProperty("nodes")] public int[] Nodes; } internal sealed class GltfNode { [JsonProperty("name")] public string Name; [JsonProperty("mesh")] public int? Mesh; [JsonProperty("skin")] public int? Skin; [JsonProperty("children")] public int[] Children; [JsonProperty("matrix")] public float[] Matrix; [JsonProperty("translation")] public float[] Translation; [JsonProperty("rotation")] public float[] Rotation; [JsonProperty("scale")] public float[] Scale; } internal sealed class GltfPrimitive { [JsonProperty("attributes")] public Dictionary Attributes; [JsonProperty("indices")] public int? Indices; [JsonProperty("material")] public int? Material; [JsonProperty("mode")] public int? Mode; } internal sealed class GltfMesh { [JsonProperty("name")] public string Name; [JsonProperty("primitives")] public List Primitives; } internal sealed class GltfAccessor { [JsonProperty("bufferView")] public int? BufferView; [JsonProperty("byteOffset")] public int ByteOffset; [JsonProperty("componentType")] public int ComponentType; [JsonProperty("count")] public int Count; [JsonProperty("type")] public string Type; [JsonProperty("normalized")] public bool Normalized; [JsonProperty("sparse")] public object Sparse; } internal sealed class GltfBufferView { [JsonProperty("buffer")] public int Buffer; [JsonProperty("byteOffset")] public int ByteOffset; [JsonProperty("byteLength")] public int ByteLength; [JsonProperty("byteStride")] public int? ByteStride; } internal sealed class GltfBuffer { [JsonProperty("byteLength")] public int ByteLength; [JsonProperty("uri")] public string Uri; } internal sealed class GltfTextureRef { [JsonProperty("index")] public int Index; [JsonProperty("texCoord")] public int TexCoord; } internal sealed class GltfPbrMetallicRoughness { [JsonProperty("baseColorTexture")] public GltfTextureRef BaseColorTexture; [JsonProperty("baseColorFactor")] public float[] BaseColorFactor; } internal sealed class GltfSpecularGlossiness { [JsonProperty("diffuseTexture")] public GltfTextureRef DiffuseTexture; [JsonProperty("diffuseFactor")] public float[] DiffuseFactor; } internal sealed class GltfMaterialExtensions { [JsonProperty("KHR_materials_pbrSpecularGlossiness")] public GltfSpecularGlossiness SpecularGlossiness; } internal sealed class GltfMaterial { [JsonProperty("name")] public string Name; [JsonProperty("pbrMetallicRoughness")] public GltfPbrMetallicRoughness Pbr; [JsonProperty("normalTexture")] public GltfTextureRef NormalTexture; [JsonProperty("extensions")] public GltfMaterialExtensions Extensions; public int? AlbedoTextureIndex { get { if (Pbr != null && Pbr.BaseColorTexture != null) { return Pbr.BaseColorTexture.Index; } GltfSpecularGlossiness gltfSpecularGlossiness = ((Extensions == null) ? null : Extensions.SpecularGlossiness); if (gltfSpecularGlossiness != null && gltfSpecularGlossiness.DiffuseTexture != null) { return gltfSpecularGlossiness.DiffuseTexture.Index; } return null; } } } internal sealed class GltfTexture { [JsonProperty("source")] public int? Source; [JsonProperty("sampler")] public int? Sampler; } internal sealed class GltfImage { [JsonProperty("bufferView")] public int? BufferView; [JsonProperty("mimeType")] public string MimeType; [JsonProperty("uri")] public string Uri; [JsonProperty("name")] public string Name; } internal sealed class GltfRoot { [JsonProperty("asset")] public GltfAsset Asset; [JsonProperty("scene")] public int? Scene; [JsonProperty("scenes")] public List Scenes; [JsonProperty("nodes")] public List Nodes; [JsonProperty("meshes")] public List Meshes; [JsonProperty("accessors")] public List Accessors; [JsonProperty("bufferViews")] public List BufferViews; [JsonProperty("buffers")] public List Buffers; [JsonProperty("materials")] public List Materials; [JsonProperty("textures")] public List Textures; [JsonProperty("images")] public List Images; [JsonProperty("extensionsRequired")] public string[] ExtensionsRequired; } internal sealed class GlbFile { private const uint MagicGltf = 1179937895u; private const uint ChunkJson = 1313821514u; private const uint ChunkBin = 5130562u; public GltfRoot Root { get; private set; } public byte[] Bin { get; private set; } public string SourcePath { get; private set; } public static GlbFile Load(string path) { byte[] array = File.ReadAllBytes(path); if (array.Length < 12) { throw new InvalidDataException(Path.GetFileName(path) + " is too small to be a .glb."); } if (BitConverter.ToUInt32(array, 0) != 1179937895) { throw new InvalidDataException(Path.GetFileName(path) + " is not a binary .glb (bad magic). Convert to GLB - .gltf, .fbx and .obj are not read by this loader."); } uint num = BitConverter.ToUInt32(array, 4); if (num != 2) { throw new InvalidDataException(Path.GetFileName(path) + " is glTF version " + num + "; only 2 is supported."); } long num2 = BitConverter.ToUInt32(array, 8); if (num2 > array.Length) { num2 = array.Length; } string text = null; byte[] array2 = null; int num3 = 12; while (num3 + 8 <= num2) { int num4 = BitConverter.ToInt32(array, num3); uint num5 = BitConverter.ToUInt32(array, num3 + 4); int num6 = num3 + 8; if (num4 < 0 || (long)num6 + (long)num4 > array.Length) { break; } switch (num5) { case 1313821514u: text = Encoding.UTF8.GetString(array, num6, num4); break; case 5130562u: array2 = new byte[num4]; Buffer.BlockCopy(array, num6, array2, 0, num4); break; } num3 = num6 + num4; } if (text == null) { throw new InvalidDataException(Path.GetFileName(path) + " has no JSON chunk."); } GltfRoot gltfRoot = JsonConvert.DeserializeObject(text); if (gltfRoot == null || gltfRoot.Meshes == null || gltfRoot.Meshes.Count == 0) { throw new InvalidDataException(Path.GetFileName(path) + " contains no meshes."); } return new GlbFile { Root = gltfRoot, Bin = (array2 ?? new byte[0]), SourcePath = path }; } public string CreditLine() { GltfAssetExtras gltfAssetExtras = ((Root == null || Root.Asset == null) ? null : Root.Asset.Extras); if (gltfAssetExtras == null) { return null; } StringBuilder stringBuilder = new StringBuilder(); if (!string.IsNullOrEmpty(gltfAssetExtras.Title)) { stringBuilder.Append(gltfAssetExtras.Title); } if (!string.IsNullOrEmpty(gltfAssetExtras.Author)) { stringBuilder.Append((stringBuilder.Length > 0) ? " by " : "").Append(gltfAssetExtras.Author); } if (!string.IsNullOrEmpty(gltfAssetExtras.License)) { stringBuilder.Append(" [").Append(gltfAssetExtras.License).Append("]"); } if (!string.IsNullOrEmpty(gltfAssetExtras.Source)) { stringBuilder.Append(" ").Append(gltfAssetExtras.Source); } if (stringBuilder.Length <= 0) { return null; } return stringBuilder.ToString(); } public byte[] ReadBufferView(int index) { GltfBufferView gltfBufferView = Root.BufferViews[index]; byte[] array = new byte[gltfBufferView.ByteLength]; Buffer.BlockCopy(Bin, gltfBufferView.ByteOffset, array, 0, gltfBufferView.ByteLength); return array; } } internal static class GlbMeshBuilder { private const int ModeTriangles = 4; private static bool WarnedAboutSkin; private static MethodInfo _loadImage; private static bool _loadImageResolved; public static Mesh Build(GlbFile glb, string meshName, out int[] groupIds) { int[] submeshMaterials; return Build(glb, meshName, out groupIds, out submeshMaterials); } public static Mesh Build(GlbFile glb, string meshName, out int[] groupIds, out int[] submeshMaterials) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown GltfRoot root = glb.Root; WarnedAboutSkin = false; List list = new List(); List list2 = new List(); int groupCounter = 0; List list3 = new List(); List list4 = new List(); Dictionary> dictionary = new Dictionary>(); foreach (int item in RootNodes(root)) { Walk(glb, item, Matrix4x4.identity, list, list3, list4, dictionary, list2, ref groupCounter); } if (list.Count == 0) { throw new InvalidDataException(Path.GetFileName(glb.SourcePath) + " produced no geometry."); } groupIds = list2.ToArray(); Mesh val = new Mesh { name = meshName }; val.indexFormat = (IndexFormat)(list.Count > 65000); val.SetVertices(list); if (list3.Count == list.Count) { val.SetNormals(list3); } if (list4.Count == list.Count) { val.SetUVs(0, list4); } List list5 = new List(dictionary.Keys); list5.Sort(); val.subMeshCount = list5.Count; for (int i = 0; i < list5.Count; i++) { val.SetTriangles(dictionary[list5[i]], i, false); } submeshMaterials = list5.ToArray(); if (list3.Count != list.Count) { val.RecalculateNormals(); } val.RecalculateBounds(); val.RecalculateTangents(); return val; } private static IEnumerable RootNodes(GltfRoot root) { int valueOrDefault = root.Scene.GetValueOrDefault(); if (root.Scenes != null && valueOrDefault >= 0 && valueOrDefault < root.Scenes.Count) { int[] nodes = root.Scenes[valueOrDefault].Nodes; if (nodes != null) { return nodes; } } List list = new List(); if (root.Nodes != null) { for (int i = 0; i < root.Nodes.Count; i++) { list.Add(i); } } return list; } private static void Walk(GlbFile glb, int nodeIndex, Matrix4x4 parent, List positions, List normals, List uvs, Dictionary> perMaterial, List groups, ref int groupCounter) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) GltfRoot root = glb.Root; if (root.Nodes == null || nodeIndex < 0 || nodeIndex >= root.Nodes.Count) { return; } GltfNode gltfNode = root.Nodes[nodeIndex]; Matrix4x4 val = parent * LocalMatrix(gltfNode); if (gltfNode.Mesh.HasValue) { Matrix4x4 world = (gltfNode.Skin.HasValue ? Matrix4x4.identity : val); if (gltfNode.Skin.HasValue && !WarnedAboutSkin) { WarnedAboutSkin = true; Plugin.Log.LogInfo((object)"Model is skinned; node transforms are ignored for its geometry, as glTF requires. Vertices are taken in bind-pose space."); } AppendMesh(glb, gltfNode.Mesh.Value, world, positions, normals, uvs, perMaterial, groups, ref groupCounter); } if (gltfNode.Children != null) { int[] children = gltfNode.Children; foreach (int nodeIndex2 in children) { Walk(glb, nodeIndex2, val, positions, normals, uvs, perMaterial, groups, ref groupCounter); } } } private static Matrix4x4 LocalMatrix(GltfNode node) { //IL_00f2: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) if (node.Matrix != null && node.Matrix.Length == 16) { Matrix4x4 result = default(Matrix4x4); ((Matrix4x4)(ref result)).SetColumn(0, new Vector4(node.Matrix[0], node.Matrix[1], node.Matrix[2], node.Matrix[3])); ((Matrix4x4)(ref result)).SetColumn(1, new Vector4(node.Matrix[4], node.Matrix[5], node.Matrix[6], node.Matrix[7])); ((Matrix4x4)(ref result)).SetColumn(2, new Vector4(node.Matrix[8], node.Matrix[9], node.Matrix[10], node.Matrix[11])); ((Matrix4x4)(ref result)).SetColumn(3, new Vector4(node.Matrix[12], node.Matrix[13], node.Matrix[14], node.Matrix[15])); return result; } ? val = ((node.Translation != null && node.Translation.Length == 3) ? new Vector3(node.Translation[0], node.Translation[1], node.Translation[2]) : Vector3.zero); Quaternion val2 = (Quaternion)((node.Rotation != null && node.Rotation.Length == 4) ? new Quaternion(node.Rotation[0], node.Rotation[1], node.Rotation[2], node.Rotation[3]) : Quaternion.identity); Vector3 val3 = (Vector3)((node.Scale != null && node.Scale.Length == 3) ? new Vector3(node.Scale[0], node.Scale[1], node.Scale[2]) : Vector3.one); return Matrix4x4.TRS((Vector3)val, val2, val3); } private static void AppendMesh(GlbFile glb, int meshIndex, Matrix4x4 world, List positions, List normals, List uvs, Dictionary> perMaterial, List groups, ref int groupCounter) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) GltfRoot root = glb.Root; if (meshIndex < 0 || meshIndex >= root.Meshes.Count) { return; } GltfMesh gltfMesh = root.Meshes[meshIndex]; if (gltfMesh.Primitives == null) { return; } Matrix4x4 inverse = ((Matrix4x4)(ref world)).inverse; Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose; foreach (GltfPrimitive primitive in gltfMesh.Primitives) { if ((primitive.Mode ?? 4) != 4 || primitive.Attributes == null || !primitive.Attributes.TryGetValue("POSITION", out var value)) { continue; } int count = positions.Count; Vector3[] array = ReadVector3(glb, value); int item = groupCounter++; for (int i = 0; i < array.Length; i++) { positions.Add(ToUnity(((Matrix4x4)(ref world)).MultiplyPoint3x4(array[i]))); groups.Add(item); } if (primitive.Attributes.TryGetValue("NORMAL", out var value2)) { Vector3[] array2 = ReadVector3(glb, value2); for (int j = 0; j < array2.Length; j++) { Vector3 val = ToUnity(((Matrix4x4)(ref transpose)).MultiplyVector(array2[j])); normals.Add(((Vector3)(ref val)).normalized); } } if (primitive.Attributes.TryGetValue("TEXCOORD_0", out var value3)) { Vector2[] array3 = ReadVector2(glb, value3); for (int k = 0; k < array3.Length; k++) { uvs.Add(new Vector2(array3[k].x, 1f - array3[k].y)); } } int[] array4 = (primitive.Indices.HasValue ? ReadIndices(glb, primitive.Indices.Value) : Sequence(array.Length)); int valueOrDefault = primitive.Material.GetValueOrDefault(); if (!perMaterial.TryGetValue(valueOrDefault, out var value4)) { value4 = (perMaterial[valueOrDefault] = new List()); } for (int l = 0; l + 2 < array4.Length; l += 3) { value4.Add(count + array4[l]); value4.Add(count + array4[l + 2]); value4.Add(count + array4[l + 1]); } } } private static Vector3 ToUnity(Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) return new Vector3(v.x, v.y, 0f - v.z); } private static int[] Sequence(int count) { int[] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = i; } return array; } private static int ComponentSize(int componentType) { switch (componentType) { case 5120: case 5121: return 1; case 5122: case 5123: return 2; case 5125: case 5126: return 4; default: throw new InvalidDataException("Unsupported glTF componentType " + componentType + "."); } } private static int ComponentCount(string type) { return type switch { "SCALAR" => 1, "VEC2" => 2, "VEC3" => 3, "VEC4" => 4, "MAT4" => 16, _ => throw new InvalidDataException("Unsupported glTF accessor type " + type + "."), }; } private static void Resolve(GlbFile glb, int accessorIndex, out GltfAccessor accessor, out int start, out int stride, out int elementSize) { accessor = glb.Root.Accessors[accessorIndex]; if (accessor.Sparse != null) { throw new InvalidDataException("Sparse glTF accessors are not supported."); } elementSize = ComponentSize(accessor.ComponentType) * ComponentCount(accessor.Type); if (!accessor.BufferView.HasValue) { throw new InvalidDataException("glTF accessor " + accessorIndex + " has no bufferView."); } GltfBufferView gltfBufferView = glb.Root.BufferViews[accessor.BufferView.Value]; start = gltfBufferView.ByteOffset + accessor.ByteOffset; stride = ((gltfBufferView.ByteStride.HasValue && gltfBufferView.ByteStride.Value > 0) ? gltfBufferView.ByteStride.Value : elementSize); } private static Vector3[] ReadVector3(GlbFile glb, int accessorIndex) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) Resolve(glb, accessorIndex, out var accessor, out var start, out var stride, out var _); if (accessor.ComponentType != 5126) { throw new InvalidDataException("Expected float VEC3 accessor, got componentType " + accessor.ComponentType + "."); } Vector3[] array = (Vector3[])(object)new Vector3[accessor.Count]; byte[] bin = glb.Bin; for (int i = 0; i < accessor.Count; i++) { int num = start + i * stride; array[i] = new Vector3(BitConverter.ToSingle(bin, num), BitConverter.ToSingle(bin, num + 4), BitConverter.ToSingle(bin, num + 8)); } return array; } private static Vector2[] ReadVector2(GlbFile glb, int accessorIndex) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) Resolve(glb, accessorIndex, out var accessor, out var start, out var stride, out var _); Vector2[] array = (Vector2[])(object)new Vector2[accessor.Count]; byte[] bin = glb.Bin; for (int i = 0; i < accessor.Count; i++) { int num = start + i * stride; switch (accessor.ComponentType) { case 5126: array[i] = new Vector2(BitConverter.ToSingle(bin, num), BitConverter.ToSingle(bin, num + 4)); break; case 5121: array[i] = new Vector2((float)(int)bin[num] / 255f, (float)(int)bin[num + 1] / 255f); break; case 5123: array[i] = new Vector2((float)(int)BitConverter.ToUInt16(bin, num) / 65535f, (float)(int)BitConverter.ToUInt16(bin, num + 2) / 65535f); break; default: throw new InvalidDataException("Unsupported UV componentType " + accessor.ComponentType + "."); } } return array; } private static int[] ReadIndices(GlbFile glb, int accessorIndex) { Resolve(glb, accessorIndex, out var accessor, out var start, out var stride, out var _); int[] array = new int[accessor.Count]; byte[] bin = glb.Bin; for (int i = 0; i < accessor.Count; i++) { int num = start + i * stride; switch (accessor.ComponentType) { case 5121: array[i] = bin[num]; break; case 5123: array[i] = BitConverter.ToUInt16(bin, num); break; case 5125: array[i] = (int)BitConverter.ToUInt32(bin, num); break; default: throw new InvalidDataException("Unsupported index componentType " + accessor.ComponentType + "."); } } return array; } public static Texture2D ReadTexture(GlbFile glb, int textureIndex, bool linear) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown GltfRoot root = glb.Root; if (root.Textures == null || textureIndex < 0 || textureIndex >= root.Textures.Count) { return null; } GltfTexture gltfTexture = root.Textures[textureIndex]; if (!gltfTexture.Source.HasValue || root.Images == null) { return null; } int value = gltfTexture.Source.Value; if (value < 0 || value >= root.Images.Count) { return null; } GltfImage gltfImage = root.Images[value]; if (!gltfImage.BufferView.HasValue) { return null; } byte[] data = glb.ReadBufferView(gltfImage.BufferView.Value); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear); if (!LoadImage(val, data)) { Object.Destroy((Object)(object)val); return null; } ((Object)val).name = gltfImage.Name ?? ("glb_tex_" + textureIndex); val.Apply(true, true); return val; } private static bool LoadImage(Texture2D texture, byte[] data) { if (!_loadImageResolved) { _loadImageResolved = true; Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule"); if (type != null) { _loadImage = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null); } if (_loadImage == null) { Plugin.Log.LogWarning((object)"ImageConversion.LoadImage not found; .glb textures cannot be decoded. Use \"material\": \"vanilla\", which does not need them."); } } if (_loadImage == null) { return false; } try { return (bool)_loadImage.Invoke(null, new object[3] { texture, data, false }); } catch (Exception ex) { Plugin.Log.LogWarning((object)("LoadImage failed: " + ex.Message)); return false; } } } internal static class MaterialFactory { public const string ModeVanilla = "vanilla"; public const string ModeModel = "model"; public const string ModeColors = "colors"; private static readonly string[] AlbedoProperties = new string[4] { "_BaseMap", "_MainTex", "_BaseColorMap", "_AlbedoMap" }; private static readonly string[] NormalProperties = new string[2] { "_BumpMap", "_NormalMap" }; private static readonly string[] ColorProperties = new string[4] { "_BaseColor", "_Color", "_Tint", "_TintColor" }; public static bool WantsModelTextures(string mode) { return string.Equals(mode, "model", StringComparison.OrdinalIgnoreCase); } public static bool WantsModelColors(string mode) { return string.Equals(mode, "colors", StringComparison.OrdinalIgnoreCase); } public static Material[] CreatePerSubmesh(Material vanillaMaterial, LoadedModel model, int slots) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)vanillaMaterial == (Object)null) { return null; } Color[] submeshColors = model.SubmeshColors; if (submeshColors == null || submeshColors.Length == 0) { Plugin.Log.LogWarning((object)"material mode 'colors' requested but the .glb declares no baseColorFactor; keeping the vanilla material."); return null; } DumpShaderProperties(vanillaMaterial.shader); string text = FirstProperty(vanillaMaterial, ColorProperties); Material val = vanillaMaterial; if (text == null) { Shader val2 = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("Game shader '" + ((Object)vanillaMaterial.shader).name + "' has no albedo colour slot and URP/Lit was not found; keeping the vanilla material.")); return null; } val = new Material(val2) { hideFlags = (HideFlags)52 }; text = "_BaseColor"; Plugin.Log.LogInfo((object)("Game shader '" + ((Object)vanillaMaterial.shader).name + "' has no albedo colour slot; colouring with fresh URP/Lit materials instead.")); } Dictionary dictionary = new Dictionary(); Material[] array = (Material[])(object)new Material[slots]; for (int i = 0; i < slots; i++) { Color val3 = ((i < submeshColors.Length) ? submeshColors[i] : Color.white); if (!dictionary.TryGetValue(val3, out var value)) { value = new Material(val) { name = "WA_" + ((Object)model.Mesh).name + "_c" + dictionary.Count, hideFlags = (HideFlags)52 }; value.SetColor(text, val3); dictionary[val3] = value; } array[i] = value; } if ((Object)(object)val != (Object)(object)vanillaMaterial) { Object.Destroy((Object)(object)val); } Plugin.Log.LogInfo((object)("Coloured " + slots + " submesh(es) with " + dictionary.Count + " distinct baseColorFactor value(s) via " + text + ".")); return array; } public static Material Create(string mode, Material vanillaMaterial, LoadedModel model) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown if (!WantsModelTextures(mode)) { return vanillaMaterial; } if ((Object)(object)model.Albedo == (Object)null) { Plugin.Log.LogWarning((object)"material mode 'model' requested but no albedo texture was decoded from the .glb; keeping the vanilla material."); return vanillaMaterial; } if ((Object)(object)vanillaMaterial != (Object)null) { Material val = new Material(vanillaMaterial) { name = "WA_" + ((Object)model.Mesh).name + "_textured", hideFlags = (HideFlags)52 }; string text = FirstProperty(val, AlbedoProperties); if (text != null) { val.SetTexture(text, (Texture)(object)model.Albedo); string text2 = (((Object)(object)model.Normal != (Object)null) ? FirstProperty(val, NormalProperties) : null); if (text2 != null) { val.SetTexture(text2, (Texture)(object)model.Normal); val.EnableKeyword("_NORMALMAP"); } Plugin.Log.LogInfo((object)("Textured using the game shader '" + ((Object)val.shader).name + "' via " + text + ((text2 != null) ? (" + " + text2) : ""))); return val; } Plugin.Log.LogWarning((object)("Game shader '" + ((Object)val.shader).name + "' exposes no albedo slot this mod knows; falling back to URP/Lit.")); Object.Destroy((Object)(object)val); } Shader val2 = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)"URP/Lit shader not found; keeping the vanilla material."); return vanillaMaterial; } Material val3 = new Material(val2) { name = "WA_" + ((Object)model.Mesh).name, hideFlags = (HideFlags)52 }; val3.SetTexture("_BaseMap", (Texture)(object)model.Albedo); if ((Object)(object)model.Normal != (Object)null) { val3.SetTexture("_BumpMap", (Texture)(object)model.Normal); val3.EnableKeyword("_NORMALMAP"); } Plugin.Log.LogInfo((object)"Textured using a fresh URP/Lit material."); return val3; } private static void DumpShaderProperties(Shader shader) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)shader == (Object)null)) { List list = new List(); int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { list.Add(shader.GetPropertyName(i) + ":" + ((object)shader.GetPropertyType(i)/*cast due to .constrained prefix*/).ToString()); } Plugin.Log.LogInfo((object)("Shader '" + ((Object)shader).name + "' properties: " + ((list.Count == 0) ? "(none)" : string.Join(", ", list.ToArray())))); } } private static string FirstProperty(Material material, string[] candidates) { foreach (string text in candidates) { if (material.HasProperty(text)) { return text; } } return null; } } internal static class MeshFitter { public static Mesh Bake(Mesh source, Bounds targetBounds, bool fitToBase, float scaleMultiplier, Vector3 positionOffset, Vector3 eulerOffset) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //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) float num = ((scaleMultiplier <= 0f) ? 1f : scaleMultiplier); Bounds bounds; if (fitToBase) { bounds = source.bounds; float num2 = Longest(((Bounds)(ref bounds)).size); float num3 = Longest(((Bounds)(ref targetBounds)).size); if (num2 > 1E-05f && num3 > 1E-05f) { num *= num3 / num2; } } Quaternion val = Quaternion.Euler(eulerOffset); bounds = source.bounds; Vector3 val2 = -((Bounds)(ref bounds)).center; Vector3 val3 = ((Bounds)(ref targetBounds)).center + positionOffset; Vector3[] vertices = source.vertices; Vector3[] normals = source.normals; Vector3[] array = (Vector3[])(object)new Vector3[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { array[i] = val * ((vertices[i] + val2) * num) + val3; } Mesh val4 = new Mesh { name = ((Object)source).name + "_fitted", indexFormat = source.indexFormat, hideFlags = (HideFlags)52 }; val4.vertices = array; if (normals != null && normals.Length == vertices.Length) { Vector3[] array2 = (Vector3[])(object)new Vector3[normals.Length]; for (int j = 0; j < normals.Length; j++) { array2[j] = val * normals[j]; } val4.normals = array2; } val4.uv = source.uv; val4.subMeshCount = source.subMeshCount; for (int k = 0; k < source.subMeshCount; k++) { val4.SetTriangles(source.GetTriangles(k), k, false); } if (val4.normals == null || val4.normals.Length != array.Length) { val4.RecalculateNormals(); } val4.RecalculateBounds(); val4.RecalculateTangents(); return val4; } private static float Longest(Vector3 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(size.x, Mathf.Max(size.y, size.z)); } } internal sealed class LoadedModel { public Mesh Mesh; public Texture2D Albedo; public Texture2D Normal; public string Credit; public string SourceFile; public int[] GroupIds; public Color[] SubmeshColors; public bool OwnsTextures = true; public float LongestAxis { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = Mesh.bounds; Vector3 size = ((Bounds)(ref bounds)).size; return Mathf.Max(size.x, Mathf.Max(size.y, size.z)); } } } internal static class ModelLibrary { private static readonly Dictionary Cache = new Dictionary(StringComparer.OrdinalIgnoreCase); public static LoadedModel LoadFromBundle(string weaponsFolder, string bundleFile, string assetName, bool wantTextures, bool axisFix) { string key = "bundle:" + bundleFile + ":" + assetName + (axisFix ? ":fix" : ""); if (Cache.TryGetValue(key, out var value)) { if (!wantTextures || (Object)(object)value.Albedo != (Object)null) { return value; } Cache.Remove(key); if ((Object)(object)value.Mesh != (Object)null) { Object.Destroy((Object)(object)value.Mesh); } } AssetBundle val = BundleSource.Resolve(weaponsFolder, bundleFile); if ((Object)(object)val == (Object)null) { throw new Exception("Asset bundle '" + bundleFile + "' could not be loaded from " + weaponsFolder + "."); } LoadedModel loadedModel = BundleSource.LoadModel(val, assetName, wantTextures, axisFix); loadedModel.OwnsTextures = false; Plugin.Log.LogInfo((object)("Loaded model " + assetName + " from " + bundleFile + " - " + loadedModel.Mesh.vertexCount + " verts, " + loadedModel.Mesh.triangles.Length / 3 + " tris, parts " + loadedModel.Mesh.subMeshCount + ", longest axis " + loadedModel.LongestAxis.ToString("F3", CultureInfo.InvariantCulture))); Cache[key] = loadedModel; return loadedModel; } public static LoadedModel Load(string path, bool wantTextures) { if (Cache.TryGetValue(path, out var value)) { if (!wantTextures || (Object)(object)value.Albedo != (Object)null) { return value; } Cache.Remove(path); if ((Object)(object)value.Mesh != (Object)null) { Object.Destroy((Object)(object)value.Mesh); } } GlbFile glbFile = GlbFile.Load(path); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); int[] groupIds; int[] submeshMaterials; LoadedModel loadedModel = new LoadedModel { Mesh = GlbMeshBuilder.Build(glbFile, "WA_" + fileNameWithoutExtension, out groupIds, out submeshMaterials), Credit = glbFile.CreditLine(), SourceFile = path }; loadedModel.GroupIds = groupIds; loadedModel.SubmeshColors = ReadSubmeshColors(glbFile, submeshMaterials); ((Object)loadedModel.Mesh).hideFlags = (HideFlags)52; if (wantTextures && glbFile.Root.Materials != null && glbFile.Root.Materials.Count > 0) { GltfMaterial gltfMaterial = glbFile.Root.Materials[0]; int? albedoTextureIndex = gltfMaterial.AlbedoTextureIndex; if (albedoTextureIndex.HasValue) { loadedModel.Albedo = GlbMeshBuilder.ReadTexture(glbFile, albedoTextureIndex.Value, linear: false); if ((Object)(object)loadedModel.Albedo != (Object)null) { ((Object)loadedModel.Albedo).hideFlags = (HideFlags)52; } } if (gltfMaterial.NormalTexture != null) { loadedModel.Normal = GlbMeshBuilder.ReadTexture(glbFile, gltfMaterial.NormalTexture.Index, linear: true); if ((Object)(object)loadedModel.Normal != (Object)null) { ((Object)loadedModel.Normal).hideFlags = (HideFlags)52; } } } Plugin.Log.LogInfo((object)("Loaded model " + Path.GetFileName(path) + " - " + loadedModel.Mesh.vertexCount + " verts, " + loadedModel.Mesh.triangles.Length / 3 + " tris, parts " + CountGroups(groupIds) + ", longest axis " + loadedModel.LongestAxis.ToString("F3", CultureInfo.InvariantCulture) + ((loadedModel.Credit != null) ? (" | " + loadedModel.Credit) : ""))); Cache[path] = loadedModel; return loadedModel; } private static Color[] ReadSubmeshColors(GlbFile glb, int[] submeshMaterials) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (submeshMaterials == null || submeshMaterials.Length == 0) { return null; } List materials = glb.Root.Materials; if (materials == null || materials.Count == 0) { return null; } Color[] array = (Color[])(object)new Color[submeshMaterials.Length]; bool flag = false; for (int i = 0; i < submeshMaterials.Length; i++) { array[i] = Color.white; int num = submeshMaterials[i]; if (num >= 0 && num < materials.Count) { float[] array2 = materials[num].Pbr?.BaseColorFactor; if (array2 != null && array2.Length >= 3) { array[i] = new Color(array2[0], array2[1], array2[2], (array2.Length > 3) ? array2[3] : 1f); flag = true; } } } if (!flag) { return null; } return array; } private static int CountGroups(int[] groupIds) { if (groupIds == null || groupIds.Length == 0) { return 0; } int num = 0; foreach (int num2 in groupIds) { if (num2 > num) { num = num2; } } return num + 1; } public static void Clear() { foreach (LoadedModel value in Cache.Values) { if ((Object)(object)value.Mesh != (Object)null) { Object.Destroy((Object)(object)value.Mesh); } if (value.OwnsTextures) { if ((Object)(object)value.Albedo != (Object)null) { Object.Destroy((Object)(object)value.Albedo); } if ((Object)(object)value.Normal != (Object)null) { Object.Destroy((Object)(object)value.Normal); } } } Cache.Clear(); } } internal static class SkinTransfer { private sealed class Grid { private readonly Dictionary> _cells = new Dictionary>(); private readonly float _cell; private readonly Vector3 _origin; public Grid(Vector3[] points) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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) Bounds val = default(Bounds); ((Bounds)(ref val))..ctor(points[0], Vector3.zero); for (int i = 1; i < points.Length; i++) { ((Bounds)(ref val)).Encapsulate(points[i]); } _origin = ((Bounds)(ref val)).min; float num = Mathf.Max(((Bounds)(ref val)).size.x, Mathf.Max(((Bounds)(ref val)).size.y, ((Bounds)(ref val)).size.z)); _cell = Mathf.Max(num / 24f, 0.0001f); for (int j = 0; j < points.Length; j++) { long key = Key(points[j]); if (!_cells.TryGetValue(key, out var value)) { value = new List(); _cells[key] = value; } value.Add(j); } } public int Nearest(Vector3 point, Vector3[] points) { //IL_0009: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) int bestIndex = -1; float bestSqr = float.MaxValue; int cx = Cell(point.x - _origin.x); int cy = Cell(point.y - _origin.y); int cz = Cell(point.z - _origin.z); for (int i = 0; i < 32; i++) { Scan(cx, cy, cz, i, point, points, ref bestIndex, ref bestSqr); if (bestIndex >= 0) { float num = (float)i * _cell; if (bestSqr <= num * num) { break; } } } if (bestIndex < 0) { for (int j = 0; j < points.Length; j++) { Vector3 val = points[j] - point; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < bestSqr) { bestSqr = sqrMagnitude; bestIndex = j; } } } return bestIndex; } private void Scan(int cx, int cy, int cz, int radius, Vector3 point, Vector3[] points, ref int bestIndex, ref float bestSqr) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) for (int i = cx - radius; i <= cx + radius; i++) { for (int j = cy - radius; j <= cy + radius; j++) { for (int k = cz - radius; k <= cz + radius; k++) { if ((radius != 0 && i != cx - radius && i != cx + radius && j != cy - radius && j != cy + radius && k != cz - radius && k != cz + radius) || !_cells.TryGetValue(Key(i, j, k), out var value)) { continue; } foreach (int item in value) { Vector3 val = points[item] - point; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < bestSqr) { bestSqr = sqrMagnitude; bestIndex = item; } } } } } } private int Cell(float value) { return Mathf.FloorToInt(value / _cell); } private long Key(Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) return Key(Cell(point.x - _origin.x), Cell(point.y - _origin.y), Cell(point.z - _origin.z)); } private static long Key(int x, int y, int z) { return ((long)(x & 0x1FFFFF) << 42) | ((long)(y & 0x1FFFFF) << 21) | (z & 0x1FFFFF); } } public const string ModeRigid = "rigid"; public const string ModeTransfer = "transfer"; public const string ModeBones = "bones"; public const string ModeParts = "parts"; public static string Explain(Mesh original) { if ((Object)(object)original == (Object)null) { return "no original mesh"; } BoneWeight[] boneWeights = original.boneWeights; Matrix4x4[] bindposes = original.bindposes; Vector3[] vertices = original.vertices; return "isReadable=" + original.isReadable + " verts=" + ((vertices == null) ? (-1) : vertices.Length) + " weights=" + ((boneWeights == null) ? (-1) : boneWeights.Length) + " bindposes=" + ((bindposes == null) ? (-1) : bindposes.Length); } public static bool ApplyTransfer(Mesh baked, Mesh original) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) BoneWeight[] boneWeights = original.boneWeights; Matrix4x4[] bindposes = original.bindposes; if (boneWeights == null || boneWeights.Length == 0 || bindposes == null || bindposes.Length == 0) { return false; } Vector3[] vertices = original.vertices; if (vertices.Length != boneWeights.Length) { return false; } Vector3[] vertices2 = baked.vertices; BoneWeight[] array = (BoneWeight[])(object)new BoneWeight[vertices2.Length]; Grid grid = new Grid(vertices); for (int i = 0; i < vertices2.Length; i++) { array[i] = boneWeights[grid.Nearest(vertices2[i], vertices)]; } baked.boneWeights = array; baked.bindposes = bindposes; return true; } public static bool ApplyPartBinding(Mesh baked, int[] groupIds, Mesh original, SkinnedMeshRenderer skinned, string rootBoneName, Dictionary overrides) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_0130: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0214: 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) Matrix4x4[] bindposes = original.bindposes; Transform[] array = (((Object)(object)skinned == (Object)null) ? null : skinned.bones); if (bindposes == null || bindposes.Length == 0 || array == null || array.Length == 0) { return false; } if (groupIds == null || groupIds.Length != baked.vertexCount) { return false; } if (!CandidateBones(array, bindposes, rootBoneName, out var candidates, out var origins)) { return false; } Vector3[] vertices = baked.vertices; int num = 0; foreach (int num2 in groupIds) { if (num2 + 1 > num) { num = num2 + 1; } } Vector3[] array2 = (Vector3[])(object)new Vector3[num]; int[] array3 = new int[num]; for (int j = 0; j < vertices.Length; j++) { ref Vector3 reference = ref array2[groupIds[j]]; reference += vertices[j]; array3[groupIds[j]]++; } int[] array4 = new int[num]; for (int k = 0; k < num; k++) { if (array3[k] == 0) { array4[k] = candidates[0]; continue; } Vector3 val = array2[k] / (float)array3[k]; int index = 0; float num3 = float.MaxValue; for (int l = 0; l < candidates.Count; l++) { Vector3 val2 = origins[l] - val; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num3) { num3 = sqrMagnitude; index = l; } } array4[k] = candidates[index]; if (overrides != null && overrides.TryGetValue(k.ToString(), out var value)) { int num4 = IndexOfBone(array, candidates, value); if (num4 >= 0) { array4[k] = num4; } else { Plugin.Log.LogWarning((object)("partBones: no bone '" + value + "' under '" + rootBoneName + "'.")); } } Plugin.Log.LogInfo((object)(" part " + k + ": " + array3[k] + " verts, centroid " + Fmt(val) + " -> bone '" + ((Object)array[array4[k]]).name + "'")); } BoneWeight[] array5 = (BoneWeight[])(object)new BoneWeight[vertices.Length]; for (int m = 0; m < vertices.Length; m++) { ((BoneWeight)(ref array5[m])).boneIndex0 = array4[groupIds[m]]; ((BoneWeight)(ref array5[m])).weight0 = 1f; } baked.boneWeights = array5; baked.bindposes = bindposes; for (int n = 0; n < candidates.Count; n++) { Plugin.Log.LogInfo((object)(" bone '" + ((Object)array[candidates[n]]).name + "' origin " + Fmt(origins[n]))); } HashSet hashSet = new HashSet(array4); Plugin.Log.LogInfo((object)("Part binding: " + num + " model part(s) bound rigidly across " + hashSet.Count + " bone(s) under '" + rootBoneName + "'.")); return true; } private static bool CandidateBones(Transform[] bones, Matrix4x4[] bindposes, string rootBoneName, out List candidates, out List origins) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) candidates = new List(); origins = new List(); Transform val = FindBone(bones, rootBoneName); if ((Object)(object)val == (Object)null) { return false; } for (int i = 0; i < bones.Length && i < bindposes.Length; i++) { if (!((Object)(object)bones[i] == (Object)null) && (!((Object)(object)bones[i] != (Object)(object)val) || bones[i].IsChildOf(val)) && !IsHandBone(bones[i], val)) { candidates.Add(i); List obj = origins; Matrix4x4 inverse = ((Matrix4x4)(ref bindposes[i])).inverse; obj.Add(((Matrix4x4)(ref inverse)).MultiplyPoint3x4(Vector3.zero)); } } return candidates.Count > 0; } public static bool ApplyBoneProximity(Mesh baked, Mesh original, SkinnedMeshRenderer skinned, string rootBoneName) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) Matrix4x4[] bindposes = original.bindposes; Transform[] array = (((Object)(object)skinned == (Object)null) ? null : skinned.bones); if (bindposes == null || bindposes.Length == 0 || array == null || array.Length == 0) { return false; } if (!CandidateBones(array, bindposes, rootBoneName, out var candidates, out var origins)) { return false; } Vector3[] vertices = baked.vertices; BoneWeight[] array2 = (BoneWeight[])(object)new BoneWeight[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { int index = -1; float num = float.MaxValue; float num2 = float.MaxValue; for (int j = 0; j < candidates.Count; j++) { Vector3 val = origins[j] - vertices[i]; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num2 = num; num = sqrMagnitude; index = j; } else if (sqrMagnitude < num2) { num2 = sqrMagnitude; } } int num3 = i; BoneWeight val2 = default(BoneWeight); ((BoneWeight)(ref val2)).boneIndex0 = candidates[index]; ((BoneWeight)(ref val2)).weight0 = 1f; array2[num3] = val2; } baked.boneWeights = array2; baked.bindposes = bindposes; Plugin.Log.LogInfo((object)("Bone-proximity skinning used " + candidates.Count + " bone(s) under '" + rootBoneName + "'.")); return true; } private static bool IsHandBone(Transform bone, Transform root) { Transform val = bone; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root.parent) { if (((Object)val).name.IndexOf("_IK", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } private static int IndexOfBone(Transform[] bones, List candidates, string name) { foreach (int candidate in candidates) { if ((Object)(object)bones[candidate] != (Object)null && string.Equals(((Object)bones[candidate]).name, name, StringComparison.OrdinalIgnoreCase)) { return candidate; } } return -1; } private static string BoneNames(Transform[] bones, List candidates) { List list = new List(); foreach (int candidate in candidates) { if ((Object)(object)bones[candidate] != (Object)null) { list.Add(((Object)bones[candidate]).name); } } return string.Join(", ", list.ToArray()); } private static string Fmt(Vector3 v) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; return "(" + v.x.ToString("F2", invariantCulture) + ", " + v.y.ToString("F2", invariantCulture) + ", " + v.z.ToString("F2", invariantCulture) + ")"; } private static Transform FindBone(Transform[] bones, string name) { foreach (Transform val in bones) { if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, name, StringComparison.OrdinalIgnoreCase)) { return val; } } return null; } } internal static class SoundLibrary { private static readonly Dictionary Owned = new Dictionary(); private static readonly HashSet Borrowed = new HashSet(); public const string FirstIndexSuffix = "1"; public static bool IsLoaded(string key) { return Owned.ContainsKey(key); } public static bool RegisterFromBundle(string weaponsFolder, string bundleFile, string assetName, string key) { if (Owned.ContainsKey(key)) { return true; } AssetBundle val = BundleSource.Resolve(weaponsFolder, bundleFile); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("Asset bundle '" + bundleFile + "' could not be loaded for sound '" + key + "'.")); return false; } AudioClip val2 = BundleSource.LoadClip(val, assetName); if ((Object)(object)val2 == (Object)null) { return false; } Owned[key] = val2; Borrowed.Add(key); Register(key, val2); Plugin.Log.LogInfo((object)("Registered sound '" + key + "' from " + bundleFile + ":" + assetName + " (" + val2.length.ToString("F2", CultureInfo.InvariantCulture) + "s)")); return true; } public static IEnumerator LoadAndRegister(string path, string key) { if (Owned.ContainsKey(key)) { yield break; } if (!File.Exists(path)) { Plugin.Log.LogWarning((object)("Sound file not found: " + path)); yield break; } AudioType val = TypeFromExtension(path); string text = "file:///" + path.Replace('\\', '/').Replace(" ", "%20"); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(text, val); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Plugin.Log.LogWarning((object)("Could not load " + Path.GetFileName(path) + ": " + request.error)); yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { Plugin.Log.LogWarning((object)("Decoded no audio from " + Path.GetFileName(path) + ".")); yield break; } ((Object)content).name = key; ((Object)content).hideFlags = (HideFlags)52; Owned[key] = content; Register(key, content); Plugin.Log.LogInfo((object)("Registered sound '" + key + "' from " + Path.GetFileName(path) + " (" + content.length.ToString("F2", CultureInfo.InvariantCulture) + "s)")); } finally { ((IDisposable)request)?.Dispose(); } } public static void ReapplyAll() { if (Owned.Count == 0) { return; } int num = 0; foreach (KeyValuePair item in Owned) { if (Register(item.Key, item.Value)) { num++; } } if (num > 0) { Plugin.Log.LogInfo((object)("Re-registered " + num + " mod sound(s) after AudioManager reset.")); } } private static bool Register(string key, AudioClip clip) { Dictionary dictionary = ClipDictionary(); if (dictionary == null) { return false; } dictionary[key] = clip; return true; } private static Dictionary ClipDictionary() { FieldInfo fieldInfo = AccessTools.Field(typeof(AudioManager), "_realClips"); if (fieldInfo == null) { Plugin.Log.LogWarning((object)"AudioManager._realClips not found; custom sounds are unavailable."); return null; } return fieldInfo.GetValue(null) as Dictionary; } private static AudioType TypeFromExtension(string path) { string text = (Path.GetExtension(path) ?? "").ToLowerInvariant(); switch (text) { case ".mp3": return (AudioType)13; case ".ogg": return (AudioType)14; case ".wav": return (AudioType)20; case ".aiff": case ".aif": return (AudioType)2; default: Plugin.Log.LogWarning((object)("Unknown audio extension '" + text + "', trying to decode as WAV.")); return (AudioType)20; } } public static void Clear() { foreach (KeyValuePair item in Owned) { if ((Object)(object)item.Value != (Object)null && !Borrowed.Contains(item.Key)) { Object.Destroy((Object)(object)item.Value); } } Owned.Clear(); Borrowed.Clear(); } } } namespace HowToFish.WeaponArsenal.Arsenal { internal static class AnimationLibrary { public static void Install(BuiltWeapon built, string weaponsFolder) { Dictionary animations = built.Def.Animations; if (animations == null || animations.Count == 0) { return; } object obj = Refl.Get(built.Weapon, "_anim"); Animation val = (Animation)((obj is Animation) ? obj : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("'" + built.Def.Id + "' has no Animation component; custom clips skipped.")); return; } if (string.IsNullOrEmpty(built.Def.Bundle)) { Plugin.Log.LogWarning((object)("'" + built.Def.Id + "' declares animations but no 'bundle' to load them from.")); return; } AssetBundle val2 = BundleSource.Resolve(weaponsFolder, built.Def.Bundle); if ((Object)(object)val2 == (Object)null) { return; } foreach (KeyValuePair item in animations) { string key = item.Key; string value = item.Value; AnimationClip val3 = val2.LoadAsset(value); if ((Object)(object)val3 == (Object)null) { Plugin.Log.LogError((object)("AnimationClip '" + value + "' not found in " + built.Def.Bundle + ". Available: " + string.Join(", ", val2.GetAllAssetNames()))); continue; } if (!val3.legacy) { val3.legacy = true; } val.RemoveClip(key); val.AddClip(val3, key); Plugin.Log.LogInfo((object)("Animation '" + key + "' on '" + built.Def.Id + "' replaced with '" + value + "' (" + val3.length.ToString("F3") + "s).")); } } public static string DumpPaths(BuiltWeapon built) { //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown if (built == null || (Object)(object)built.Weapon == (Object)null) { return "weapon not built"; } object obj = Refl.Get(built.Weapon, "_anim"); Animation val = (Animation)((obj is Animation) ? obj : null); Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : built.Prefab.transform); List list = new List(); StringBuilder stringBuilder = new StringBuilder(); Transform[] componentsInChildren = ((Component)val2).GetComponentsInChildren(true); foreach (Transform val3 in componentsInChildren) { if (!((Object)(object)val3 == (Object)(object)val2)) { string text = Path(val2, val3); stringBuilder.Append(" ").Append(text).AppendLine(); if (((Object)val3).name.EndsWith("_IK") || ((Object)val3).name == "Gun" || ((Object)val3).name == "Mag" || ((Object)val3).name == "Slide") { list.Add(text); } } } Plugin.Log.LogInfo((object)("=== animation paths for '" + built.Def.Id + "' (relative to '" + ((Object)val2).name + "') ===")); Plugin.Log.LogInfo((object)"--- the ones a weapon clip usually drives ---"); foreach (string item in list) { Plugin.Log.LogInfo((object)(" " + item)); } Plugin.Log.LogInfo((object)"--- every transform ---"); Plugin.Log.LogInfo((object)stringBuilder.ToString().TrimEnd(Array.Empty())); if ((Object)(object)val != (Object)null) { Plugin.Log.LogInfo((object)"--- clips currently installed ---"); foreach (AnimationState item2 in val) { AnimationState val4 = item2; Plugin.Log.LogInfo((object)(" '" + val4.name + "' " + val4.length.ToString("F3") + "s")); } } Plugin.Log.LogInfo((object)"=== end animation paths ==="); return list.Count + " key path(s) and the full list are in the log"; } private static string Path(Transform root, Transform node) { List list = new List(); while ((Object)(object)node != (Object)null && (Object)(object)node != (Object)(object)root) { list.Add(((Object)node).name); node = node.parent; } list.Reverse(); return string.Join("/", list.ToArray()); } } internal sealed class ArsenalRuntime : MonoBehaviour { private const float PollInterval = 0.5f; private readonly List _built = new List(); private float _nextPoll; private bool _done; public IReadOnlyList Built => _built; public bool Done => _done; public BuiltWeapon Find(string weaponId) { foreach (BuiltWeapon item in _built) { if (string.Equals(item.Def.Id, weaponId, StringComparison.OrdinalIgnoreCase)) { return item; } } return null; } private void Update() { if (!_done && Plugin.Cfg != null && Plugin.Cfg.Enabled.Value && !(Time.unscaledTime < _nextPoll)) { _nextPoll = Time.unscaledTime + 0.5f; if (!((Object)(object)InstanceFinder.NetworkManager == (Object)null) && BaseWeaponIndex.Build()) { BuildAll(); _done = true; } } } private void BuildAll() { _built.Clear(); InventorySlotSetItemPatch.ClearCache(); WeaponRegistry registry = Plugin.Registry; List> list = new List>(); foreach (WeaponDef def in registry.Defs) { BuiltWeapon builtWeapon = WeaponBuilder.Build(def, registry.WeaponsFolder); if (builtWeapon != null) { _built.Add(builtWeapon); list.Add(new KeyValuePair(def.Id, builtWeapon.NetworkObject)); } } if (_built.Count == 0) { Plugin.Log.LogWarning((object)"No weapons were built. Nothing to register."); return; } ModPrefabRegistry.RegisterAll(list, Plugin.Cfg.PrefabCollectionId.Value); ItemIdRegistry.RegisterAll(_built); ShopPlacer.Install(); PropPlacer.Install(); LoadSounds(); foreach (BuiltWeapon item in _built) { if (!string.IsNullOrEmpty(item.Def.ResolvedCredit)) { Plugin.Log.LogInfo((object)("Model credit - " + item.Def.Id + ": " + item.Def.ResolvedCredit)); } } } private void LoadSounds() { foreach (BuiltWeapon item in _built) { SoundDef sound = item.Def.Sound; if (sound == null || (string.IsNullOrEmpty(sound.Fire) && string.IsNullOrEmpty(sound.FireAsset))) { continue; } string key = WeaponBuilder.FireSoundName(item.Def.Id) + "1"; if (!SoundLibrary.IsLoaded(key)) { if (!string.IsNullOrEmpty(sound.FireAsset)) { SoundLibrary.RegisterFromBundle(Plugin.Registry.WeaponsFolder, item.Def.Bundle, sound.FireAsset, key); continue; } string path = Path.Combine(Plugin.Registry.WeaponsFolder, sound.Fire); ((MonoBehaviour)this).StartCoroutine(SoundLibrary.LoadAndRegister(path, key)); } } } public void Rebuild() { foreach (BuiltWeapon item in _built) { if ((Object)(object)item.Prefab != (Object)null) { Object.Destroy((Object)(object)item.Prefab); } } _built.Clear(); ModelLibrary.Clear(); ModPrefabRegistry.Reset(); ItemIdRegistry.Reset(); Plugin.Registry.Load(Plugin.WeaponsFolder); _done = false; _nextPoll = 0f; } private void OnDestroy() { WeaponBuilder.DestroyTemplates(); ModelLibrary.Clear(); } } internal sealed class ArsenalWeapon : MonoBehaviour { public string WeaponId; [NonSerialized] public bool RuntimeStatsApplied; public WeaponDef Def { get { if (Plugin.Registry != null) { return Plugin.Registry.Get(WeaponId); } return null; } } } internal static class AutoSolver { private const string GunBone = "Gun"; public static string Solve(BuiltWeapon built, bool alignModel, bool snapHands) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) if (built == null || built.Targets.Count == 0) { return "no model target to solve against."; } ModelSwapTarget modelSwapTarget = built.Targets[0]; if ((Object)(object)modelSwapTarget.Skinned == (Object)null) { return "auto solving needs a skinned target."; } List list = new List(); if (alignModel) { Vector3 val = HeightDelta(built, modelSwapTarget); Vector3 val2 = ToVector(built.Def.Model.Position); Vector3 val3 = val2 + val; built.Def.Model.Position = new float[3] { val3.x, val3.y, val3.z }; WeaponBuilder.Refit(built); list.Add("position " + Fmt(val2) + " -> " + Fmt(val3)); } if (snapHands) { if (GripOnPart(built, modelSwapTarget, built.Def.Model.LeftHandPart, out var gunLocal, out var longAxis)) { if (built.Def.Ik == null) { built.Def.Ik = new IkDef(); } Transform val4 = WeaponBuilder.FindIkTarget(built, left: true); Vector3 v = (((Object)(object)val4 == (Object)null) ? Vector3.zero : val4.localPosition); built.Def.Ik.Left = new float[3] { gunLocal.x, gunLocal.y, gunLocal.z }; if ((Object)(object)val4 != (Object)null) { Vector3 val5 = WeaponBuilder.MuzzleForward(built); Vector3 val7; if (!((Object)(object)val4.parent == (Object)null) && !(val5 == Vector3.zero)) { Vector3 val6 = val4.parent.InverseTransformDirection(val5); val7 = ((Vector3)(ref val6)).normalized; } else { val7 = Vector3.zero; } Vector3 val8 = val7; if (val8 != Vector3.zero) { if (Vector3.Dot(longAxis, val8) < 0f) { longAxis = -longAxis; } Quaternion val9 = Quaternion.FromToRotation(val8, longAxis) * val4.localRotation; Vector3 eulerAngles = ((Quaternion)(ref val9)).eulerAngles; built.Def.Ik.LeftRotation = new float[3] { eulerAngles.x, eulerAngles.y, eulerAngles.z }; val9 = val4.localRotation; list.Add("l_IK rot " + Fmt(((Quaternion)(ref val9)).eulerAngles) + " -> " + Fmt(eulerAngles)); Plugin.Log.LogInfo((object)(" auto: barrel axis " + Fmt(val8) + ", magazine axis " + Fmt(longAxis))); } } WeaponBuilder.ApplyIk(built); WeaponBuilder.SyncIkOnLiveInstances(built); list.Add("l_IK " + Fmt(v) + " -> " + Fmt(gunLocal) + " (on the magazine)"); } else { list.Add("could not locate the magazine geometry; left hand untouched."); } } WeaponBuilder.SyncLiveInstances(built); foreach (string item in list) { Plugin.Log.LogInfo((object)(" auto: " + item)); } if (list.Count != 0) { return string.Join(" | ", list.ToArray()); } return "nothing to change."; } private static Vector3 HeightDelta(BuiltWeapon built, ModelSwapTarget target) { //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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_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: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Quaternion.Euler(ToVector(built.Def.Model.Rotation)) * Vector3.up; Vector3 normalized = ((Vector3)(ref val)).normalized; float num = Extent(target.BaseBounds, normalized); float num2 = Extent(target.FittedMesh.bounds, normalized); Plugin.Log.LogInfo((object)(" auto: up in mesh space " + Fmt(normalized) + ", base top " + num.ToString("F3") + ", model top " + num2.ToString("F3"))); return normalized * (num - num2); } private static float Extent(Bounds bounds, Vector3 axis) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) Vector3 extents = ((Bounds)(ref bounds)).extents; float num = Mathf.Abs(extents.x * axis.x) + Mathf.Abs(extents.y * axis.y) + Mathf.Abs(extents.z * axis.z); return Vector3.Dot(((Bounds)(ref bounds)).center, axis) + num; } private static bool GripOnPart(BuiltWeapon built, ModelSwapTarget target, int requestedPart, out Vector3 gunLocal, out Vector3 longAxis) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_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_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) gunLocal = Vector3.zero; longAxis = Vector3.zero; Mesh fittedMesh = target.FittedMesh; int[] array = ((built.Model == null) ? null : built.Model.GroupIds); Transform[] bones = target.Skinned.bones; Matrix4x4[] array2 = (((Object)(object)fittedMesh == (Object)null) ? null : fittedMesh.bindposes); if ((Object)(object)fittedMesh == (Object)null || array == null || bones == null || array2 == null) { return false; } Vector3[] vertices = fittedMesh.vertices; if (array.Length != vertices.Length) { return false; } int num = ((requestedPart >= 0) ? requestedPart : LargestPartOnBone(built, array, "Mag")); if (num < 0) { return false; } string text = BoneForPart(built, num); int num2 = IndexOfBone(bones, array2, text); if (num2 < 0) { return false; } Transform val = FindBone(bones, "Gun"); if ((Object)(object)val == (Object)null) { return false; } Matrix4x4 val2 = bones[num2].localToWorldMatrix * array2[num2]; List list = new List(); for (int i = 0; i < vertices.Length; i++) { if (array[i] == num) { list.Add(val.InverseTransformPoint(((Matrix4x4)(ref val2)).MultiplyPoint3x4(vertices[i]))); } } if (list.Count == 0) { return false; } Vector3 val3 = Vector3.zero; foreach (Vector3 item in list) { val3 += item; } gunLocal = val3 / (float)list.Count; longAxis = DominantDirection(list, gunLocal); float num3 = 0f; foreach (Vector3 item2 in list) { float num4 = Vector3.Dot(item2 - gunLocal, longAxis); if (Mathf.Abs(num4) > num3) { num3 = Mathf.Abs(num4); } } float num5 = ((Vector3.Dot(val.InverseTransformPoint(val.position) - gunLocal, longAxis) >= 0f) ? 1f : (-1f)); gunLocal += longAxis * (num5 * num3 * built.Def.Model.GripAlongPart); Plugin.Log.LogInfo((object)(" auto: gripping part " + num + " (" + list.Count + " verts, bone '" + text + "') at " + Fmt(gunLocal) + " in Gun space.")); return true; } private static Vector3 DominantDirection(List points, Vector3 centre) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.up; for (int i = 0; i < 24; i++) { Vector3 val2 = Vector3.zero; foreach (Vector3 point in points) { Vector3 val3 = point - centre; val2 += val3 * Vector3.Dot(val3, val); } if (((Vector3)(ref val2)).sqrMagnitude < 1E-12f) { return val; } ((Vector3)(ref val2)).Normalize(); if (Vector3.Dot(val2, val) > 0.999999f) { return val2; } val = val2; } return val; } private static int LargestPartOnBone(BuiltWeapon built, int[] groups, string boneName) { Dictionary dictionary = new Dictionary(); foreach (int num in groups) { if (string.Equals(BoneForPart(built, num), boneName, StringComparison.OrdinalIgnoreCase)) { dictionary.TryGetValue(num, out var value); dictionary[num] = value + 1; } } int result = -1; int num2 = 0; foreach (KeyValuePair item in dictionary) { if (item.Value > num2) { result = item.Key; num2 = item.Value; } } return result; } private static string BoneForPart(BuiltWeapon built, int part) { Dictionary partBones = built.Def.Model.PartBones; if (partBones == null || !partBones.TryGetValue(part.ToString(), out var value)) { return null; } return value; } private static int IndexOfBone(Transform[] bones, Matrix4x4[] bindposes, string name) { if (name == null) { return -1; } for (int i = 0; i < bones.Length && i < bindposes.Length; i++) { if ((Object)(object)bones[i] != (Object)null && ((Object)bones[i]).name == name) { return i; } } return -1; } private static Transform FindBone(Transform[] bones, string name) { foreach (Transform val in bones) { if ((Object)(object)val != (Object)null && ((Object)val).name == name) { return val; } } return null; } private static Vector3 ToVector(float[] v) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (v == null || v.Length < 3) { return Vector3.zero; } return new Vector3(v[0], v[1], v[2]); } private static string Fmt(Vector3 v) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; return "(" + v.x.ToString("F2", invariantCulture) + ", " + v.y.ToString("F2", invariantCulture) + ", " + v.z.ToString("F2", invariantCulture) + ")"; } } internal static class BaseWeaponIndex { private static readonly Dictionary ByName = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly List Names = new List(); public static bool Ready { get; private set; } public static IReadOnlyList WeaponNames => Names; public static NetworkObject Find(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } if (!ByName.TryGetValue(prefabName, out var value)) { return null; } return value; } public static bool Build() { ByName.Clear(); Names.Clear(); Ready = false; NetworkManager networkManager = InstanceFinder.NetworkManager; if ((Object)(object)networkManager == (Object)null) { Plugin.Log.LogWarning((object)"No NetworkManager yet; base weapon index deferred."); return false; } PrefabObjects spawnablePrefabs = networkManager.SpawnablePrefabs; if ((Object)(object)spawnablePrefabs == (Object)null) { Plugin.Log.LogWarning((object)"NetworkManager has no SpawnablePrefabs collection."); return false; } int objectCount = spawnablePrefabs.GetObjectCount(); for (int i = 0; i < objectCount; i++) { NetworkObject val = null; try { val = spawnablePrefabs.GetObject(true, i); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not read spawnable prefab " + i + ": " + ex.Message)); } if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponentInChildren(true) == (Object)null)) { string name = ((Object)((Component)val).gameObject).name; if (ByName.ContainsKey(name)) { Plugin.Log.LogWarning((object)("Two weapon prefabs share the name '" + name + "'; keeping the first.")); continue; } ByName[name] = val; Names.Add(name); } } Names.Sort(StringComparer.Ordinal); Ready = Names.Count > 0; Plugin.Log.LogInfo((object)("Base weapon index: " + Names.Count + " weapon prefab(s) of " + objectCount + " spawnable.")); if (Plugin.Cfg != null && Plugin.Cfg.VerboseLogging.Value) { foreach (string name2 in Names) { Plugin.Log.LogInfo((object)(" base: " + name2)); } } return Ready; } public static string Summary() { if (!Ready) { return "base weapon index not built yet"; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(Names.Count).Append(" base weapons: "); for (int i = 0; i < Names.Count; i++) { if (i > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Names[i]); } return stringBuilder.ToString(); } } internal sealed class BoneRecorder : MonoBehaviour { private sealed class Track { public Transform Bone; public Vector3 StartLocalPos; public Quaternion StartLocalRot; public Vector3 StartWorldPos; public float MaxLocalMove; public float MaxLocalAngle; public float MaxWorldMove; } public static bool Recording { get; private set; } public static string Start(float seconds) { if (Recording) { return "already recording"; } Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return "no local player"; } Item val = (((Object)(object)localPlayer.Holding == (Object)null) ? null : localPlayer.Holding.HeldItem); if ((Object)(object)val == (Object)null) { return "hold the weapon you want to record"; } Weapon componentInChildren = ((Component)val).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { return "the held item is not a weapon"; } SkinnedMeshRenderer componentInChildren2 = ((Component)val).GetComponentInChildren(true); if ((Object)(object)componentInChildren2 == (Object)null || componentInChildren2.bones == null || componentInChildren2.bones.Length == 0) { return "no skinned renderer with bones on the held weapon"; } ArsenalRuntime runtime = Plugin.Runtime; if ((Object)(object)runtime == (Object)null) { return "runtime not ready"; } ((MonoBehaviour)runtime).StartCoroutine(Record(val, componentInChildren, componentInChildren2, seconds)); return "recording " + componentInChildren2.bones.Length + " bone(s) for " + seconds + "s - reload now"; } private static IEnumerator Record(Item held, Weapon weapon, SkinnedMeshRenderer skinned, float seconds) { Recording = true; Plugin.Log.LogInfo((object)("=== bone recording: " + ((Object)((Component)held).gameObject).name + " ===")); LogAnimations(weapon); List tracks = new List(); HashSet hashSet = new HashSet(); Transform[] bones = skinned.bones; foreach (Transform val in bones) { if ((Object)(object)val != (Object)null && hashSet.Add(val)) { tracks.Add(Begin(val)); } } bones = ((Component)held).GetComponentsInChildren(true); foreach (Transform val2 in bones) { if ((!(((Object)val2).name != "l_IK") || !(((Object)val2).name != "r_IK")) && hashSet.Add(val2)) { tracks.Add(Begin(val2)); } } bool wasSuspended = HandDriver.Suspended; HandDriver.Suspended = true; Plugin.Log.LogInfo((object)" HandDriver override suspended for this recording."); try { float elapsed = 0f; while (elapsed < seconds) { foreach (Track item in tracks) { if (!((Object)(object)item.Bone == (Object)null)) { Vector3 val3 = item.Bone.localPosition - item.StartLocalPos; float magnitude = ((Vector3)(ref val3)).magnitude; if (magnitude > item.MaxLocalMove) { item.MaxLocalMove = magnitude; } float num = Quaternion.Angle(item.Bone.localRotation, item.StartLocalRot); if (num > item.MaxLocalAngle) { item.MaxLocalAngle = num; } val3 = item.Bone.position - item.StartWorldPos; float magnitude2 = ((Vector3)(ref val3)).magnitude; if (magnitude2 > item.MaxWorldMove) { item.MaxWorldMove = magnitude2; } } } elapsed += Time.deltaTime; yield return null; } } finally { HandDriver.Suspended = wasSuspended; } tracks.Sort((Track a, Track b) => (b.MaxLocalMove + b.MaxLocalAngle * 0.01f).CompareTo(a.MaxLocalMove + a.MaxLocalAngle * 0.01f)); Plugin.Log.LogInfo((object)"--- bones that moved (local space) ---"); int num2 = 0; foreach (Track item2 in tracks) { if (!(item2.MaxLocalMove < 0.0005f) || !(item2.MaxLocalAngle < 0.5f)) { num2++; Plugin.Log.LogInfo((object)(" " + ((Object)item2.Bone).name + " move=" + F(item2.MaxLocalMove) + " rot=" + F(item2.MaxLocalAngle) + "deg worldMove=" + F(item2.MaxWorldMove))); } } if (num2 == 0) { Plugin.Log.LogInfo((object)" none - no bone moved during the recording"); } Plugin.Log.LogInfo((object)"--- bones that stayed still ---"); foreach (Track item3 in tracks) { if (item3.MaxLocalMove < 0.0005f && item3.MaxLocalAngle < 0.5f) { Plugin.Log.LogInfo((object)(" " + ((Object)item3.Bone).name)); } } Verdict(tracks); LogMagCandidates(held); Plugin.Log.LogInfo((object)"=== end bone recording ==="); ChatManager.ChatMessage("[WA] recording done - " + num2 + " bone(s) moved, see the log"); Recording = false; } private static void Verdict(List tracks) { Plugin.Log.LogInfo((object)"--- IK target verdict ---"); bool flag = false; foreach (Track track in tracks) { if (!((Object)(object)track.Bone == (Object)null) && (!(((Object)track.Bone).name != "l_IK") || !(((Object)track.Bone).name != "r_IK"))) { flag = true; bool flag2 = track.MaxLocalMove >= 0.0005f || track.MaxLocalAngle >= 0.5f; Plugin.Log.LogInfo((object)(" " + ((Object)track.Bone).name + ": " + (flag2 ? "ANIMATED by the clip" : "not animated") + " (move=" + F(track.MaxLocalMove) + " rot=" + F(track.MaxLocalAngle) + "deg)")); } } if (!flag) { Plugin.Log.LogInfo((object)" no l_IK/r_IK transform on this weapon at all."); } else { Plugin.Log.LogInfo((object)" ANIMATED means the hand pose must be applied as an offset on top of the clip, never as an absolute position."); } } private static Track Begin(Transform node) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) return new Track { Bone = node, StartLocalPos = node.localPosition, StartLocalRot = node.localRotation, StartWorldPos = node.position }; } private static void LogAnimations(Weapon weapon) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown object obj = Refl.Get(weapon, "_anim"); Animation val = (Animation)((obj is Animation) ? obj : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogInfo((object)" Tool._anim is null - no legacy Animation on this weapon"); return; } Plugin.Log.LogInfo((object)" Animation component with clips:"); foreach (AnimationState item in val) { AnimationState val2 = item; Plugin.Log.LogInfo((object)(" clip '" + val2.name + "' length=" + F(val2.length))); } string text = Refl.Get(weapon, "_activeReloadAnimName") as string; Plugin.Log.LogInfo((object)(" _activeReloadAnimName = '" + (text ?? "") + "'")); } private static void LogMagCandidates(Item held) { Plugin.Log.LogInfo((object)"--- transforms with 'mag' or 'clip' in the name ---"); Transform[] componentsInChildren = ((Component)held).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { string text = ((Object)val).name.ToLowerInvariant(); if (text.IndexOf("mag") >= 0 || text.IndexOf("clip") >= 0) { Renderer component = ((Component)val).GetComponent(); Plugin.Log.LogInfo((object)(" " + ((Object)val).name + " active=" + ((Component)val).gameObject.activeSelf + " renderer=" + (((Object)(object)component == (Object)null) ? "none" : ((object)component).GetType().Name) + " children=" + val.childCount)); } } } private static string F(float value) { return value.ToString("F4", CultureInfo.InvariantCulture); } } internal static class ClipForge { private sealed class Sample { public float T; public Vector3[] Positions; public Quaternion[] Rotations; } private const int KeyCount = 32; private const string ClipName = "ReloadLast"; private static readonly string[] Tracked = new string[5] { "l_IK", "r_IK", "Gun", "Mag", "Slide" }; public static bool Recording; private static AnimationClip _original; private static Animation _originalOn; public static bool ApplyCharge; private static readonly List Samples = new List(); private static Transform[] _nodes; private static string[] _paths; private static BuiltWeapon _built; private static Animation _anim; private static bool _active; private static float _length; public static bool HasRecording => Samples.Count >= 8; public static void Begin(BuiltWeapon built, Animation animation, Transform searchRoot) { _built = built; _anim = animation; _active = false; Samples.Clear(); Transform transform = ((Component)animation).transform; List list = new List(); List list2 = new List(); string[] tracked = Tracked; foreach (string text in tracked) { Transform[] componentsInChildren = ((Component)searchRoot).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (!(((Object)val).name != text)) { string text2 = RelativePath(transform, val); if (text2 == null) { Plugin.Log.LogWarning((object)("Clip forge: '" + text + "' is not under the Animation component ('" + ((Object)transform).name + "'); it cannot be animated by a clip.")); } else { list.Add(val); list2.Add(text2); } break; } } } _nodes = list.ToArray(); _paths = list2.ToArray(); Recording = true; Plugin.Log.LogInfo((object)("Clip forge: watching 'ReloadLast' on " + _nodes.Length + " transform(s), paths relative to '" + ((Object)transform).name + "': " + string.Join(", ", _paths))); } public static void Tick(AnimationState state) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (!Recording || _nodes == null) { return; } if ((TrackedReference)(object)state == (TrackedReference)null || state.name != "ReloadLast") { if (_active) { Finish(); } return; } _active = true; Vector3[] array = (Vector3[])(object)new Vector3[_nodes.Length]; Quaternion[] array2 = (Quaternion[])(object)new Quaternion[_nodes.Length]; for (int i = 0; i < _nodes.Length; i++) { array[i] = _nodes[i].localPosition; array2[i] = _nodes[i].localRotation; } float num = Mathf.Clamp01(state.normalizedTime); if (Samples.Count <= 0 || !(num <= Samples[Samples.Count - 1].T)) { Samples.Add(new Sample { T = num, Positions = array, Rotations = array2 }); } } private static void Finish() { Recording = false; _active = false; if (Samples.Count < 8 || _built == null || (Object)(object)_anim == (Object)null) { Plugin.Log.LogWarning((object)("Clip forge: too few samples (" + Samples.Count + "); nothing built.")); ChatManager.ChatMessage("[WA] clip forge: not enough of the reload was seen"); return; } Samples.Sort((Sample a, Sample b) => a.T.CompareTo(b.T)); if (_length <= 0f) { _length = (((TrackedReference)(object)_anim["ReloadLast"] != (TrackedReference)null) ? _anim["ReloadLast"].length : 2.3f); } Rebake(); ChatManager.ChatMessage("[WA] clip forge: rebuilt" + (ApplyCharge ? " with the charge fix" : " as-is") + " - reload to check, /wa forge restore to undo"); } public static bool Rebake() { if (Samples.Count < 8 || _built == null || (Object)(object)_anim == (Object)null) { return false; } List list = new List(Samples.Count); foreach (Sample sample in Samples) { list.Add(new Sample { T = sample.T, Positions = (Vector3[])sample.Positions.Clone(), Rotations = (Quaternion[])sample.Rotations.Clone() }); } int num = Array.IndexOf(_paths, PathOf("l_IK")); IkDef ik = _built.Def.Ik; bool flag = false; if (ApplyCharge && num >= 0 && ik != null && ik.ChargeLeft != null && ik.ChargeLeft.Length >= 3) { RewriteCharge(list, num, ik); flag = true; } AnimationClip val = Bake(list, _length); if ((Object)(object)_original == (Object)null) { _original = _anim.GetClip("ReloadLast"); _originalOn = _anim; } _anim.RemoveClip("ReloadLast"); _anim.AddClip(val, "ReloadLast"); Plugin.Log.LogInfo((object)("Clip forge: rebuilt 'ReloadLast' from " + Samples.Count + " sample(s) at " + _length.ToString("F3") + "s" + (flag ? ", charge segment rewritten." : ", reproduced as recorded."))); return true; } private static void RewriteCharge(List samples, int handIndex, IkDef ik) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(ik.ChargeLeft[0], ik.ChargeLeft[1], ik.ChargeLeft[2]); float num = Mathf.Clamp01(ik.ChargeFrom); float num2 = Mathf.Clamp01(ik.ChargePeak); float num3 = Mathf.Clamp01(ik.ChargeTo); foreach (Sample sample in samples) { if (!(sample.T <= num) && !(sample.T >= num3)) { float num4 = ((sample.T < num2) ? Mathf.InverseLerp(num, num2, sample.T) : (1f - Mathf.InverseLerp(num2, num3, sample.T))); ref Vector3 reference = ref sample.Positions[handIndex]; reference += val * Mathf.SmoothStep(0f, 1f, num4); } } } private static AnimationClip Bake(List samples, float length) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown AnimationClip val = new AnimationClip { name = "WA_ReloadLast", legacy = true, wrapMode = (WrapMode)1 }; List picked = Decimate(samples); int n; for (n = 0; n < _paths.Length; n++) { SetCurve(val, _paths[n], "m_LocalPosition.x", picked, length, (Sample s) => s.Positions[n].x); SetCurve(val, _paths[n], "m_LocalPosition.y", picked, length, (Sample s) => s.Positions[n].y); SetCurve(val, _paths[n], "m_LocalPosition.z", picked, length, (Sample s) => s.Positions[n].z); Hemisphere(picked, n); SetCurve(val, _paths[n], "m_LocalRotation.x", picked, length, (Sample s) => s.Rotations[n].x); SetCurve(val, _paths[n], "m_LocalRotation.y", picked, length, (Sample s) => s.Rotations[n].y); SetCurve(val, _paths[n], "m_LocalRotation.z", picked, length, (Sample s) => s.Rotations[n].z); SetCurve(val, _paths[n], "m_LocalRotation.w", picked, length, (Sample s) => s.Rotations[n].w); } return val; } private static void Hemisphere(List picked, int index) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) for (int i = 1; i < picked.Count; i++) { Quaternion val = picked[i - 1].Rotations[index]; Quaternion val2 = picked[i].Rotations[index]; if (!(Quaternion.Dot(val, val2) >= 0f)) { picked[i].Rotations[index] = new Quaternion(0f - val2.x, 0f - val2.y, 0f - val2.z, 0f - val2.w); } } } private static void SetCurve(AnimationClip clip, string path, string property, List picked, float length, Func read) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown AnimationCurve val = new AnimationCurve(); foreach (Sample item in picked) { val.AddKey(item.T * length, read(item)); } Linear(val); clip.SetCurve(path, typeof(Transform), property, val); } private static void Linear(AnimationCurve curve) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < curve.length; i++) { Keyframe val = curve[i]; if (i > 0) { Keyframe val2 = curve[i - 1]; float num = ((Keyframe)(ref val)).time - ((Keyframe)(ref val2)).time; ((Keyframe)(ref val)).inTangent = ((num > 0.0001f) ? ((((Keyframe)(ref val)).value - ((Keyframe)(ref val2)).value) / num) : 0f); } if (i < curve.length - 1) { Keyframe val3 = curve[i + 1]; float num2 = ((Keyframe)(ref val3)).time - ((Keyframe)(ref val)).time; ((Keyframe)(ref val)).outTangent = ((num2 > 0.0001f) ? ((((Keyframe)(ref val3)).value - ((Keyframe)(ref val)).value) / num2) : 0f); } if (i == 0) { ((Keyframe)(ref val)).inTangent = ((Keyframe)(ref val)).outTangent; } if (i == curve.length - 1) { ((Keyframe)(ref val)).outTangent = ((Keyframe)(ref val)).inTangent; } curve.MoveKey(i, val); } } private static List Decimate(List samples) { if (samples.Count <= 32) { return new List(samples); } List list = new List(); float num = (float)(samples.Count - 1) / 31f; for (int i = 0; i < 32; i++) { list.Add(samples[Mathf.RoundToInt((float)i * num)]); } return list; } public static bool Restore() { if ((Object)(object)_original == (Object)null || (Object)(object)_originalOn == (Object)null) { return false; } _originalOn.RemoveClip("ReloadLast"); _originalOn.AddClip(_original, "ReloadLast"); Plugin.Log.LogInfo((object)"Clip forge: 'ReloadLast' restored to the weapon's own clip."); Samples.Clear(); ApplyCharge = false; _original = null; _originalOn = null; return true; } private static string PathOf(string name) { string[] paths = _paths; foreach (string text in paths) { if (text == name || text.EndsWith("/" + name)) { return text; } } return name; } private static string RelativePath(Transform root, Transform node) { List list = new List(); Transform val = node; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } if ((Object)(object)val != (Object)(object)root) { return null; } list.Reverse(); return string.Join("/", list.ToArray()); } } internal static class GripSolver { private const float Clearance = 0.04f; private const int Iterations = 24; private const float MaxCurl = 110f; private static readonly string[] Fingers = new string[5] { "thumb", "index", "middle", "ring", "pinky" }; private static readonly string[] Segments = new string[3] { "low", "mid", "tip" }; public static string Solve(BuiltWeapon built, bool left, bool apply, out Dictionary pose) { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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) pose = new Dictionary(); if (built == null || built.Targets.Count == 0) { return "weapon not built"; } SkinnedMeshRenderer skinned = built.Targets[0].Skinned; if ((Object)(object)skinned == (Object)null || skinned.bones == null || skinned.bones.Length == 0) { return "the base weapon has no skinned renderer with bones"; } List list = SkinnedPoints(skinned); if (list.Count == 0) { return "could not read the weapon surface"; } string prefix = (left ? "l_" : "r_"); Dictionary bones = ByName(skinned.bones); float num = HandSpan(bones, prefix) * 0.04f; int num2 = 0; StringBuilder stringBuilder = new StringBuilder(); string[] fingers = Fingers; foreach (string text in fingers) { Transform[] array = Chain(bones, prefix, text); if (array != null) { Transform val = array[^1]; float value = NearestDistance(list, val.position); Transform[] array2 = array; for (int j = 0; j < array2.Length; j++) { CurlJoint(array2[j], val, list, num); } float value2 = NearestDistance(list, val.position); num2++; array2 = array; foreach (Transform val2 in array2) { Quaternion localRotation = val2.localRotation; Vector3 eulerAngles = ((Quaternion)(ref localRotation)).eulerAngles; pose[((Object)val2).name] = new float[3] { Wrap(eulerAngles.x), Wrap(eulerAngles.y), Wrap(eulerAngles.z) }; } stringBuilder.Append(" ").Append(text).Append(": tip ") .Append(F(value)) .Append(" -> ") .Append(F(value2)) .Append(" from the surface") .AppendLine(); } } if (num2 == 0) { return "no " + (left ? "left" : "right") + "-hand finger bones on this weapon"; } Plugin.Log.LogInfo((object)("Grip solve on '" + built.Def.Id + "' (" + (left ? "left" : "right") + " hand), " + list.Count + " surface points, clearance " + F(num) + ":")); Plugin.Log.LogInfo((object)stringBuilder.ToString().TrimEnd(Array.Empty())); if (apply) { if (built.Def.Pose == null) { built.Def.Pose = new Dictionary(); } foreach (KeyValuePair item in pose) { built.Def.Pose[item.Key] = item.Value; } WeaponBuilder.ApplyPose(built); } return num2 + " finger(s) wrapped; see the log for how close each tip landed"; } private static void CurlJoint(Transform joint, Transform tip, List surface, float clearance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) Quaternion localRotation = joint.localRotation; float num = Score(tip, surface, clearance); float num2 = 16f; for (int i = 0; i < 24; i++) { bool flag = false; for (int j = 0; j < 3; j++) { if (flag) { break; } for (int k = -1; k <= 1; k += 2) { if (flag) { break; } Quaternion localRotation2 = joint.localRotation; Vector3 zero = Vector3.zero; ((Vector3)(ref zero))[j] = num2 * (float)k; joint.localRotation = localRotation2 * Quaternion.Euler(zero); if (Quaternion.Angle(localRotation, joint.localRotation) > 110f) { joint.localRotation = localRotation2; continue; } float num3 = Score(tip, surface, clearance); if (num3 < num - 0.0001f) { num = num3; flag = true; } else { joint.localRotation = localRotation2; } } } if (!flag) { num2 *= 0.5f; if (num2 < 0.5f) { break; } } } } private static float Score(Transform tip, List surface, float clearance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) float num = NearestDistance(surface, tip.position) - clearance; if (!(num < 0f)) { return num; } return (0f - num) * 4f; } private static float NearestDistance(List points, Vector3 from) { //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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) float num = float.MaxValue; for (int i = 0; i < points.Count; i++) { Vector3 val = points[i] - from; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; } } return Mathf.Sqrt(num); } private static List SkinnedPoints(SkinnedMeshRenderer skinned) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Mesh sharedMesh = skinned.sharedMesh; if ((Object)(object)sharedMesh == (Object)null) { return list; } Vector3[] vertices = sharedMesh.vertices; BoneWeight[] boneWeights = sharedMesh.boneWeights; Matrix4x4[] bindposes = sharedMesh.bindposes; Transform[] bones = skinned.bones; if (boneWeights.Length != vertices.Length || bindposes.Length == 0) { return list; } int num = Mathf.Max(1, vertices.Length / 2000); for (int i = 0; i < vertices.Length; i += num) { BoneWeight val = boneWeights[i]; int boneIndex = ((BoneWeight)(ref val)).boneIndex0; if (boneIndex >= 0 && boneIndex < bones.Length && boneIndex < bindposes.Length && !((Object)(object)bones[boneIndex] == (Object)null)) { Matrix4x4 localToWorldMatrix = bones[boneIndex].localToWorldMatrix; list.Add(((Matrix4x4)(ref localToWorldMatrix)).MultiplyPoint3x4(((Matrix4x4)(ref bindposes[boneIndex])).MultiplyPoint3x4(vertices[i]))); } } return list; } private static Transform[] Chain(Dictionary bones, string prefix, string finger) { List list = new List(); string[] segments = Segments; foreach (string text in segments) { if (bones.TryGetValue(prefix + finger + "_" + text, out var value)) { list.Add(value); } } if (list.Count != 0) { return list.ToArray(); } return null; } private static float HandSpan(Dictionary bones, string prefix) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (bones.TryGetValue(prefix + "middle_low", out var value) && bones.TryGetValue(prefix + "middle_tip", out var value2)) { float num = Vector3.Distance(value.position, value2.position); if (num > 0.0001f) { return num; } } return 0.1f; } private static Dictionary ByName(Transform[] bones) { Dictionary dictionary = new Dictionary(); foreach (Transform val in bones) { if ((Object)(object)val != (Object)null && !dictionary.ContainsKey(((Object)val).name)) { dictionary[((Object)val).name] = val; } } return dictionary; } private static float Wrap(float degrees) { if (!(degrees > 180f)) { return degrees; } return degrees - 360f; } private static string F(float value) { return value.ToString("F4", CultureInfo.InvariantCulture); } } internal sealed class HandDriver : MonoBehaviour { private Transform _left; private Transform _right; private Vector3 _leftDelta; private Vector3 _rightDelta; private Quaternion _leftRotDelta; private Quaternion _rightRotDelta; private Vector3 _leftReloadDelta; private Quaternion _leftReloadRotDelta = Quaternion.identity; private float _reloadBlend = 0.15f; private float _blend; private Animation _anim; private const float ReloadEaseIn = 0.12f; private float _gripReturnAt = 0.85f; private Vector3 _chargeDelta; private float _chargeFrom = 0.6f; private float _chargePeak = 0.72f; private float _chargeTo = 0.85f; private string _chargeClip = "ReloadLast"; private static readonly string[] ReloadClips = new string[2] { "ReloadLast", "Reload" }; private bool _hasLeftPos; private bool _hasRightPos; private bool _hasLeftRot; private bool _hasRightRot; private bool _resolved; private Weapon _weapon; private Transform _gun; private Transform _mag; private ReloadAnimator _reload; private Vector3 _magRest; private bool _wasReloading; private static bool _loggedOnce; public static bool Suspended; public static bool LearningCharge; private BuiltWeapon _built; private SkinnedMeshRenderer _skinned; private Transform _slide; private Vector3 _slideRest; private float _chargeStartT = -1f; private float _chargePeakT; private float _peakDisplacement; private Vector3 _capturedHand; private Vector3 _capturedHandle; private bool _capturing; private bool _captured; private string _capturedClip; private readonly List> _path = new List>(); private Vector3 _leftWrittenPos; private Vector3 _rightWrittenPos; private Vector3 _leftClipPos; private Vector3 _rightClipPos; private Quaternion _leftWrittenRot; private Quaternion _rightWrittenRot; private Quaternion _leftClipRot; private Quaternion _rightClipRot; private bool _leftPrimed; private bool _rightPrimed; public Animation Anim => _anim; public BuiltWeapon Built => _built; public void Rebuild(BuiltWeapon built) { //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_019e: 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_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: 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_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) _hasLeftPos = (_hasRightPos = (_hasLeftRot = (_hasRightRot = false))); _leftPrimed = (_rightPrimed = false); _left = Find("l_IK"); _right = Find("r_IK"); IkDef ikDef = built?.Def.Ik; if (ikDef != null) { if (ikDef.Left != null && ikDef.Left.Length >= 3 && (Object)(object)_left != (Object)null && built.HasIkRestLeft) { _leftDelta = new Vector3(ikDef.Left[0], ikDef.Left[1], ikDef.Left[2]) - built.IkRestLeftPos; _hasLeftPos = true; } _reloadBlend = Mathf.Max(0.01f, ikDef.ReloadBlend); _gripReturnAt = Mathf.Clamp01(ikDef.GripReturnAt); _chargeFrom = Mathf.Clamp01(ikDef.ChargeFrom); _chargePeak = Mathf.Clamp01(ikDef.ChargePeak); _chargeTo = Mathf.Clamp01(ikDef.ChargeTo); _chargeClip = ikDef.ChargeClip; _chargeDelta = (Vector3)((ikDef.ChargeLeft != null && ikDef.ChargeLeft.Length >= 3) ? new Vector3(ikDef.ChargeLeft[0], ikDef.ChargeLeft[1], ikDef.ChargeLeft[2]) : Vector3.zero); _leftReloadDelta = (Vector3)((ikDef.ReloadLeft != null && ikDef.ReloadLeft.Length >= 3) ? new Vector3(ikDef.ReloadLeft[0], ikDef.ReloadLeft[1], ikDef.ReloadLeft[2]) : Vector3.zero); _leftReloadRotDelta = ((ikDef.ReloadLeftRotation != null && ikDef.ReloadLeftRotation.Length >= 3) ? Quaternion.Euler(ikDef.ReloadLeftRotation[0], ikDef.ReloadLeftRotation[1], ikDef.ReloadLeftRotation[2]) : Quaternion.identity); if (ikDef.Right != null && ikDef.Right.Length >= 3 && (Object)(object)_right != (Object)null && built.HasIkRestRight) { _rightDelta = new Vector3(ikDef.Right[0], ikDef.Right[1], ikDef.Right[2]) - built.IkRestRightPos; _hasRightPos = true; } if (ikDef.LeftRotation != null && ikDef.LeftRotation.Length >= 3 && (Object)(object)_left != (Object)null && built.HasIkRestLeft) { Quaternion val = Quaternion.Euler(ikDef.LeftRotation[0], ikDef.LeftRotation[1], ikDef.LeftRotation[2]); _leftRotDelta = Quaternion.Inverse(built.IkRestLeftRot) * val; _hasLeftRot = true; } if (ikDef.RightRotation != null && ikDef.RightRotation.Length >= 3 && (Object)(object)_right != (Object)null && built.HasIkRestRight) { Quaternion val2 = Quaternion.Euler(ikDef.RightRotation[0], ikDef.RightRotation[1], ikDef.RightRotation[2]); _rightRotDelta = Quaternion.Inverse(built.IkRestRightRot) * val2; _hasRightRot = true; } } } private void Resolve() { if (_resolved) { return; } _resolved = true; ArsenalWeapon componentInChildren = ((Component)this).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null || (Object)(object)Plugin.Runtime == (Object)null) { return; } BuiltWeapon builtWeapon = Plugin.Runtime.Find(componentInChildren.WeaponId); if (builtWeapon == null) { return; } _built = builtWeapon; _weapon = ((Component)this).GetComponentInChildren(true); _anim = (Animation)(((Object)(object)_weapon == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); _skinned = ((Component)this).GetComponentInChildren(true); Rebuild(builtWeapon); Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == "Gun") { _gun = val; } else if (((Object)val).name == "Mag") { _mag = val; } } SetUpReload(builtWeapon); if (!_loggedOnce) { _loggedOnce = true; Plugin.Log.LogInfo((object)("HandDriver live on '" + componentInChildren.WeaponId + "': leftPos=" + _hasLeftPos + " leftRot=" + _hasLeftRot + " rightPos=" + _hasRightPos + " rightRot=" + _hasRightRot + " | offsets are applied on top of the weapon's own animation")); } } private unsafe void SetUpReload(BuiltWeapon built) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) ReloadDef reload = built.Def.Reload; if (reload == null || !reload.Enabled || (Object)(object)_gun == (Object)null || (Object)(object)_mag == (Object)null || !_hasLeftPos) { return; } if (HasClip(_anim, "Reload") || HasClip(_anim, "ReloadLast")) { Plugin.Log.LogInfo((object)("Reload animation on '" + built.Def.Id + "': skipped - the base weapon '" + built.Def.BasePrefab + "' has its own reload clip, which already moves the magazine and the gun. Set reload.enabled=false in the def to silence this.")); return; } _magRest = _mag.localPosition; Vector3 val = _mag.localPosition; Vector3 val2 = ((Vector3)(ref val)).normalized; if (val2 == Vector3.zero) { val2 = Vector3.down; } Vector3 dipDirection = Vector3.Cross(val2, Vector3.right); if (((Vector3)(ref dipDirection)).sqrMagnitude < 0.01f) { dipDirection = Vector3.Cross(val2, Vector3.forward); } _reload = new ReloadAnimator(reload, val2, dipDirection); ManualLogSource log = Plugin.Log; string[] obj = new string[9] { "Reload animation on '", built.Def.Id, "': synthesised - extract ", ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(), ", dip ", null, null, null, null }; val = ((Vector3)(ref dipDirection)).normalized; obj[5] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[6] = ", "; obj[7] = reload.Duration.ToString(); obj[8] = "s"; log.LogInfo((object)string.Concat(obj)); } private float ReloadWeight(bool reloading) { if (!reloading) { return 0f; } AnimationState val = ReloadState(); if ((TrackedReference)(object)val == (TrackedReference)null) { return 1f; } float num = Mathf.Repeat(val.normalizedTime, 1f); if (num < 0.12f) { return num / 0.12f; } if (num > _gripReturnAt) { return Mathf.Max(0f, (1f - num) / Mathf.Max(0.0001f, 1f - _gripReturnAt)); } return 1f; } private void CaptureCharge(bool reloading) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_slide == (Object)null) { Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == "Slide") { _slide = val; _slideRest = val.localPosition; break; } } } AnimationState val2 = ReloadState(); if (!reloading || (TrackedReference)(object)val2 == (TrackedReference)null) { if (_capturing) { _capturing = false; LearningCharge = false; Finish(); } return; } if (!_capturing) { _capturing = true; _captured = false; _peakDisplacement = 0f; _chargeStartT = -1f; _capturedClip = val2.name; _path.Clear(); if ((Object)(object)_slide != (Object)null) { _slideRest = _slide.localPosition; } } if ((Object)(object)_left != (Object)null) { _path.Add(new KeyValuePair(Mathf.Repeat(val2.normalizedTime, 1f), _left.localPosition)); } if ((Object)(object)_slide == (Object)null) { return; } float num = Mathf.Repeat(val2.normalizedTime, 1f); Vector3 val3 = _slide.localPosition - _slideRest; float magnitude = ((Vector3)(ref val3)).magnitude; if (magnitude > 0.0005f && _chargeStartT < 0f) { _chargeStartT = num; } if (magnitude > _peakDisplacement) { _peakDisplacement = magnitude; _chargePeakT = num; if ((Object)(object)_left != (Object)null) { _capturedHand = _left.localPosition; _capturedHandle = HandleCentre(); _captured = _capturedHandle != Vector3.zero; } } } private Vector3 HandleCentre() { //IL_002f: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_skinned == (Object)null || (Object)(object)_left == (Object)null || (Object)(object)_left.parent == (Object)null) { return Vector3.zero; } Mesh sharedMesh = _skinned.sharedMesh; Transform[] bones = _skinned.bones; if ((Object)(object)sharedMesh == (Object)null || bones == null) { return Vector3.zero; } BoneWeight[] boneWeights = sharedMesh.boneWeights; Matrix4x4[] bindposes = sharedMesh.bindposes; Vector3[] vertices = sharedMesh.vertices; if (boneWeights.Length != vertices.Length || bindposes.Length == 0) { return Vector3.zero; } int num = -1; for (int i = 0; i < bones.Length; i++) { if ((Object)(object)bones[i] != (Object)null && ((Object)bones[i]).name == "Slide") { num = i; break; } } if (num < 0 || num >= bindposes.Length) { return Vector3.zero; } Vector3 val = Vector3.zero; int num2 = 0; for (int j = 0; j < vertices.Length; j++) { if (((BoneWeight)(ref boneWeights[j])).boneIndex0 == num) { Vector3 val2 = val; Matrix4x4 localToWorldMatrix = bones[num].localToWorldMatrix; val = val2 + ((Matrix4x4)(ref localToWorldMatrix)).MultiplyPoint3x4(((Matrix4x4)(ref bindposes[num])).MultiplyPoint3x4(vertices[j])); num2++; } } if (num2 == 0) { return Vector3.zero; } return _left.parent.InverseTransformPoint(val / (float)num2); } private void Finish() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!_captured || _built == null) { Plugin.Log.LogWarning((object)"Charge learn: nothing measured. Either the reload clip never moved the Slide bone, or no model geometry is bound to it - check the def's partBones."); ChatManager.ChatMessage("[WA] charge learn: nothing to measure, see the log"); return; } Vector3 val = _capturedHandle - _capturedHand; IkDef ikDef = _built.Def.Ik ?? (_built.Def.Ik = new IkDef()); ikDef.ChargeLeft = new float[3] { val.x, val.y, val.z }; ikDef.ChargeClip = _capturedClip; ikDef.ChargeFrom = ApproachStart(); ikDef.ChargePeak = Mathf.Clamp01(_chargePeakT); ikDef.ChargeTo = Mathf.Clamp01(_chargePeakT + (_chargePeakT - ikDef.ChargeFrom)); if (ikDef.GripReturnAt < ikDef.ChargeTo) { ikDef.GripReturnAt = Mathf.Clamp01(ikDef.ChargeTo + 0.05f); } Rebuild(_built); Plugin.Log.LogInfo((object)("Charge learn on '" + _built.Def.Id + "': the clip put the hand at " + ((Vector3)(ref _capturedHand)).ToString("F3") + " while this model's handle sits at " + ((Vector3)(ref _capturedHandle)).ToString("F3") + " -> offset " + ((Vector3)(ref val)).ToString("F3") + ", window " + ikDef.ChargeFrom.ToString("F2") + "-" + ikDef.ChargePeak.ToString("F2") + "-" + ikDef.ChargeTo.ToString("F2") + " of '" + ikDef.ChargeClip + "' only - the shorter 'Reload' clip never racks, so it is left alone.")); ChatManager.ChatMessage("[WA] charge learn: offset " + ((Vector3)(ref val)).ToString("F2") + " - reload to check, then /wa ik " + _built.Def.Id + " save"); } private float ApproachStart() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) float num = ((_chargeStartT < 0f) ? Mathf.Max(0f, _chargePeakT - 0.15f) : _chargeStartT); float num2 = -1f; foreach (KeyValuePair item in _path) { if (!(item.Key >= _chargePeakT)) { Vector3 val = item.Value - _capturedHand; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude <= num2)) { num2 = sqrMagnitude; num = item.Key; } } } return Mathf.Clamp01(num); } private Vector3 ChargeOffset(bool reloading) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (!reloading || _chargeDelta == Vector3.zero) { return Vector3.zero; } AnimationState val = ReloadState(); if ((TrackedReference)(object)val == (TrackedReference)null) { return Vector3.zero; } if (!string.IsNullOrEmpty(_chargeClip) && val.name != _chargeClip) { return Vector3.zero; } float num = Mathf.Repeat(val.normalizedTime, 1f); if (num <= _chargeFrom || num >= _chargeTo) { return Vector3.zero; } float num2 = ((num < _chargePeak) ? Mathf.InverseLerp(_chargeFrom, _chargePeak, num) : (1f - Mathf.InverseLerp(_chargePeak, _chargeTo, num))); return _chargeDelta * Mathf.SmoothStep(0f, 1f, num2); } private AnimationState ReloadState() { Animation anim = _anim; if ((Object)(object)anim == (Object)null) { return null; } string[] reloadClips = ReloadClips; foreach (string text in reloadClips) { if (anim.IsPlaying(text)) { return anim[text]; } } return null; } private static bool HasClip(Animation animation, string clip) { if ((Object)(object)animation != (Object)null) { return (Object)(object)animation.GetClip(clip) != (Object)null; } return false; } private Transform Find(string wanted) { Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == wanted) { return val; } } return null; } private void OnEnable() { Resolve(); } private bool Busy() { if ((Object)(object)_weapon == (Object)null) { return false; } object obj = Refl.Get(_weapon, "_isReloading"); if (obj is bool) { return (bool)obj; } return false; } private void LateUpdate() { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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_008b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)this == (Object)null || Suspended) { return; } bool flag = Busy(); if (LearningCharge) { CaptureCharge(flag); return; } if (ClipForge.Recording) { ClipForge.Tick(ReloadState()); return; } if (flag && _reload != null) { DriveSynthesisedReload(); return; } if (_wasReloading) { _wasReloading = false; if (_reload != null) { _reload.Stop(); } if (_reload != null && (Object)(object)_mag != (Object)null) { _mag.localPosition = _magRest; } } _blend = Mathf.MoveTowards(_blend, ReloadWeight(flag), Time.deltaTime / _reloadBlend); Vector3 posDelta = Vector3.Lerp(_leftDelta, _leftReloadDelta, _blend) + ChargeOffset(flag); Quaternion rotDelta = Quaternion.Slerp(_leftRotDelta, _leftReloadRotDelta, _blend); ApplySide(_left, ref _leftPrimed, ref _leftWrittenPos, ref _leftClipPos, ref _leftWrittenRot, ref _leftClipRot, _hasLeftPos, posDelta, _hasLeftRot, rotDelta); ApplySide(_right, ref _rightPrimed, ref _rightWrittenPos, ref _rightClipPos, ref _rightWrittenRot, ref _rightClipRot, _hasRightPos, _rightDelta, _hasRightRot, _rightRotDelta); } private static void ApplySide(Transform node, ref bool primed, ref Vector3 written, ref Vector3 clipPos, ref Quaternion writtenRot, ref Quaternion clipRot, bool hasPos, Vector3 posDelta, bool hasRot, Quaternion rotDelta) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)node == (Object)null) && (hasPos || hasRot)) { Vector3 localPosition = node.localPosition; Quaternion localRotation = node.localRotation; if (!primed || !(localPosition == written) || !(localRotation == writtenRot)) { clipPos = localPosition; clipRot = localRotation; } if (hasPos) { written = clipPos + posDelta; node.localPosition = written; } else { written = localPosition; } if (hasRot) { writtenRot = clipRot * rotDelta; node.localRotation = writtenRot; } else { writtenRot = localRotation; } primed = true; } } private void DriveSynthesisedReload() { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (!_wasReloading) { _reload.Begin(Time.time); } _wasReloading = true; if (!_reload.Sample(Time.time, out var handOffset, out var magOffset)) { return; } if ((Object)(object)_left != (Object)null && _hasLeftPos) { _leftWrittenPos = _leftClipPos + _leftDelta + handOffset; _left.localPosition = _leftWrittenPos; if (_hasLeftRot) { _leftWrittenRot = _leftClipRot * _leftRotDelta; _left.localRotation = _leftWrittenRot; } } if ((Object)(object)_mag != (Object)null) { _mag.localPosition = _magRest + magOffset; } } } internal static class IslandCatalog { public static int Total => IslandManager.TotalIslands; public static string SceneName(int islandIndex) { int num = islandIndex + 1; if (num < 0 || num >= SceneManager.sceneCountInBuildSettings) { return null; } string scenePathByBuildIndex = SceneUtility.GetScenePathByBuildIndex(num); if (!string.IsNullOrEmpty(scenePathByBuildIndex)) { return Path.GetFileNameWithoutExtension(scenePathByBuildIndex); } return null; } public static int Current() { FieldInfo fieldInfo = AccessTools.Field(typeof(IslandManager), "_instance"); IslandManager val = (IslandManager)((fieldInfo == null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val == (Object)null) { return -1; } object obj = Refl.Get(val, "_curIsland"); if (obj != null) { return (byte)obj; } return -1; } public static bool IsDevIsland(int islandIndex) { string text = SceneName(islandIndex); if (text != null) { return text.IndexOf("dev", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } public static int LastPlayableIsland() { for (int num = Total - 1; num >= 0; num--) { if (!IsDevIsland(num)) { return num; } } return Total - 1; } public static List Describe() { List list = new List(); int num = Current(); for (int i = 0; i < Total; i++) { string text = SceneName(i) ?? ""; list.Add(((i == num) ? "> " : " ") + i + ": " + text + (IsDevIsland(i) ? " [dev]" : "")); } return list; } public static int Resolve(string nameFragment, int index) { if (!string.IsNullOrEmpty(nameFragment)) { for (int i = 0; i < Total; i++) { string text = SceneName(i); if (text != null && text.IndexOf(nameFragment, StringComparison.OrdinalIgnoreCase) >= 0) { return i; } } Plugin.Log.LogWarning((object)("No island scene matching '" + nameFragment + "'; falling back to the index.")); } if (index >= 0 && index < Total) { return index; } return LastPlayableIsland(); } } internal static class ItemIdRegistry { private const byte InvalidId = byte.MaxValue; private static readonly Dictionary Assigned = new Dictionary(StringComparer.OrdinalIgnoreCase); public static bool TryGetId(string weaponId, out byte id) { return Assigned.TryGetValue(weaponId, out id); } public static void Reset() { Assigned.Clear(); } public static void RegisterAll(IReadOnlyList built) { Dictionary dictionary = Dict("_allItems"); if (dictionary == null) { Plugin.Log.LogWarning((object)"GameInfo._allItems unavailable; custom weapons cannot be sold."); return; } Dictionary dictionary2 = Dict("_idToSpawnable"); Dictionary dictionary3 = NameDict(); foreach (BuiltWeapon item in built) { if ((Object)(object)item.Weapon == (Object)null) { continue; } if (!Assigned.TryGetValue(item.Def.Id, out var value)) { if (!TryAllocate(dictionary, out value)) { Plugin.Log.LogError((object)("No free item ID left for '" + item.Def.Id + "'.")); continue; } Assigned[item.Def.Id] = value; } ((Item)item.Weapon).SetID(value); if (item.Def.Shop != null) { Refl.SetRaw(item.Weapon, "_cost", item.Def.Shop.Price); } dictionary[value] = (Item)(object)item.Weapon; if (dictionary2 != null) { dictionary2[value] = (Item)(object)item.Weapon; } if (dictionary3 != null) { dictionary3[item.Def.Id.Replace(" ", "").ToLower()] = (Item)(object)item.Weapon; } Plugin.Log.LogInfo((object)("Item ID " + value + " -> " + item.Def.Id + " (cost " + ((item.Def.Shop != null) ? item.Def.Shop.Price : 0) + ")")); } } private static bool TryAllocate(Dictionary allItems, out byte id) { HashSet hashSet = new HashSet(allItems.Keys); foreach (byte value in Assigned.Values) { hashSet.Add(value); } for (int num = 254; num >= 0; num--) { if (!hashSet.Contains((byte)num)) { id = (byte)num; return true; } } id = byte.MaxValue; return false; } private static Dictionary Dict(string fieldName) { FieldInfo fieldInfo = AccessTools.Field(typeof(GameInfo), fieldName); if (!(fieldInfo == null)) { return fieldInfo.GetValue(null) as Dictionary; } return null; } private static Dictionary NameDict() { FieldInfo fieldInfo = AccessTools.Field(typeof(GameInfo), "_nameToSpawnable"); if (!(fieldInfo == null)) { return fieldInfo.GetValue(null) as Dictionary; } return null; } } internal static class ModPrefabRegistry { private static readonly Dictionary Registered = new Dictionary(StringComparer.OrdinalIgnoreCase); public static bool Ready { get; private set; } public static ushort CollectionId { get; private set; } public static string LastError { get; private set; } public static int Count => Registered.Count; public static NetworkObject Get(string weaponId) { if (string.IsNullOrEmpty(weaponId)) { return null; } if (!Registered.TryGetValue(weaponId, out var value)) { return null; } return value; } public static void Reset() { Registered.Clear(); Ready = false; LastError = null; } public static bool RegisterAll(IReadOnlyList> orderedPrefabs, ushort collectionId) { Reset(); CollectionId = collectionId; if (orderedPrefabs == null || orderedPrefabs.Count == 0) { Plugin.Log.LogInfo((object)"No weapon prefabs to register."); Ready = true; return true; } NetworkManager networkManager = InstanceFinder.NetworkManager; if ((Object)(object)networkManager == (Object)null) { LastError = "no NetworkManager available"; Plugin.Log.LogWarning((object)("Prefab registration deferred: " + LastError)); return false; } PrefabObjects prefabObjects; try { prefabObjects = networkManager.GetPrefabObjects(collectionId, true); } catch (Exception ex) { LastError = "GetPrefabObjects failed: " + ex.Message; Plugin.Log.LogError((object)("Prefab registration failed: " + LastError)); return false; } if ((Object)(object)prefabObjects == (Object)null) { LastError = "GetPrefabObjects returned null for collection " + collectionId; Plugin.Log.LogError((object)("Prefab registration failed: " + LastError)); return false; } try { prefabObjects.Clear(); for (int i = 0; i < orderedPrefabs.Count; i++) { KeyValuePair keyValuePair = orderedPrefabs[i]; NetworkObject value = keyValuePair.Value; if (!((Object)(object)value == (Object)null)) { value.SetIsNetworked(true); prefabObjects.AddObject(value, true, true); Registered[keyValuePair.Key] = value; Plugin.Log.LogInfo((object)("Registered network prefab " + keyValuePair.Key + " -> collection " + value.SpawnableCollectionId + ", prefabId " + value.PrefabId + " (expected index " + i + ")")); if (value.PrefabId != i) { Plugin.Log.LogWarning((object)("Prefab '" + keyValuePair.Key + "' landed on id " + value.PrefabId + " but the arsenal order puts it at " + i + ". Ordering must be identical on every client.")); } } } } catch (Exception ex2) { LastError = ex2.Message; Plugin.Log.LogError((object)("Prefab registration threw: " + ex2)); return false; } Ready = true; Plugin.Log.LogInfo((object)("Prefab registration complete: " + Registered.Count + " weapon(s) in collection " + collectionId + ".")); return true; } public static string Status() { if (Ready) { return "collection " + CollectionId + ", " + Registered.Count + " weapon(s) registered"; } return "NOT registered" + ((LastError != null) ? (" (" + LastError + ")") : ""); } } internal sealed class PoseDriver : MonoBehaviour { private readonly List _bones = new List(); private readonly List _rotations = new List(); private bool _resolved; public int Count => _bones.Count; private void OnEnable() { if (_resolved) { return; } _resolved = true; ArsenalWeapon componentInChildren = ((Component)this).GetComponentInChildren(true); if (!((Object)(object)componentInChildren == (Object)null) && !((Object)(object)Plugin.Runtime == (Object)null)) { BuiltWeapon builtWeapon = Plugin.Runtime.Find(componentInChildren.WeaponId); if (builtWeapon != null) { Rebuild(builtWeapon.Def.Pose); } } } public void Rebuild(Dictionary pose) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) _bones.Clear(); _rotations.Clear(); if (pose == null || pose.Count == 0) { return; } Dictionary dictionary = new Dictionary(); Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (!dictionary.ContainsKey(((Object)val).name)) { dictionary[((Object)val).name] = val; } } foreach (KeyValuePair item in pose) { if (item.Value != null && item.Value.Length >= 3) { if (!dictionary.TryGetValue(item.Key, out var value)) { Plugin.Log.LogWarning((object)("pose: no bone called '" + item.Key + "' on this weapon.")); continue; } _bones.Add(value); _rotations.Add(Quaternion.Euler(item.Value[0], item.Value[1], item.Value[2])); } } } private void LateUpdate() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _bones.Count; i++) { if ((Object)(object)_bones[i] != (Object)null) { _bones[i].localRotation = _rotations[i]; } } } } internal static class PrefabInspector { public static string Dump(GameObject root, Item item, string label) { if ((Object)(object)root == (Object)null) { return "nothing to inspect"; } GameObject val = (((Object)(object)item != (Object)null) ? Refl.GetAs(item, "_inHandHolder") : null); GameObject val2 = (((Object)(object)item != (Object)null) ? Refl.GetAs(item, "_outOfHandHolder") : null); Renderer val3 = (((Object)(object)item != (Object)null) ? Refl.GetAs(item, "_handsMesh") : null); Plugin.Log.LogInfo((object)("=== prefab dump: " + label + " ===")); Plugin.Log.LogInfo((object)(" _inHandHolder : " + (((Object)(object)val != (Object)null) ? ((Object)val).name : ""))); Plugin.Log.LogInfo((object)(" _outOfHandHolder : " + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : ""))); Plugin.Log.LogInfo((object)(" _handsMesh : " + (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : ""))); List list = Refl.Get(item, "_renderers") as List; List list2 = Refl.Get(item, "_skinRenderers") as List; Plugin.Log.LogInfo((object)(" _renderers : " + ((list != null) ? list.Count.ToString() : ""))); Plugin.Log.LogInfo((object)(" _skinRenderers : " + ((list2 != null) ? list2.Count.ToString() : ""))); int meshRenderers = 0; int skinnedRenderers = 0; Walk(root.transform, root.transform, 0, val, val2, val3, ref meshRenderers, ref skinnedRenderers); string text = meshRenderers + " MeshRenderer(s), " + skinnedRenderers + " SkinnedMeshRenderer(s)"; Plugin.Log.LogInfo((object)("=== end dump: " + text + " ===")); return text; } private static void Walk(Transform root, Transform node, int depth, GameObject inHand, GameObject outOfHand, Renderer handsMesh, ref int meshRenderers, ref int skinnedRenderers) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(" ").Append(' ', depth * 2).Append(((Object)node).name); if (!((Component)node).gameObject.activeSelf) { stringBuilder.Append(" [inactive]"); } if ((Object)(object)inHand != (Object)null && (Object)(object)((Component)node).gameObject == (Object)(object)inHand) { stringBuilder.Append(" "); } if ((Object)(object)outOfHand != (Object)null && (Object)(object)((Component)node).gameObject == (Object)(object)outOfHand) { stringBuilder.Append(" "); } MeshFilter component = ((Component)node).GetComponent(); SkinnedMeshRenderer component2 = ((Component)node).GetComponent(); Renderer component3 = ((Component)node).GetComponent(); if ((Object)(object)component2 != (Object)null) { skinnedRenderers++; stringBuilder.Append(" | SkinnedMeshRenderer mesh='").Append(((Object)(object)component2.sharedMesh != (Object)null) ? ((Object)component2.sharedMesh).name : "").Append("' bones=") .Append((component2.bones != null) ? component2.bones.Length : 0) .Append(" size=") .Append(Size(component2.sharedMesh)); } else if ((Object)(object)component != (Object)null) { if ((Object)(object)component3 != (Object)null) { meshRenderers++; } stringBuilder.Append(" | MeshFilter mesh='").Append(((Object)(object)component.sharedMesh != (Object)null) ? ((Object)component.sharedMesh).name : "").Append("' size=") .Append(Size(component.sharedMesh)) .Append(((Object)(object)component3 != (Object)null) ? "" : " (NO RENDERER)"); } else if ((Object)(object)component3 != (Object)null) { stringBuilder.Append(" | ").Append(((object)component3).GetType().Name); } if ((Object)(object)handsMesh != (Object)null && (Object)(object)component3 == (Object)(object)handsMesh) { stringBuilder.Append(" "); } if (stringBuilder.Length > 0) { Plugin.Log.LogInfo((object)stringBuilder.ToString()); } for (int i = 0; i < node.childCount; i++) { Walk(root, node.GetChild(i), depth + 1, inHand, outOfHand, handsMesh, ref meshRenderers, ref skinnedRenderers); } } private static string Size(Mesh mesh) { //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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mesh == (Object)null) { return "-"; } Bounds bounds = mesh.bounds; Vector3 size = ((Bounds)(ref bounds)).size; return Mathf.Max(size.x, Mathf.Max(size.y, size.z)).ToString("F3", CultureInfo.InvariantCulture); } } internal sealed class PropDef { [JsonProperty("id")] public string Id; [JsonProperty("enabled")] public bool Enabled = true; [JsonProperty("file")] public string File; [JsonProperty("bundle")] public string Bundle; [JsonProperty("bundleAsset")] public string BundleAsset; [JsonProperty("bundleAxisFix")] public bool BundleAxisFix = true; [JsonProperty("island")] public string Island; [JsonProperty("position")] public float[] Position; [JsonProperty("rotation")] public float[] Rotation; [JsonProperty("scale")] public float Scale = 1f; [JsonProperty("targetHeight")] public float? TargetHeight; [JsonProperty("restOnGround")] public bool RestOnGround = true; [JsonProperty("material")] public string Material = "model"; [JsonProperty("collider")] public bool Collider = true; [JsonProperty("credit")] public string Credit; } internal sealed class PropsFile { [JsonProperty("props")] public PropDef[] Props; } internal static class PropPlacer { private const string FileName = "props.json"; private static readonly List Defs = new List(); private static readonly Dictionary Live = new Dictionary(); private static bool _installed; private static Material _borrowed; public static IList All => Defs; public static void Install() { Load(); if (!_installed) { _installed = true; SceneManager.sceneLoaded += OnSceneLoaded; } } public static void Uninstall() { if (_installed) { _installed = false; SceneManager.sceneLoaded -= OnSceneLoaded; } } public static void Load() { Defs.Clear(); string path = Path.Combine(Plugin.WeaponsFolder, "props.json"); if (!File.Exists(path)) { return; } try { PropsFile propsFile = JsonConvert.DeserializeObject(File.ReadAllText(path)); if (propsFile == null || propsFile.Props == null) { return; } PropDef[] props = propsFile.Props; foreach (PropDef propDef in props) { if (propDef != null && !string.IsNullOrEmpty(propDef.Id)) { Defs.Add(propDef); } } Plugin.Log.LogInfo((object)("Loaded " + Defs.Count + " prop def(s) from props.json.")); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to read props.json: " + ex.Message)); } } public static PropDef Find(string id) { foreach (PropDef def in Defs) { if (string.Equals(def.Id, id, StringComparison.OrdinalIgnoreCase)) { return def; } } return null; } public static GameObject LiveObject(string id) { if (!Live.TryGetValue(id, out var value)) { return null; } return value; } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Cfg != null && Plugin.Cfg.Enabled.Value) { PlaceInScene(scene); } } public static string PlaceNow() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) int num = 0; for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); if (((Scene)(ref sceneAt)).isLoaded) { num += PlaceInScene(sceneAt); } } if (num != 0) { return "placed " + num + " prop(s)"; } return "no props belong to the island you are on"; } private static int PlaceInScene(Scene scene) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (PropDef def in Defs) { if (def.Enabled && BelongsHere(def, scene) && Build(def, scene)) { num++; } } return num; } private static bool BelongsHere(PropDef def, Scene scene) { if (!string.IsNullOrEmpty(def.Island)) { return ((Scene)(ref scene)).name.IndexOf(def.Island, StringComparison.OrdinalIgnoreCase) >= 0; } string text = IslandCatalog.SceneName(IslandCatalog.Resolve(Plugin.Cfg.ShopIslandName.Value, Plugin.Cfg.ShopIslandIndex.Value)); if (!string.IsNullOrEmpty(text)) { return string.Equals(((Scene)(ref scene)).name, text, StringComparison.OrdinalIgnoreCase); } return false; } private static bool Build(PropDef def, Scene scene) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_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_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_034b: Unknown result type (might be due to invalid IL or missing references) if (Live.TryGetValue(def.Id, out var value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } Live.Remove(def.Id); LoadedModel loadedModel; try { bool wantTextures = MaterialFactory.WantsModelTextures(def.Material); loadedModel = (string.IsNullOrEmpty(def.BundleAsset) ? ModelLibrary.Load(Path.Combine(Plugin.WeaponsFolder, def.File), wantTextures) : ModelLibrary.LoadFromBundle(Plugin.WeaponsFolder, def.Bundle, def.BundleAsset, wantTextures, def.BundleAxisFix)); } catch (Exception ex) { Plugin.Log.LogError((object)("Prop " + def.Id + ": " + ex.Message)); return false; } if (loadedModel == null || (Object)(object)loadedModel.Mesh == (Object)null) { Plugin.Log.LogError((object)("Prop " + def.Id + ": no mesh.")); return false; } Bounds bounds = loadedModel.Mesh.bounds; float num = def.Scale; if (def.TargetHeight.HasValue && ((Bounds)(ref bounds)).size.y > 0.0001f) { num = def.TargetHeight.Value / ((Bounds)(ref bounds)).size.y; Plugin.Log.LogInfo((object)("Prop " + def.Id + " target height " + def.TargetHeight.Value + " m over a baked " + ((Bounds)(ref bounds)).size.y.ToString("0.###") + " m model -> scale " + num.ToString("0.#####") + ".")); } GameObject val = new GameObject("WA_Prop_" + def.Id); SceneManager.MoveGameObjectToScene(val, scene); Vector3 val2 = Vec(def.Position); if (def.RestOnGround) { val2.y -= ((Bounds)(ref bounds)).min.y * num; } val.transform.SetPositionAndRotation(val2, Quaternion.Euler(Vec(def.Rotation))); val.transform.localScale = Vector3.one * num; val.AddComponent().sharedMesh = loadedModel.Mesh; ((Renderer)val.AddComponent()).sharedMaterials = BuildMaterials(def, loadedModel, loadedModel.Mesh.subMeshCount); if (def.Collider) { val.AddComponent().sharedMesh = loadedModel.Mesh; } Live[def.Id] = val; Plugin.Log.LogInfo((object)("Prop " + def.Id + " placed in " + ((Scene)(ref scene)).name + " at " + ((object)val.transform.position/*cast due to .constrained prefix*/).ToString() + "; baked " + ((object)((Bounds)(ref bounds)).size/*cast due to .constrained prefix*/).ToString() + " * " + num.ToString("0.#####") + " = " + ((object)(((Bounds)(ref bounds)).size * num)/*cast due to .constrained prefix*/).ToString() + " m.")); return true; } private static Material[] BuildMaterials(PropDef def, LoadedModel model, int slots) { Material vanillaMaterial = BorrowSceneryMaterial(); if (MaterialFactory.WantsModelColors(def.Material)) { return MaterialFactory.CreatePerSubmesh(vanillaMaterial, model, slots); } Material val = MaterialFactory.Create(def.Material, vanillaMaterial, model); Material[] array = (Material[])(object)new Material[Mathf.Max(1, slots)]; for (int i = 0; i < array.Length; i++) { array[i] = val; } return array; } private static Material BorrowSceneryMaterial() { if ((Object)(object)_borrowed != (Object)null) { return _borrowed; } MeshRenderer[] array = Object.FindObjectsByType((FindObjectsInactive)1); foreach (MeshRenderer val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Renderer)val).sharedMaterial == (Object)null) && !((Object)(object)((Renderer)val).sharedMaterial.shader == (Object)null)) { _borrowed = ((Renderer)val).sharedMaterial; Plugin.Log.LogInfo((object)("Props will use the shader " + ((Object)_borrowed.shader).name + " borrowed from " + ((Object)((Component)val).gameObject).name + ".")); return _borrowed; } } Plugin.Log.LogWarning((object)"No scenery MeshRenderer to borrow a shader from; props may render untextured."); return null; } private static Vector3 Vec(float[] v) { //IL_0018: 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) if (v != null && v.Length >= 3) { return new Vector3(v[0], v[1], v[2]); } return Vector3.zero; } public static string Save() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown string contents = JsonConvert.SerializeObject((object)new PropsFile { Props = Defs.ToArray() }, (Formatting)1, new JsonSerializerSettings { NullValueHandling = (NullValueHandling)1 }); int num = 0; string[] array = new string[2] { Plugin.WeaponsFolder, Plugin.Cfg.SourceWeaponsFolder.Value }; foreach (string text in array) { if (!string.IsNullOrEmpty(text) && Directory.Exists(text)) { try { File.WriteAllText(Path.Combine(text, "props.json"), contents); num++; } catch (Exception ex) { Plugin.Log.LogError((object)("Could not write props.json to " + text + ": " + ex.Message)); } } } if (num != 0) { return "saved to " + num + " location(s)"; } return "could not write props.json"; } } internal struct ReloadKey { public float T; public float AlongMag; public float Dip; public ReloadKey(float t, float alongMag, float dip) { T = t; AlongMag = alongMag; Dip = dip; } } internal sealed class ReloadAnimator { private static readonly ReloadKey[] Curve = new ReloadKey[8] { new ReloadKey(0f, 0f, 0f), new ReloadKey(0.12f, 0.35f, 0.05f), new ReloadKey(0.3f, 1f, 0.55f), new ReloadKey(0.48f, 1.15f, 1f), new ReloadKey(0.62f, 1.1f, 0.95f), new ReloadKey(0.8f, 0.45f, 0.2f), new ReloadKey(0.92f, 0f, 0f), new ReloadKey(1f, 0f, 0f) }; private readonly ReloadDef _def; private readonly Vector3 _extract; private readonly Vector3 _dip; private float _startedAt = -1f; public bool Running => _startedAt >= 0f; public ReloadAnimator(ReloadDef def, Vector3 extractDirection, Vector3 dipDirection) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) _def = def; _extract = ((Vector3)(ref extractDirection)).normalized; _dip = ((Vector3)(ref dipDirection)).normalized; } public void Begin(float now) { _startedAt = now; } public void Stop() { _startedAt = -1f; } public bool Sample(float now, out Vector3 handOffset, out Vector3 magOffset) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) handOffset = Vector3.zero; magOffset = Vector3.zero; if (_startedAt < 0f) { return false; } float num = Mathf.Max(0.2f, _def.Duration); Evaluate(Mathf.Clamp01((now - _startedAt) / num), out var along, out var dip); handOffset = _extract * (along * _def.Drop) + _dip * (dip * _def.Dip); float num2 = Mathf.Min(along, 1.15f); magOffset = _extract * (num2 * _def.Drop) + _dip * (dip * _def.Dip); return true; } private static void Evaluate(float t, out float along, out float dip) { for (int i = 0; i < Curve.Length - 1; i++) { ReloadKey reloadKey = Curve[i]; ReloadKey reloadKey2 = Curve[i + 1]; if (!(t < reloadKey.T) && !(t > reloadKey2.T)) { float num = Mathf.Max(0.0001f, reloadKey2.T - reloadKey.T); float num2 = Mathf.SmoothStep(0f, 1f, (t - reloadKey.T) / num); along = Mathf.Lerp(reloadKey.AlongMag, reloadKey2.AlongMag, num2); dip = Mathf.Lerp(reloadKey.Dip, reloadKey2.Dip, num2); return; } } along = 0f; dip = 0f; } } internal static class ShopPlacer { private static bool _installed; private static readonly List Placed = new List(); public static void Install() { if (!_installed) { _installed = true; SceneManager.sceneLoaded += OnSceneLoaded; } } public static void Uninstall() { if (_installed) { _installed = false; SceneManager.sceneLoaded -= OnSceneLoaded; } } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Cfg == null || !Plugin.Cfg.Enabled.Value || (Object)(object)Plugin.Runtime == (Object)null || Plugin.Runtime.Built.Count == 0) { return; } Placed.RemoveAll((GameObject go) => (Object)(object)go == (Object)null); if (IsShopScene(scene, log: true)) { List list = FindWeaponStands(scene); if (list.Count == 0) { Plugin.Log.LogInfo((object)("No weapon stands found in '" + ((Scene)(ref scene)).name + "'; nothing to extend.")); return; } Plugin.Log.LogInfo((object)("Found " + list.Count + " weapon stand(s) in '" + ((Scene)(ref scene)).name + "'.")); PlaceAll(list); } } private static bool IsShopScene(Scene scene, bool log) { int islandIndex = IslandCatalog.Resolve(Plugin.Cfg.ShopIslandName.Value, Plugin.Cfg.ShopIslandIndex.Value); string text = IslandCatalog.SceneName(islandIndex); if (string.IsNullOrEmpty(text)) { return false; } bool flag = string.Equals(((Scene)(ref scene)).name, text, StringComparison.OrdinalIgnoreCase); if (log) { Plugin.Log.LogInfo((object)("Scene '" + ((Scene)(ref scene)).name + "' loaded; shop island is '" + text + "' (" + islandIndex + ") -> " + (flag ? "placing stands" : "skipping"))); } return flag; } public static string PlaceNow() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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) if ((Object)(object)Plugin.Runtime == (Object)null || Plugin.Runtime.Built.Count == 0) { return "no weapons built yet"; } for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); if (((Scene)(ref sceneAt)).isLoaded && IsShopScene(sceneAt, log: false)) { List list = FindWeaponStands(sceneAt); if (list.Count == 0) { return "no weapon stands found in " + ((Scene)(ref sceneAt)).name; } ClearPlaced(); PlaceAll(list); return "placed " + Placed.Count + " stand(s) in " + ((Scene)(ref sceneAt)).name; } } return "not on the shop island right now"; } private static void ClearPlaced() { foreach (GameObject item in Placed) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } Placed.Clear(); } private static List FindWeaponStands(Scene scene) { List list = new List(); GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); for (int i = 0; i < rootGameObjects.Length; i++) { ItemPurchasable[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren(true); foreach (ItemPurchasable val in componentsInChildren) { object obj = Refl.Get(val, "_itemToPurchase"); Item val2 = (Item)((obj is Item) ? obj : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).GetComponentInChildren(true) == (Object)null)) { list.Add(val); } } } return list; } private static ItemPurchasable PickTemplate(List stands, BuiltWeapon built) { foreach (ItemPurchasable stand in stands) { object obj = Refl.Get(stand, "_itemToPurchase"); Item val = (Item)((obj is Item) ? obj : null); if (!((Object)(object)val == (Object)null) && string.Equals(((Object)((Component)val).gameObject).name, built.Def.BasePrefab, StringComparison.OrdinalIgnoreCase)) { return stand; } } return stands[stands.Count - 1]; } private static void PlaceAll(List stands) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) Vector3 val = DeriveStep(stands); ItemPurchasable val2 = stands[stands.Count - 1]; int num = 1; foreach (BuiltWeapon item in Plugin.Runtime.Built) { if (item.Def.Shop != null && item.Def.Shop.Sell && !((Object)(object)item.Weapon == (Object)null)) { ItemPurchasable val3 = PickTemplate(stands, item); GameObject val4 = Object.Instantiate(((Component)val3).gameObject, ((Component)val2).transform.parent); ((Object)val4).name = "WA_Stand_" + item.Def.Id; val4.transform.SetPositionAndRotation(((Component)val2).transform.position + val * (float)num, ((Component)val2).transform.rotation); ItemPurchasable component = val4.GetComponent(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val4); continue; } Refl.SetRaw(component, "_itemToPurchase", item.Weapon); Refl.SetRaw(component, "_customCost", item.Def.Shop.Price); int num2 = WeaponBuilder.SwapDisplayMeshes(Refl.Get(component, "_modelsToOutline") as GameObject[], item); Plugin.Log.LogInfo((object)("Stand display: swapped " + num2 + " renderer(s) from template '" + ((Object)((Component)val3).gameObject).name + "'.")); Placed.Add(val4); num++; Plugin.Log.LogInfo((object)("Placed stand for '" + item.Def.Id + "' at " + ((object)val4.transform.position/*cast due to .constrained prefix*/).ToString() + " ($" + item.Def.Shop.Price + ")")); } } } private unsafe static Vector3 DeriveStep(List stands) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (stands.Count >= 2) { Vector3 val = Vector3.zero; int num = 0; for (int i = 1; i < stands.Count; i++) { Vector3 val2 = ((Component)stands[i]).transform.position - ((Component)stands[i - 1]).transform.position; if (!(((Vector3)(ref val2)).sqrMagnitude < 0.0001f)) { val += val2; num++; } } if (num > 0) { Vector3 result = val / (float)num; Plugin.Log.LogInfo((object)("Derived stand spacing " + ((object)(*(Vector3*)(&result))/*cast due to .constrained prefix*/).ToString() + " from " + num + " gap(s).")); return result; } } Vector3 result2 = ((Component)stands[stands.Count - 1]).transform.right * Plugin.Cfg.ShopFallbackSpacing.Value; Plugin.Log.LogInfo((object)("Only one stand present; using fallback spacing " + ((object)(*(Vector3*)(&result2))/*cast due to .constrained prefix*/).ToString() + ".")); return result2; } } internal sealed class SlideDriver : MonoBehaviour { private Weapon _weapon; private Transform _slide; private Vector3 _rest; private Vector3 _travel; private float _duration = 0.07f; private Animation _anim; private bool _wasFiring; private static bool _loggedCycle; public static bool Learning; private Vector3 _learnPeak; private float _learnStarted = -1f; private float _learnPeakAt; private float _startedAt = -1f; private bool _hooked; private bool _resolved; public bool Rebuild(Weapon weapon, Transform slide, Vector3 travel, float duration) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) _weapon = weapon; _slide = slide; if ((Object)(object)_slide == (Object)null || (Object)(object)_weapon == (Object)null) { return false; } ref Animation anim = ref _anim; object obj = Refl.Get(_weapon, "_anim"); anim = (Animation)((obj is Animation) ? obj : null); _rest = _slide.localPosition; _travel = travel; _duration = Mathf.Max(0.01f, duration); return true; } private void OnEnable() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Resolve(); if (!_hooked) { Application.onBeforeRender += new UnityAction(Tick); _hooked = true; } } private void OnDisable() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown if (_hooked) { Application.onBeforeRender -= new UnityAction(Tick); _hooked = false; } } private void Resolve() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) if (_resolved) { return; } _resolved = true; ArsenalWeapon componentInChildren = ((Component)this).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null || (Object)(object)Plugin.Runtime == (Object)null) { return; } BuiltWeapon builtWeapon = Plugin.Runtime.Find(componentInChildren.WeaponId); if (builtWeapon == null || builtWeapon.Def.Slide == null) { return; } Transform val = null; Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if (((Object)val2).name == "Slide") { val = val2; break; } } Vector3 val3 = WeaponBuilder.RearwardInGunSpace(builtWeapon, val); if (!((Object)(object)val == (Object)null) && !(val3 == Vector3.zero)) { Rebuild(((Component)this).GetComponentInChildren(true), val, val3 * builtWeapon.Def.Slide.Travel, builtWeapon.Def.Slide.Time); } } private void Learn() { //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_anim != (Object)null) || (!_anim.IsPlaying("ReloadLast") && !_anim.IsPlaying("Reload"))) { if (_learnStarted < 0f) { return; } Learning = false; _learnStarted = -1f; if (((Vector3)(ref _learnPeak)).sqrMagnitude < 1E-06f) { Plugin.Log.LogWarning((object)("Slide learn: the reload clip never moved '" + ((Object)_slide).name + "'. Nothing to copy - the rack you are seeing is the hand, not this bone.")); ChatManager.ChatMessage("[WA] slide learn: the reload clip does not move the slide bone"); return; } _travel = _learnPeak; _duration = Mathf.Max(0.02f, _learnPeakAt * 2f); WeaponDef weaponDef = Def(); string text = ""; if (weaponDef != null) { if (weaponDef.Slide == null) { weaponDef.Slide = new SlideDef(); } weaponDef.Slide.Offset = new float[3] { _travel.x, _travel.y, _travel.z }; weaponDef.Slide.Time = _duration; text = " - applied; set the speed with /wa slide " + weaponDef.Id + " time , then save"; } Plugin.Log.LogInfo((object)("Slide learn: reload moves '" + ((Object)_slide).name + "' by " + ((Vector3)(ref _learnPeak)).ToString("F4") + " over " + _learnPeakAt.ToString("F3") + "s out, so a shot cycle is " + _duration.ToString("F3") + "s round trip." + ((weaponDef == null) ? " Could not reach the def to store it." : " Stored in the def."))); ChatManager.ChatMessage("[WA] slide learn: " + ((Vector3)(ref _learnPeak)).ToString("F3") + " over " + _duration.ToString("F2") + "s" + text); } else { if (_learnStarted < 0f) { _learnStarted = Time.time; _learnPeak = Vector3.zero; _learnPeakAt = 0f; } Vector3 learnPeak = _slide.localPosition - _rest; if (((Vector3)(ref learnPeak)).sqrMagnitude > ((Vector3)(ref _learnPeak)).sqrMagnitude) { _learnPeak = learnPeak; _learnPeakAt = Time.time - _learnStarted; } } } private WeaponDef Def() { ArsenalWeapon componentInChildren = ((Component)this).GetComponentInChildren(true); if (!((Object)(object)componentInChildren == (Object)null)) { return componentInChildren.Def; } return null; } public bool Captured(out Vector3 travel, out float duration) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) travel = _travel; duration = _duration; return ((Vector3)(ref _travel)).sqrMagnitude > 1E-06f; } private void Tick() { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_slide == (Object)null || (Object)(object)_weapon == (Object)null) { return; } if (Learning) { Learn(); } bool flag = (Object)(object)_anim != (Object)null && (_anim.IsPlaying("Fire") || _anim.IsPlaying("FireLast")); if (flag && !_wasFiring) { _startedAt = Time.time; if (!_loggedCycle) { _loggedCycle = true; Plugin.Log.LogInfo((object)("Slide cycled on '" + ((Object)_slide).name + "' by " + ((Vector3)(ref _travel)).ToString("F3") + ". If nothing appears to move, the model parts mapped to the Slide bone are not the charging handle - find the right part index with /wa part next and remap it in the def's partBones.")); } } _wasFiring = flag; if (!(_startedAt < 0f)) { float num = (Time.time - _startedAt) / _duration; if (num >= 1f) { _slide.localPosition = _rest; _startedAt = -1f; } else { float num2 = ((num < 0.4f) ? (num / 0.4f) : (1f - (num - 0.4f) / 0.6f)); _slide.localPosition = _rest + _travel * num2; } } } } internal sealed class ModelSwapTarget { public string Label; public string Path; public MeshFilter Filter; public SkinnedMeshRenderer Skinned; public Renderer Renderer; public Mesh OriginalMesh; public Bounds BaseBounds; public Mesh FittedMesh; public int BoneIndex = -1; public bool LoggedSkinning; public LoadedModel Model; public Dictionary PartBones; public bool IsSkinned => (Object)(object)Skinned != (Object)null; } internal sealed class BuiltWeapon { public WeaponDef Def; public GameObject Prefab; public NetworkObject NetworkObject; public Weapon Weapon; public readonly List Targets = new List(); public bool InventoryCaptured; public float VanillaInvScale; public Vector3 VanillaInvPos; public Vector3 VanillaInvRot; public int IsolatePart = -1; public LoadedModel Model; public Vector3 IkRestLeftPos; public Vector3 IkRestRightPos; public Quaternion IkRestLeftRot = Quaternion.identity; public Quaternion IkRestRightRot = Quaternion.identity; public bool HasIkRestLeft; public bool HasIkRestRight; } internal static class WeaponBuilder { private const string GunBoneName = "Gun"; private static GameObject _templateRoot; private static Transform TemplateRoot { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)_templateRoot == (Object)null) { _templateRoot = new GameObject("HowToFish.WeaponArsenal.Templates"); _templateRoot.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_templateRoot); ((Object)_templateRoot).hideFlags = (HideFlags)61; } return _templateRoot.transform; } } public static BuiltWeapon Build(WeaponDef def, string weaponsFolder) { NetworkObject val = BaseWeaponIndex.Find(def.BasePrefab); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Weapon '" + def.Id + "' wants base prefab '" + def.BasePrefab + "', which does not exist. Run /wa bases in game to list the real names.")); return null; } GameObject val2; try { val2 = Object.Instantiate(((Component)val).gameObject, TemplateRoot); } catch (Exception ex) { Plugin.Log.LogError((object)("Cloning base prefab for '" + def.Id + "' failed: " + ex)); return null; } ((Object)val2).name = "WA_" + def.Id; BuiltWeapon builtWeapon = new BuiltWeapon { Def = def, Prefab = val2, NetworkObject = val2.GetComponent(), Weapon = val2.GetComponentInChildren(true) }; if ((Object)(object)builtWeapon.NetworkObject == (Object)null) { Plugin.Log.LogError((object)("Clone for '" + def.Id + "' has no NetworkObject; discarding.")); Object.Destroy((Object)(object)val2); return null; } val2.AddComponent().WeaponId = def.Id; if (!SwapModel(builtWeapon, weaponsFolder)) { Object.Destroy((Object)(object)val2); return null; } CheckOrientation(builtWeapon); ApplyAds(builtWeapon); AnimationLibrary.Install(builtWeapon, weaponsFolder); ApplySerializedStats(builtWeapon); ApplyIk(builtWeapon); ApplyPose(builtWeapon); ApplySlide(builtWeapon); Plugin.Log.LogInfo((object)("Built weapon '" + def.Id + "' from base '" + def.BasePrefab + "' with " + builtWeapon.Targets.Count + " model slot(s).")); return builtWeapon; } private static LoadedModel LoadModel(WeaponDef def, string weaponsFolder, bool wantTextures) { if (!string.IsNullOrEmpty(def.Model.BundleAsset)) { return ModelLibrary.LoadFromBundle(weaponsFolder, def.Bundle, def.Model.BundleAsset, wantTextures, def.Model.BundleAxisFix); } return ModelLibrary.Load(Path.Combine(weaponsFolder, def.Model.File), wantTextures); } private static bool SwapModel(BuiltWeapon built, string weaponsFolder) { WeaponDef def = built.Def; bool wantTextures = string.Equals(def.Model.Material, "model", StringComparison.OrdinalIgnoreCase); try { built.Model = LoadModel(def, weaponsFolder, wantTextures); } catch (Exception ex) { Plugin.Log.LogError((object)("Loading model for '" + def.Id + "' failed: " + ex.Message)); return false; } def.ResolvedCredit = ((!string.IsNullOrEmpty(def.Credit)) ? def.Credit : built.Model.Credit); CollectTargets(built); if (built.Targets.Count == 0) { Plugin.Log.LogError((object)("No suitable renderer to replace on base prefab '" + def.BasePrefab + "'.")); return false; } Refit(built); ApplyMaterials(built); if (def.Model.HideBaseAttachments) { HideBaseAttachments(built); } return true; } private static void CollectTargets(BuiltWeapon built) { //IL_0126: Unknown result type (might be due to invalid IL or missing references) built.Targets.Clear(); Weapon weapon = built.Weapon; Renderer handsMesh = Refl.GetAs(weapon, "_handsMesh"); HashSet claimed = new HashSet(); AddFromList(built, Refl.Get(weapon, "_renderers") as List, "renderer", handsMesh, claimed); AddFromList(built, Refl.Get(weapon, "_skinRenderers") as List, "skin", handsMesh, claimed); if (built.Targets.Count == 0) { Plugin.Log.LogWarning((object)"Item declares no renderers; falling back to the largest active one."); AddLargestActive(built, handsMesh, claimed); } foreach (ModelSwapTarget target in built.Targets) { Plugin.Log.LogInfo((object)(" model slot [" + target.Label + "] " + (string.IsNullOrEmpty(target.Path) ? "" : target.Path) + " mesh='" + ((Object)target.OriginalMesh).name + "' type=" + ((object)target.Renderer).GetType().Name + " size=" + Longest(((Bounds)(ref target.BaseBounds)).size).ToString("F3", CultureInfo.InvariantCulture))); } } private static void AddFromList(BuiltWeapon built, List renderers, string label, Renderer handsMesh, HashSet claimed) { if (renderers == null) { return; } foreach (Renderer renderer in renderers) { if (!((Object)(object)renderer == (Object)null) && !((Object)(object)renderer == (Object)(object)handsMesh) && claimed.Add(renderer)) { ModelSwapTarget modelSwapTarget = MakeTarget(built, renderer, label); if (modelSwapTarget != null) { built.Targets.Add(modelSwapTarget); } } } } private static void AddLargestActive(BuiltWeapon built, Renderer handsMesh, HashSet claimed) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) Renderer val = null; float num = -1f; Renderer[] componentsInChildren = built.Prefab.GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)(object)handsMesh || claimed.Contains(val2) || !((Component)val2).gameObject.activeSelf) { continue; } Mesh val3 = MeshOf(val2); if (!((Object)(object)val3 == (Object)null)) { Bounds bounds = val3.bounds; float num2 = Longest(((Bounds)(ref bounds)).size); if (num2 > num) { num = num2; val = val2; } } } if (!((Object)(object)val == (Object)null)) { claimed.Add(val); ModelSwapTarget modelSwapTarget = MakeTarget(built, val, "largest"); if (modelSwapTarget != null) { built.Targets.Add(modelSwapTarget); } } } private static ModelSwapTarget MakeTarget(BuiltWeapon built, Renderer renderer, string label) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) Mesh val = MeshOf(renderer); if ((Object)(object)val == (Object)null) { return null; } SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); return new ModelSwapTarget { Label = label, Path = RelativePath(built.Prefab.transform, ((Component)renderer).transform), Filter = (((Object)(object)val2 == (Object)null) ? ((Component)renderer).GetComponent() : null), Skinned = val2, Renderer = renderer, OriginalMesh = val, BaseBounds = val.bounds, BoneIndex = (((Object)(object)val2 != (Object)null) ? ChooseBoneIndex(val2) : (-1)) }; } private static Mesh MeshOf(Renderer renderer) { SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if ((Object)(object)val != (Object)null) { return val.sharedMesh; } MeshFilter component = ((Component)renderer).GetComponent(); if (!((Object)(object)component != (Object)null)) { return null; } return component.sharedMesh; } private static int ChooseBoneIndex(SkinnedMeshRenderer skinned) { Transform[] bones = skinned.bones; if (bones == null || bones.Length == 0) { return -1; } for (int i = 0; i < bones.Length; i++) { if ((Object)(object)bones[i] != (Object)null && string.Equals(((Object)bones[i]).name, "Gun", StringComparison.OrdinalIgnoreCase)) { return i; } } if ((Object)(object)skinned.rootBone != (Object)null) { for (int j = 0; j < bones.Length; j++) { if ((Object)(object)bones[j] == (Object)(object)skinned.rootBone) { return j; } } } return 0; } public static void Refit(BuiltWeapon built) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) if (built == null || built.Model == null) { return; } ModelDef model = built.Def.Model; Vector3 positionOffset = ToVector(model.Position); Vector3 eulerOffset = ToVector(model.Rotation); foreach (ModelSwapTarget target in built.Targets) { Mesh fittedMesh = target.FittedMesh; Mesh val = MeshFitter.Bake(built.Model.Mesh, target.BaseBounds, model.FitToBase, model.Scale, positionOffset, eulerOffset); ((Object)val).name = "WA_" + built.Def.Id + "_" + target.Label; ManualLogSource log = Plugin.Log; string[] obj = new string[20] { "Fit [", target.Label, "] rot=", ((Vector3)(ref eulerOffset)).ToString("F1"), " pos=", ((Vector3)(ref positionOffset)).ToString("F2"), " scale=", model.Scale.ToString("F3"), " fitToBase=", model.FitToBase.ToString(), " | source ", null, null, null, null, null, null, null, null, null }; Bounds bounds = built.Model.Mesh.bounds; Vector3 val2 = ((Bounds)(ref bounds)).size; obj[11] = ((Vector3)(ref val2)).ToString("F2"); obj[12] = " -> baked center="; bounds = val.bounds; val2 = ((Bounds)(ref bounds)).center; obj[13] = ((Vector3)(ref val2)).ToString("F2"); obj[14] = " size="; bounds = val.bounds; val2 = ((Bounds)(ref bounds)).size; obj[15] = ((Vector3)(ref val2)).ToString("F2"); obj[16] = " | base center="; val2 = ((Bounds)(ref target.BaseBounds)).center; obj[17] = ((Vector3)(ref val2)).ToString("F2"); obj[18] = " size="; val2 = ((Bounds)(ref target.BaseBounds)).size; obj[19] = ((Vector3)(ref val2)).ToString("F2"); log.LogInfo((object)string.Concat(obj)); if (built.IsolatePart >= 0) { IsolateGroup(val, built.Model.GroupIds, built.IsolatePart); } if (target.IsSkinned) { target.Model = built.Model; target.PartBones = built.Def.Model.PartBones; BindSkin(val, target, built.Def.Model.Skinning); target.Skinned.sharedMesh = val; ((Renderer)target.Skinned).localBounds = val.bounds; } else if ((Object)(object)target.Filter != (Object)null) { target.Filter.sharedMesh = val; } target.FittedMesh = val; if ((Object)(object)fittedMesh != (Object)null) { Object.Destroy((Object)(object)fittedMesh); } } if (built.Targets.Count > 0) { Refl.SetRaw(built.Weapon, "_mesh", built.Targets[0].FittedMesh); ApplyInventoryPose(built, built.Targets[0]); } } public unsafe static void ApplyInventoryPose(BuiltWeapon built, ModelSwapTarget target) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_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_0103: 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_0130: 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_0137: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) Weapon weapon = built.Weapon; if ((Object)(object)weapon == (Object)null || target == null || (Object)(object)target.OriginalMesh == (Object)null || (Object)(object)target.FittedMesh == (Object)null) { return; } InventoryDef inventory = built.Def.Inventory; object obj = Refl.Get(weapon, "_inventoryMeshScale"); object obj2 = Refl.Get(weapon, "_inventoryMeshPos"); object obj3 = Refl.Get(weapon, "_inventoryMeshRot"); if (!(obj is float) || !(obj2 is Vector3) || !(obj3 is Vector3)) { return; } if (!built.InventoryCaptured) { built.VanillaInvScale = (float)obj; built.VanillaInvPos = (Vector3)obj2; built.VanillaInvRot = (Vector3)obj3; built.InventoryCaptured = true; } float vanillaInvScale = built.VanillaInvScale; Vector3 vanillaInvPos = built.VanillaInvPos; Vector3 vanillaInvRot = built.VanillaInvRot; if (inventory == null || inventory.Auto) { Bounds bounds = target.OriginalMesh.bounds; Bounds bounds2 = target.FittedMesh.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float magnitude = ((Vector3)(ref size)).magnitude; size = ((Bounds)(ref bounds2)).size; float magnitude2 = ((Vector3)(ref size)).magnitude; if (magnitude2 <= 0.0001f || magnitude <= 0.0001f) { return; } float num = vanillaInvScale * (magnitude / magnitude2); Quaternion val = Quaternion.Euler(vanillaInvRot); Vector3 val2 = vanillaInvPos + val * (((Bounds)(ref bounds)).center * vanillaInvScale - ((Bounds)(ref bounds2)).center * num); Refl.SetRaw(weapon, "_inventoryMeshScale", num); Refl.SetRaw(weapon, "_inventoryMeshPos", val2); Plugin.Log.LogInfo((object)("Inventory pose for '" + built.Def.Id + "': scale " + vanillaInvScale.ToString("0.###") + " -> " + num.ToString("0.###") + ", pos " + ((object)(*(Vector3*)(&vanillaInvPos))/*cast due to .constrained prefix*/).ToString() + " -> " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString())); } if (inventory != null) { if (inventory.Scale.HasValue) { Refl.SetRaw(weapon, "_inventoryMeshScale", inventory.Scale.Value); } if (inventory.Pos != null && inventory.Pos.Length >= 3) { Refl.SetRaw(weapon, "_inventoryMeshPos", ToVector(inventory.Pos)); } if (inventory.Rot != null && inventory.Rot.Length >= 3) { Refl.SetRaw(weapon, "_inventoryMeshRot", ToVector(inventory.Rot)); } } } private static void IsolateGroup(Mesh mesh, int[] groupIds, int group) { if (groupIds == null || groupIds.Length != mesh.vertexCount) { return; } for (int i = 0; i < mesh.subMeshCount; i++) { int[] triangles = mesh.GetTriangles(i); List list = new List(triangles.Length); for (int j = 0; j + 2 < triangles.Length; j += 3) { if (groupIds[triangles[j]] == group && groupIds[triangles[j + 1]] == group && groupIds[triangles[j + 2]] == group) { list.Add(triangles[j]); list.Add(triangles[j + 1]); list.Add(triangles[j + 2]); } } mesh.SetTriangles(list, i, false); } mesh.RecalculateBounds(); } private static void BindSkin(Mesh mesh, ModelSwapTarget target, string mode) { bool flag = !target.LoggedSkinning; target.LoggedSkinning = true; if (string.Equals(mode, "rigid", StringComparison.OrdinalIgnoreCase)) { BindRigidly(mesh, target); return; } bool flag2 = string.Equals(mode, "parts", StringComparison.OrdinalIgnoreCase); bool flag3 = string.Equals(mode, "bones", StringComparison.OrdinalIgnoreCase); if (flag2 && target.Model != null && SkinTransfer.ApplyPartBinding(mesh, target.Model.GroupIds, target.OriginalMesh, target.Skinned, "Gun", target.PartBones)) { return; } bool flag4 = !flag3 && !flag2; if (flag4 && SkinTransfer.ApplyTransfer(mesh, target.OriginalMesh)) { if (flag) { Plugin.Log.LogInfo((object)("Skin weights transferred from '" + ((Object)target.OriginalMesh).name + "'.")); } return; } if (flag && flag4) { Plugin.Log.LogInfo((object)("Weight transfer unavailable (" + SkinTransfer.Explain(target.OriginalMesh) + "); trying bone proximity.")); } if (!SkinTransfer.ApplyBoneProximity(mesh, target.OriginalMesh, target.Skinned, "Gun")) { if (flag) { Plugin.Log.LogWarning((object)"Bone proximity unavailable too; binding rigidly - the weapon moves as one piece."); } BindRigidly(mesh, target); } } private static void BindRigidly(Mesh mesh, ModelSwapTarget target) { Matrix4x4[] bindposes = target.OriginalMesh.bindposes; if (bindposes == null || bindposes.Length == 0 || target.BoneIndex < 0) { Plugin.Log.LogWarning((object)("Cannot rig '" + ((Object)mesh).name + "': the original mesh has no bindposes.")); return; } int boneIndex = Mathf.Clamp(target.BoneIndex, 0, bindposes.Length - 1); BoneWeight[] array = (BoneWeight[])(object)new BoneWeight[mesh.vertexCount]; for (int i = 0; i < array.Length; i++) { ((BoneWeight)(ref array[i])).boneIndex0 = boneIndex; ((BoneWeight)(ref array[i])).weight0 = 1f; } mesh.boneWeights = array; mesh.bindposes = bindposes; } public static int SwapDisplayMeshes(GameObject[] models, BuiltWeapon built) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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) if (models == null || built == null || built.Model == null) { return 0; } ModelDef model = built.Def.Model; Vector3 positionOffset = ToVector(model.Position); Vector3 eulerOffset = ToVector(model.Rotation); int num = 0; foreach (GameObject val in models) { if ((Object)(object)val == (Object)null) { continue; } Renderer[] componentsInChildren = val.GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { Mesh val3 = MeshOf(val2); if ((Object)(object)val3 == (Object)null) { continue; } Mesh val4 = MeshFitter.Bake(built.Model.Mesh, val3.bounds, model.FitToBase, model.Scale, positionOffset, eulerOffset); ((Object)val4).name = "WA_" + built.Def.Id + "_display"; SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null); if ((Object)(object)val5 != (Object)null) { ModelSwapTarget target = new ModelSwapTarget { OriginalMesh = val3, Skinned = val5, Model = built.Model, PartBones = built.Def.Model.PartBones, BoneIndex = ChooseBoneIndex(val5) }; BindSkin(val4, target, model.Skinning); val5.sharedMesh = val4; ((Renderer)val5).localBounds = val4.bounds; } else { MeshFilter component = ((Component)val2).GetComponent(); if ((Object)(object)component == (Object)null) { continue; } component.sharedMesh = val4; } if (built.Targets.Count > 0 && (Object)(object)built.Targets[0].Renderer != (Object)null) { val2.sharedMaterials = built.Targets[0].Renderer.sharedMaterials; } num++; } } return num; } public static bool SwitchMaterial(BuiltWeapon built, string mode, string weaponsFolder) { if (built == null) { return false; } built.Def.Model.Material = mode; try { built.Model = LoadModel(built.Def, weaponsFolder, MaterialFactory.WantsModelTextures(mode)); } catch (Exception ex) { Plugin.Log.LogError((object)("Reloading model for '" + built.Def.Id + "' failed: " + ex.Message)); return false; } Refit(built); ApplyMaterials(built); SyncLiveInstances(built); return true; } private static void DetachFromSkinSystem(BuiltWeapon built) { if (!(Refl.Get(built.Weapon, "_skinRenderers") is List list)) { return; } int num = 0; foreach (ModelSwapTarget target in built.Targets) { if ((Object)(object)target.Renderer != (Object)null && list.Remove(target.Renderer)) { num++; } } if (num > 0) { Plugin.Log.LogInfo((object)("Removed " + num + " renderer(s) from the item skin system; a model-textured weapon does not use the game skin shader.")); } } public static Transform FindIkTarget(BuiltWeapon built, bool left) { string text = (left ? "l_IK" : "r_IK"); Transform[] componentsInChildren = built.Prefab.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == text) { return val; } } return null; } public static void ApplyIk(BuiltWeapon built) { IkDef ik = built.Def.Ik; if (ik == null) { return; } CaptureIkRest(built); ApplyIkSide(built, left: true, ik.Left); ApplyIkSide(built, left: false, ik.Right); InstallHandDriver(built.Prefab, built); ArsenalWeapon[] array = Resources.FindObjectsOfTypeAll(); foreach (ArsenalWeapon arsenalWeapon in array) { if (!((Object)(object)arsenalWeapon == (Object)null) && string.Equals(arsenalWeapon.WeaponId, built.Def.Id, StringComparison.OrdinalIgnoreCase)) { InstallHandDriver(((Component)arsenalWeapon).gameObject, built); } } } public static void CheckOrientation(BuiltWeapon built) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) foreach (ModelSwapTarget target in built.Targets) { if (!((Object)(object)target.OriginalMesh == (Object)null) && !((Object)(object)target.FittedMesh == (Object)null)) { int num = LongestAxisIndex(((Bounds)(ref target.BaseBounds)).size); float num2 = CentroidBias(target.OriginalMesh, num); float num3 = CentroidBias(target.FittedMesh, num); string text = num switch { 1 => "Y", 0 => "X", _ => "Z", }; bool flag = num2 * num3 < 0f && Mathf.Abs(num2) > 0.01f && Mathf.Abs(num3) > 0.01f; Plugin.Log.LogInfo((object)("Orientation check on '" + built.Def.Id + "' [" + target.Label + "]: mass bias along " + text + " is " + F(num2) + " for the base and " + F(num3) + " for the model -> " + (flag ? ("REVERSED, run /wa fit " + built.Def.Id + " reverse") : "same way round"))); } } } private static int LongestAxisIndex(Vector3 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (size.x >= size.y && size.x >= size.z) { return 0; } if (!(size.y >= size.z)) { return 2; } return 1; } private static float CentroidBias(Mesh mesh, int axis) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) Vector3[] vertices = mesh.vertices; if (vertices.Length == 0) { return 0f; } double num = 0.0; Vector3[] array = vertices; for (int i = 0; i < array.Length; i++) { Vector3 val = array[i]; num += (double)((Vector3)(ref val))[axis]; } float num2 = (float)(num / (double)vertices.Length); Bounds bounds = mesh.bounds; Vector3 val2 = ((Bounds)(ref bounds)).extents; float num3 = ((Vector3)(ref val2))[axis]; if (!(num3 < 0.0001f)) { bounds = mesh.bounds; val2 = ((Bounds)(ref bounds)).center; return (num2 - ((Vector3)(ref val2))[axis]) / num3; } return 0f; } private static string F(float value) { return value.ToString("F3", CultureInfo.InvariantCulture); } private static void CaptureIkRest(BuiltWeapon built) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!built.HasIkRestLeft && !built.HasIkRestRight) { Transform val = FindIkTarget(built, left: true); if ((Object)(object)val != (Object)null) { built.IkRestLeftPos = val.localPosition; built.IkRestLeftRot = val.localRotation; built.HasIkRestLeft = true; } Transform val2 = FindIkTarget(built, left: false); if ((Object)(object)val2 != (Object)null) { built.IkRestRightPos = val2.localPosition; built.IkRestRightRot = val2.localRotation; built.HasIkRestRight = true; } } } private static void InstallHandDriver(GameObject root, BuiltWeapon built) { if (!((Object)(object)root == (Object)null)) { HandDriver handDriver = root.GetComponent(); if ((Object)(object)handDriver == (Object)null) { handDriver = root.AddComponent(); } handDriver.Rebuild(built); Plugin.Log.LogInfo((object)("HandDriver installed on '" + ((Object)root).name + "' for '" + built.Def.Id + "' (active=" + root.activeInHierarchy + ")")); } } private unsafe static void ApplyIkSide(BuiltWeapon built, bool left, float[] value) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if (value != null && value.Length >= 3) { Transform val = FindIkTarget(built, left); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("No " + (left ? "l_IK" : "r_IK") + " target on '" + built.Def.Id + "'; hand position left alone.")); return; } Vector3 localPosition = default(Vector3); ((Vector3)(ref localPosition))..ctor(value[0], value[1], value[2]); Plugin.Log.LogInfo((object)(" " + (left ? "l_IK" : "r_IK") + " moved from " + ((object)val.localPosition/*cast due to .constrained prefix*/).ToString() + " to " + ((object)(*(Vector3*)(&localPosition))/*cast due to .constrained prefix*/).ToString() + " on '" + built.Def.Id + "'.")); val.localPosition = localPosition; } } public static void ApplyPose(BuiltWeapon built) { ApplyPoseTo(built.Prefab, built); ArsenalWeapon[] array = Resources.FindObjectsOfTypeAll(); foreach (ArsenalWeapon arsenalWeapon in array) { if (!((Object)(object)arsenalWeapon == (Object)null) && string.Equals(arsenalWeapon.WeaponId, built.Def.Id, StringComparison.OrdinalIgnoreCase)) { ApplyPoseTo(((Component)arsenalWeapon).gameObject, built); } } } private static void ApplyPoseTo(GameObject root, BuiltWeapon built) { if (!((Object)(object)root == (Object)null)) { PoseDriver poseDriver = root.GetComponent(); if ((Object)(object)poseDriver == (Object)null) { poseDriver = root.AddComponent(); } poseDriver.Rebuild(built.Def.Pose); } } public static List BoneNames(BuiltWeapon built) { List list = new List(); Transform[] componentsInChildren = built.Prefab.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (!list.Contains(((Object)val).name)) { list.Add(((Object)val).name); } } list.Sort(StringComparer.Ordinal); return list; } public static Vector3 CurrentLocalEuler(BuiltWeapon built, string boneName) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Transform[] componentsInChildren = built.Prefab.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == boneName) { Quaternion localRotation = val.localRotation; return ((Quaternion)(ref localRotation)).eulerAngles; } } return Vector3.zero; } public static void SyncIkOnLiveInstances(BuiltWeapon built) { if (built.Def.Ik == null) { return; } ArsenalWeapon[] array = Resources.FindObjectsOfTypeAll(); foreach (ArsenalWeapon arsenalWeapon in array) { if (!((Object)(object)arsenalWeapon == (Object)null) && string.Equals(arsenalWeapon.WeaponId, built.Def.Id, StringComparison.OrdinalIgnoreCase)) { HandDriver handDriver = ((Component)arsenalWeapon).GetComponentInParent(); if ((Object)(object)handDriver == (Object)null) { handDriver = ((Component)arsenalWeapon).GetComponentInChildren(true); } if ((Object)(object)handDriver != (Object)null) { handDriver.Rebuild(built); } } } } public static void ApplyAds(BuiltWeapon built) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) float[] ads = built.Def.Ads; if (ads == null || ads.Length < 3) { return; } Vector3 pos = default(Vector3); ((Vector3)(ref pos))..ctor(ads[0], ads[1], ads[2]); int num = Write(Sights(built), pos); int num2 = 0; ArsenalWeapon[] array = Resources.FindObjectsOfTypeAll(); foreach (ArsenalWeapon arsenalWeapon in array) { if (!((Object)(object)arsenalWeapon == (Object)null) && string.Equals(arsenalWeapon.WeaponId, built.Def.Id, StringComparison.OrdinalIgnoreCase)) { Weapon componentInChildren = ((Component)arsenalWeapon).GetComponentInChildren(true); if (!((Object)(object)componentInChildren == (Object)null) && !((Object)(object)componentInChildren.Attachments == (Object)null) && !((Object)(object)componentInChildren == (Object)(object)built.Weapon)) { num2 += Write(SightArray(Refl.Get(componentInChildren.Attachments, "_sights")), pos); } } } if (num + num2 > 0) { Plugin.Log.LogInfo((object)("ADS position " + ((Vector3)(ref pos)).ToString("F3") + " set on " + num + " template sight(s) and " + num2 + " live one(s) of " + built.Def.Id + ".")); } else { Plugin.Log.LogWarning((object)("ADS position could not be written for " + built.Def.Id + " - no Sight components found.")); } } private static int Write(object[] sights, Vector3 pos) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (sights == null) { return 0; } int num = 0; foreach (object obj in sights) { if (obj != null && Refl.SetRaw(obj, "_adsPos", pos)) { num++; } } return num; } public static object[] Sights(BuiltWeapon built) { if ((Object)(object)built.Weapon == (Object)null || (Object)(object)built.Weapon.Attachments == (Object)null) { return null; } return (Refl.Get(built.Weapon.Attachments, "_sights") as object[]) ?? SightArray(Refl.Get(built.Weapon.Attachments, "_sights")); } private static object[] SightArray(object raw) { if (!(raw is IEnumerable enumerable)) { return null; } List list = new List(); foreach (object item in enumerable) { list.Add(item); } return list.ToArray(); } public static Vector3 CurrentAds(BuiltWeapon built) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) object[] array = Sights(built); if (array == null) { return Vector3.zero; } object[] array2 = array; foreach (object obj in array2) { if (obj != null) { object obj2 = Refl.Get(obj, "_adsPos"); if (obj2 is Vector3) { return (Vector3)obj2; } } } return Vector3.zero; } public static void ApplySlide(BuiltWeapon built) { if (built.Def.Slide == null) { return; } InstallSlideDriver(built.Prefab, built); ArsenalWeapon[] array = Resources.FindObjectsOfTypeAll(); foreach (ArsenalWeapon arsenalWeapon in array) { if (!((Object)(object)arsenalWeapon == (Object)null) && string.Equals(arsenalWeapon.WeaponId, built.Def.Id, StringComparison.OrdinalIgnoreCase)) { InstallSlideDriver(((Component)arsenalWeapon).gameObject, built); } } } private static void InstallSlideDriver(GameObject root, BuiltWeapon built) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null) { return; } Transform val = null; Transform[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if (((Object)val2).name == "Slide") { val = val2; break; } } if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("No 'Slide' bone on '" + built.Def.Id + "'; slide travel skipped.")); return; } SlideDef slide = built.Def.Slide; Vector3 travel = default(Vector3); if (slide.Offset != null && slide.Offset.Length >= 3) { ((Vector3)(ref travel))..ctor(slide.Offset[0], slide.Offset[1], slide.Offset[2]); } else { Vector3 val3 = RearwardInGunSpace(built, val); if (val3 == Vector3.zero) { return; } travel = val3 * slide.Travel; } Weapon componentInChildren = root.GetComponentInChildren(true); SlideDriver slideDriver = root.GetComponent(); if ((Object)(object)slideDriver == (Object)null) { slideDriver = root.AddComponent(); } if (slideDriver.Rebuild(componentInChildren, val, travel, slide.Time)) { Plugin.Log.LogInfo((object)("Slide travel on '" + built.Def.Id + "': " + ((Vector3)(ref travel)).ToString("F4") + " over " + slide.Time + "s" + ((slide.Offset != null) ? " (measured)" : " (derived from the fire point)") + ".")); } } public static Vector3 RearwardInGunSpace(BuiltWeapon built, Transform slide) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)slide == (Object)null || (Object)(object)slide.parent == (Object)null) { return Vector3.zero; } Vector3 val = MuzzleForward(built); if (val == Vector3.zero) { return Vector3.zero; } Vector3 val2 = slide.parent.InverseTransformDirection(-val); return ((Vector3)(ref val2)).normalized; } public static Vector3 MuzzleForward(BuiltWeapon built) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) Weapon weapon = built.Weapon; if ((Object)(object)weapon != (Object)null && (Object)(object)weapon.Attachments != (Object)null) { Transform firePoint = weapon.Attachments.FirePoint; if ((Object)(object)firePoint != (Object)null) { return firePoint.forward; } } if (built.Targets.Count == 0) { return Vector3.zero; } ModelSwapTarget modelSwapTarget = built.Targets[0]; if ((Object)(object)modelSwapTarget.Renderer == (Object)null) { return Vector3.zero; } Vector3 size = ((Bounds)(ref modelSwapTarget.BaseBounds)).size; Vector3 val = ((size.x >= size.y && size.x >= size.z) ? Vector3.right : ((size.y >= size.z) ? Vector3.up : Vector3.forward)); return ((Component)modelSwapTarget.Renderer).transform.TransformDirection(val); } private static void HideBaseAttachments(BuiltWeapon built) { HashSet hashSet = new HashSet(); foreach (ModelSwapTarget target in built.Targets) { if ((Object)(object)target.Renderer != (Object)null) { hashSet.Add(target.Renderer); } } SkinnedMeshRenderer[] componentsInChildren = built.Prefab.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer item in componentsInChildren) { hashSet.Add((Renderer)(object)item); } int num = 0; MeshRenderer[] componentsInChildren2 = built.Prefab.GetComponentsInChildren(true); foreach (MeshRenderer val in componentsInChildren2) { if (!((Object)(object)val == (Object)null) && !hashSet.Contains((Renderer)(object)val) && ((Renderer)val).enabled) { ((Renderer)val).enabled = false; num++; Plugin.Log.LogInfo((object)(" hid base attachment renderer '" + ((Object)((Component)val).gameObject).name + "'.")); } } Plugin.Log.LogInfo((object)("Hid " + num + " base attachment renderer(s) on '" + built.Def.Id + "'; their GameObjects and transforms are untouched.")); } private static void ApplyMaterials(BuiltWeapon built) { if (MaterialFactory.WantsModelTextures(built.Def.Model.Material)) { DetachFromSkinSystem(built); } if (MaterialFactory.WantsModelColors(built.Def.Model.Material)) { DetachFromSkinSystem(built); { foreach (ModelSwapTarget target in built.Targets) { if (!((Object)(object)target.Renderer == (Object)null)) { int slots = Mathf.Max(1, target.FittedMesh.subMeshCount); Material[] array = MaterialFactory.CreatePerSubmesh(target.Renderer.sharedMaterial, built.Model, slots); if (array != null) { target.Renderer.sharedMaterials = array; } } } return; } } foreach (ModelSwapTarget target2 in built.Targets) { if ((Object)(object)target2.Renderer == (Object)null) { continue; } Material val = MaterialFactory.Create(built.Def.Model.Material, target2.Renderer.sharedMaterial, built.Model); if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)target2.Renderer.sharedMaterial)) { int num = Mathf.Max(1, target2.FittedMesh.subMeshCount); Material[] array2 = (Material[])(object)new Material[num]; for (int i = 0; i < num; i++) { array2[i] = val; } target2.Renderer.sharedMaterials = array2; } } } public static void SyncLiveInstances(BuiltWeapon built) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if (built == null || built.Targets.Count == 0) { return; } int num = 0; ArsenalWeapon[] array = Resources.FindObjectsOfTypeAll(); foreach (ArsenalWeapon arsenalWeapon in array) { if ((Object)(object)arsenalWeapon == (Object)null || !string.Equals(arsenalWeapon.WeaponId, built.Def.Id, StringComparison.OrdinalIgnoreCase)) { continue; } foreach (ModelSwapTarget target in built.Targets) { Transform val = (string.IsNullOrEmpty(target.Path) ? ((Component)arsenalWeapon).transform : ((Component)arsenalWeapon).transform.Find(target.Path)); if ((Object)(object)val == (Object)null) { continue; } Renderer component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)target.Renderer != (Object)null) { component.sharedMaterials = target.Renderer.sharedMaterials; } SkinnedMeshRenderer component2 = ((Component)val).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.sharedMesh = target.FittedMesh; ((Renderer)component2).localBounds = target.FittedMesh.bounds; num++; continue; } MeshFilter component3 = ((Component)val).GetComponent(); if ((Object)(object)component3 != (Object)null) { component3.sharedMesh = target.FittedMesh; num++; } } } if (Plugin.Cfg != null && Plugin.Cfg.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Refit pushed to " + num + " slot(s) of " + built.Def.Id + ".")); } } private static void LogBaseline(BuiltWeapon built, object weapon, string field, T? value) where T : struct { if (value.HasValue && Plugin.Cfg != null && Plugin.Cfg.VerboseLogging.Value) { object obj = Refl.Get(weapon, field); if (obj != null) { Plugin.Log.LogInfo((object)(" " + built.Def.Id + " " + field + ": " + obj?.ToString() + " -> " + value.Value)); } } } private static void ApplySerializedStats(BuiltWeapon built) { StatsDef stats = built.Def.Stats; if (stats == null || (Object)(object)built.Weapon == (Object)null) { return; } Weapon weapon = built.Weapon; LogBaseline(built, weapon, "_timeBetweenShots", stats.TimeBetweenShots); LogBaseline(built, weapon, "_spread", stats.Spread); LogBaseline(built, weapon, "_projSpeed", stats.ProjectileSpeed); LogBaseline(built, weapon, "_recoilKnockback", stats.RecoilKnockback); Refl.Set(weapon, "_fullAuto", stats.FullAuto); Refl.Set(weapon, "_noQueueingShots", stats.NoQueueingShots); Refl.Set(weapon, "_noShootingDuringShootAnim", stats.NoShootingDuringShootAnim); Refl.Set(weapon, "_canAds", stats.CanAds); Refl.Set(weapon, "_timeBetweenShots", stats.TimeBetweenShots); Refl.Set(weapon, "_spread", stats.Spread); Refl.Set(weapon, "_projectileCountPerShot", stats.ProjectileCountPerShot); Refl.Set(weapon, "_projSpeed", stats.ProjectileSpeed); Refl.Set(weapon, "_recoilKnockback", stats.RecoilKnockback); object obj = Refl.Get(weapon, "_attachments"); Attachments val = (Attachments)((obj is Attachments) ? obj : null); if ((Object)(object)val == (Object)null) { val = built.Prefab.GetComponentInChildren(true); } if ((Object)(object)val != (Object)null) { Refl.Set(val, "_defaultAmmoPerMag", stats.AmmoPerMag); Refl.Set(val, "_extendedAmmoPerMag", stats.ExtendedAmmoPerMag); if (stats.Damage.HasValue) { ApplyDamage(val, stats.Damage.Value); } if (built.Def.Attachments != null && built.Def.Attachments.BulletUpgradeCostMultiplier.HasValue) { ScaleBulletCosts(val, built.Def.Attachments.BulletUpgradeCostMultiplier.Value); } } object obj2 = Refl.Get(weapon, "_weaponInfo"); if (obj2 != null) { if (stats.Damage.HasValue) { Refl.SetProperty(obj2, "ProjectileDamage", stats.Damage.Value); } if (stats.ProjectileForce.HasValue) { Refl.SetProperty(obj2, "ProjectileForce", stats.ProjectileForce.Value); } if (stats.ProjectileGravity.HasValue) { Refl.SetProperty(obj2, "ProjectileGravity", stats.ProjectileGravity.Value); } } ApplyRecoil(built); ApplySound(built); } private static void ApplyRecoil(BuiltWeapon built) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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_01bf: Unknown result type (might be due to invalid IL or missing references) RecoilDef recoil = built.Def.Recoil; if (recoil == null || (Object)(object)built.Prefab == (Object)null) { return; } BarrelAttachment[] componentsInChildren = built.Prefab.GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { Plugin.Log.LogWarning((object)("No BarrelAttachment on '" + built.Def.Id + "'; recoil not applied.")); return; } bool flag = Plugin.Cfg != null && Plugin.Cfg.VerboseLogging.Value; BarrelAttachment[] array = componentsInChildren; foreach (BarrelAttachment val in array) { if ((Object)(object)val == (Object)null) { continue; } if (recoil.ScreenMultiplier.HasValue) { object obj = Refl.Get(val, "_screenRecoilAmount"); if (obj is Vector2) { Refl.SetRaw(val, "_screenRecoilAmount", (Vector2)obj * recoil.ScreenMultiplier.Value); } } if (recoil.ModelMultiplier.HasValue) { float value = recoil.ModelMultiplier.Value; object obj2 = Refl.Get(val, "_modelRecoilPos"); if (obj2 is Vector3) { Refl.SetRaw(val, "_modelRecoilPos", (Vector3)obj2 * value); } object obj3 = Refl.Get(val, "_modelRecoilRot"); if (obj3 is Vector2) { Refl.SetRaw(val, "_modelRecoilRot", (Vector2)obj3 * value); } } if (Vec2(recoil.Screen, out var result)) { Refl.SetRaw(val, "_screenRecoilAmount", result); } if (Vec3(recoil.ModelPos, out var result2)) { Refl.SetRaw(val, "_modelRecoilPos", result2); } if (Vec2(recoil.ModelRot, out var result3)) { Refl.SetRaw(val, "_modelRecoilRot", result3); } Refl.Set(val, "_weaponRecoilMulti", recoil.WeaponRecoilMulti); Refl.Set(val, "_recoilSpringPos", recoil.SpringPos); Refl.Set(val, "_recoilDamperPos", recoil.DamperPos); Refl.Set(val, "_recoilSpringRot", recoil.SpringRot); Refl.Set(val, "_recoilDamperRot", recoil.DamperRot); Refl.Set(val, "_adsRecoilPosMulti", recoil.AdsPosMulti); Refl.Set(val, "_adsRecoilRotMulti", recoil.AdsRotMulti); Refl.Set(val, "_adsRecoilSpringMulti", recoil.AdsSpringMulti); if (flag) { Plugin.Log.LogInfo((object)(" recoil on " + ((Object)((Component)val).gameObject).name + ": screen=" + Refl.Get(val, "_screenRecoilAmount")?.ToString() + " modelPos=" + Refl.Get(val, "_modelRecoilPos"))); } } Plugin.Log.LogInfo((object)("Recoil applied to " + componentsInChildren.Length + " barrel(s) of '" + built.Def.Id + "'.")); } private static bool Vec2(float[] v, out Vector2 result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) result = Vector2.zero; if (v == null || v.Length < 2) { return false; } result = new Vector2(v[0], v[1]); return true; } private static bool Vec3(float[] v, out Vector3 result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) result = Vector3.zero; if (v == null || v.Length < 3) { return false; } result = new Vector3(v[0], v[1], v[2]); return true; } private static void ApplyDamage(Attachments attachments, int damage) { if (Refl.Get(attachments, "_bulletUpgrades") is Array { Length: not 0 } array) { object value = array.GetValue(0); FieldInfo fieldInfo = Refl.Field(value.GetType(), "_damage"); if (fieldInfo == null) { return; } int num = (int)fieldInfo.GetValue(value); int num2 = damage - num; for (int i = 0; i < array.Length; i++) { object value2 = array.GetValue(i); if (value2 != null) { int num3 = (int)fieldInfo.GetValue(value2); fieldInfo.SetValue(value2, Mathf.Max(1, num3 + num2)); } } Plugin.Log.LogInfo((object)("Damage table shifted by " + num2 + " (tier 0: " + num + " -> " + damage + ").")); } else { Plugin.Log.LogWarning((object)"No _bulletUpgrades on this weapon; damage not applied."); } } private static void ScaleBulletCosts(Attachments attachments, float multiplier) { if (!(Refl.Get(attachments, "_bulletUpgrades") is Array { Length: not 0 } array) || multiplier <= 0f) { return; } FieldInfo fieldInfo = Refl.Field(array.GetValue(0).GetType(), "_cost"); if (fieldInfo == null) { return; } for (int i = 0; i < array.Length; i++) { object value = array.GetValue(i); if (value != null) { int num = (int)fieldInfo.GetValue(value); fieldInfo.SetValue(value, Mathf.Max(1, Mathf.RoundToInt((float)num * multiplier))); } } Plugin.Log.LogInfo((object)("Bullet upgrade costs scaled by " + multiplier.ToString("F2", CultureInfo.InvariantCulture) + ".")); } private static void ApplySound(BuiltWeapon built) { SoundDef sound = built.Def.Sound; if (sound == null || string.IsNullOrEmpty(sound.Fire)) { return; } object obj = Refl.Get(built.Weapon, "_attachments"); Attachments val = (Attachments)((obj is Attachments) ? obj : null); if ((Object)(object)val == (Object)null) { return; } if (!(Refl.Get(val, "_barrelAttachments") is IEnumerable enumerable)) { Plugin.Log.LogWarning((object)("No _barrelAttachments on '" + built.Def.Id + "'; fire sound not applied.")); return; } string text = FireSoundName(built.Def.Id); int num = 0; foreach (BarrelAttachment item in enumerable) { if (!((Object)(object)item == (Object)null)) { Refl.SetRaw(item, "_outsideFireSound", text); Refl.SetRaw(item, "_insideFireSound", text); Refl.SetRaw(item, "_fireSoundCount", 1); if (sound.FireVolume.HasValue) { Refl.SetRaw(item, "_fireSoundVolume", sound.FireVolume.Value); } num++; } } Plugin.Log.LogInfo((object)("Fire sound '" + text + "' set on " + num + " barrel attachment(s) of " + built.Def.Id + ".")); } public static string FireSoundName(string weaponId) { return "WA_" + weaponId + "_fire"; } public static Vector3 SuggestRotation(BuiltWeapon built) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (built == null || built.Model == null || built.Targets.Count == 0) { return Vector3.zero; } Bounds bounds = built.Model.Mesh.bounds; Vector3 val = DominantAxis(((Bounds)(ref bounds)).size); Vector3 val2 = DominantAxis(((Bounds)(ref built.Targets[0].BaseBounds)).size); Quaternion val3 = Quaternion.FromToRotation(val, val2); return ((Quaternion)(ref val3)).eulerAngles; } public static Vector3 RotateAboutBarrel(BuiltWeapon built, float degrees) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Compose(built, BarrelAxis(built), degrees); } public static Vector3 RotateAboutPerpendicular(BuiltWeapon built, float degrees) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Vector3 axis = ((Mathf.Abs(Vector3.Dot(BarrelAxis(built), Vector3.up)) > 0.9f) ? Vector3.right : Vector3.up); return Compose(built, axis, degrees); } private static Vector3 Compose(BuiltWeapon built, Vector3 axis, float degrees) { //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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ToVector(built.Def.Model.Rotation); Quaternion val2 = Quaternion.AngleAxis(degrees, axis) * Quaternion.Euler(val); return ((Quaternion)(ref val2)).eulerAngles; } private static Vector3 BarrelAxis(BuiltWeapon built) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (built == null || built.Targets.Count == 0) { return Vector3.forward; } return DominantAxis(((Bounds)(ref built.Targets[0].BaseBounds)).size); } private static Vector3 DominantAxis(Vector3 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_003e: Unknown result type (might be due to invalid IL or missing references) if (size.x >= size.y && size.x >= size.z) { return Vector3.right; } if (size.y >= size.x && size.y >= size.z) { return Vector3.up; } return Vector3.forward; } public static void ApplyRuntimeStats(Weapon weapon, WeaponDef def) { if ((Object)(object)weapon == (Object)null || def == null || def.Stats == null) { return; } object obj = Refl.Get(weapon, "_weaponInfo"); if (obj != null) { StatsDef stats = def.Stats; if (stats.Damage.HasValue) { Refl.SetProperty(obj, "ProjectileDamage", stats.Damage.Value); } if (stats.ProjectileForce.HasValue) { Refl.SetProperty(obj, "ProjectileForce", stats.ProjectileForce.Value); } if (stats.ProjectileGravity.HasValue) { Refl.SetProperty(obj, "ProjectileGravity", stats.ProjectileGravity.Value); } } } private static float Longest(Vector3 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(size.x, Mathf.Max(size.y, size.z)); } private static string RelativePath(Transform root, Transform child) { if ((Object)(object)child == (Object)(object)root) { return ""; } List list = new List(); Transform val = child; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list.ToArray()); } private static Vector3 ToVector(float[] values) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (values == null || values.Length < 3) { return Vector3.zero; } return new Vector3(values[0], values[1], values[2]); } public static void DestroyTemplates() { if ((Object)(object)_templateRoot != (Object)null) { Object.Destroy((Object)(object)_templateRoot); _templateRoot = null; } } } internal sealed class ModelDef { [JsonProperty("file")] public string File; [JsonProperty("bundleAsset")] public string BundleAsset; [JsonProperty("bundleAxisFix")] public bool BundleAxisFix = true; [JsonProperty("fitToBase")] public bool FitToBase = true; [JsonProperty("scale")] public float Scale = 1f; [JsonProperty("position")] public float[] Position; [JsonProperty("rotation")] public float[] Rotation; [JsonProperty("material")] public string Material = "vanilla"; [JsonProperty("skinning")] public string Skinning = "parts"; [JsonProperty("partBones")] public Dictionary PartBones; [JsonProperty("hideBaseAttachments")] public bool HideBaseAttachments; [JsonProperty("leftHandPart")] public int LeftHandPart = -1; [JsonProperty("gripAlongPart")] public float GripAlongPart = 0.35f; } internal sealed class IkDef { [JsonProperty("left")] public float[] Left; [JsonProperty("right")] public float[] Right; [JsonProperty("leftRotation")] public float[] LeftRotation; [JsonProperty("rightRotation")] public float[] RightRotation; [JsonProperty("followMagOnReload")] public bool FollowMagOnReload; [JsonProperty("reloadLeft")] public float[] ReloadLeft; [JsonProperty("reloadLeftRotation")] public float[] ReloadLeftRotation; [JsonProperty("reloadBlend")] public float ReloadBlend = 0.15f; [JsonProperty("chargeLeft")] public float[] ChargeLeft; [JsonProperty("chargeFrom")] public float ChargeFrom = 0.6f; [JsonProperty("chargePeak")] public float ChargePeak = 0.72f; [JsonProperty("chargeTo")] public float ChargeTo = 0.85f; [JsonProperty("chargeClip")] public string ChargeClip = "ReloadLast"; [JsonProperty("gripReturnAt")] public float GripReturnAt = 0.85f; } internal sealed class ReloadDef { [JsonProperty("enabled")] public bool Enabled = true; [JsonProperty("duration")] public float Duration = 2f; [JsonProperty("drop")] public float Drop = 6f; [JsonProperty("dip")] public float Dip = 4f; } internal sealed class SlideDef { [JsonProperty("travel")] public float Travel = 0.5f; [JsonProperty("time")] public float Time = 0.07f; [JsonProperty("offset")] public float[] Offset; } internal sealed class StatsDef { [JsonProperty("damage")] public int? Damage; [JsonProperty("timeBetweenShots")] public float? TimeBetweenShots; [JsonProperty("fullAuto")] public bool? FullAuto; [JsonProperty("noQueueingShots")] public bool? NoQueueingShots; [JsonProperty("noShootingDuringShootAnim")] public bool? NoShootingDuringShootAnim; [JsonProperty("canAds")] public bool? CanAds; [JsonProperty("spread")] public float? Spread; [JsonProperty("projectileCountPerShot")] public int? ProjectileCountPerShot; [JsonProperty("projectileSpeed")] public float? ProjectileSpeed; [JsonProperty("projectileForce")] public float? ProjectileForce; [JsonProperty("projectileGravity")] public float? ProjectileGravity; [JsonProperty("recoilKnockback")] public int? RecoilKnockback; [JsonProperty("ammoPerMag")] public int? AmmoPerMag; [JsonProperty("extendedAmmoPerMag")] public int? ExtendedAmmoPerMag; } internal sealed class SoundDef { [JsonProperty("fire")] public string Fire; [JsonProperty("fireAsset")] public string FireAsset; [JsonProperty("fireVolume")] public float? FireVolume; } internal sealed class AttachmentsDef { [JsonProperty("sights")] public bool Sights = true; [JsonProperty("barrels")] public bool Barrels = true; [JsonProperty("laser")] public bool Laser = true; [JsonProperty("extendedMag")] public bool ExtendedMag = true; [JsonProperty("bulletUpgradeCostMultiplier")] public float? BulletUpgradeCostMultiplier; } internal sealed class RecoilDef { [JsonProperty("screen")] public float[] Screen; [JsonProperty("screenMultiplier")] public float? ScreenMultiplier; [JsonProperty("modelPos")] public float[] ModelPos; [JsonProperty("modelRot")] public float[] ModelRot; [JsonProperty("modelMultiplier")] public float? ModelMultiplier; [JsonProperty("weaponRecoilMulti")] public float? WeaponRecoilMulti; [JsonProperty("springPos")] public float? SpringPos; [JsonProperty("damperPos")] public float? DamperPos; [JsonProperty("springRot")] public float? SpringRot; [JsonProperty("damperRot")] public float? DamperRot; [JsonProperty("adsPosMulti")] public float? AdsPosMulti; [JsonProperty("adsRotMulti")] public float? AdsRotMulti; [JsonProperty("adsSpringMulti")] public float? AdsSpringMulti; } internal sealed class InventoryDef { [JsonProperty("auto")] public bool Auto = true; [JsonProperty("pos")] public float[] Pos; [JsonProperty("rot")] public float[] Rot; [JsonProperty("scale")] public float? Scale; } internal sealed class ShopDef { [JsonProperty("sell")] public bool Sell = true; [JsonProperty("price")] public int Price = 1000; } internal sealed class WeaponDef { [JsonProperty("id")] public string Id; [JsonProperty("displayName")] public string DisplayName; [JsonProperty("basePrefab")] public string BasePrefab; [JsonProperty("enabled")] public bool Enabled = true; [JsonProperty("bundle")] public string Bundle; [JsonProperty("model")] public ModelDef Model; [JsonProperty("stats")] public StatsDef Stats; [JsonProperty("ik")] public IkDef Ik; [JsonProperty("slide")] public SlideDef Slide; [JsonProperty("reload")] public ReloadDef Reload; [JsonProperty("pose")] public Dictionary Pose; [JsonProperty("sound")] public SoundDef Sound; [JsonProperty("attachments")] public AttachmentsDef Attachments; [JsonProperty("recoil")] public RecoilDef Recoil; [JsonProperty("inventory")] public InventoryDef Inventory; [JsonProperty("shop")] public ShopDef Shop; [JsonProperty("animations")] public Dictionary Animations; [JsonProperty("ads")] public float[] Ads; [JsonProperty("credit")] public string Credit; [JsonIgnore] public string SourcePath; [JsonIgnore] public string ResolvedCredit; public string Describe() { return (DisplayName ?? Id) + " (" + Id + ", base=" + (BasePrefab ?? "?") + ")"; } } internal sealed class WeaponRegistry { private readonly List _defs = new List(); private readonly Dictionary _byId = new Dictionary(StringComparer.OrdinalIgnoreCase); public IReadOnlyList Defs => _defs; public string WeaponsFolder { get; private set; } public string Fingerprint { get; private set; } public List LoadErrors { get; } = new List(); public WeaponDef Get(string id) { if (string.IsNullOrEmpty(id)) { return null; } if (!_byId.TryGetValue(id, out var value)) { return null; } return value; } public void Load(string weaponsFolder) { _defs.Clear(); _byId.Clear(); LoadErrors.Clear(); WeaponsFolder = weaponsFolder; if (!Directory.Exists(weaponsFolder)) { LoadErrors.Add("weapons folder not found: " + weaponsFolder); Fingerprint = "empty"; return; } string[] files = Directory.GetFiles(weaponsFolder, "*.json", SearchOption.TopDirectoryOnly); List list = new List(); string[] array = files; foreach (string text in array) { if (string.Equals(Path.GetFileName(text), "props.json", StringComparison.OrdinalIgnoreCase)) { continue; } try { WeaponDef weaponDef = JsonConvert.DeserializeObject(File.ReadAllText(text)); if (weaponDef == null) { LoadErrors.Add(Path.GetFileName(text) + ": empty or unparsable"); continue; } weaponDef.SourcePath = text; string text2 = Validate(weaponDef, weaponsFolder); if (text2 != null) { LoadErrors.Add(Path.GetFileName(text) + ": " + text2); continue; } if (!weaponDef.Enabled) { Plugin.Log.LogInfo((object)("Skipping disabled weapon def " + weaponDef.Id)); continue; } if (_byId.ContainsKey(weaponDef.Id)) { LoadErrors.Add(Path.GetFileName(text) + ": duplicate id '" + weaponDef.Id + "'"); continue; } _byId[weaponDef.Id] = weaponDef; list.Add(weaponDef); } catch (Exception ex) { LoadErrors.Add(Path.GetFileName(text) + ": " + ex.Message); } } list.Sort((WeaponDef a, WeaponDef b) => string.CompareOrdinal(a.Id, b.Id)); _defs.AddRange(list); Fingerprint = ComputeFingerprint(_defs); Plugin.Log.LogInfo((object)("Loaded " + _defs.Count + " weapon def(s), fingerprint " + Fingerprint)); for (int num = 0; num < _defs.Count; num++) { Plugin.Log.LogInfo((object)(" [" + num + "] " + _defs[num].Describe())); } foreach (string loadError in LoadErrors) { Plugin.Log.LogWarning((object)("Weapon def rejected - " + loadError)); } } private static string Validate(WeaponDef def, string folder) { if (string.IsNullOrEmpty(def.Id)) { return "missing 'id'"; } string id = def.Id; foreach (char c in id) { if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_' && c != '-') { return "id '" + def.Id + "' may only contain letters, digits, '_' and '-'"; } } if (string.IsNullOrEmpty(def.BasePrefab)) { return "missing 'basePrefab'"; } if (def.Model == null) { return "missing 'model'"; } if (!string.IsNullOrEmpty(def.Model.BundleAsset)) { if (string.IsNullOrEmpty(def.Bundle)) { return "'model.bundleAsset' is set but 'bundle' is missing"; } if (!File.Exists(Path.Combine(folder, def.Bundle))) { return "asset bundle not found: " + def.Bundle; } } else { if (string.IsNullOrEmpty(def.Model.File)) { return "missing 'model.file' or 'model.bundleAsset'"; } if (!File.Exists(Path.Combine(folder, def.Model.File))) { return "model file not found: " + def.Model.File; } } return null; } private static string ComputeFingerprint(List defs) { if (defs.Count == 0) { return "empty"; } uint num = 2166136261u; foreach (WeaponDef def in defs) { byte[] bytes = Encoding.UTF8.GetBytes(def.Id); foreach (byte b in bytes) { num ^= b; num *= 16777619; } num ^= 0x7C; num *= 16777619; } return defs.Count + ":" + num.ToString("x8"); } } internal static class WeaponSpawner { private const float SpawnDistance = 1.5f; public unsafe static bool TrySpawn(BuiltWeapon built, out string error) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) error = null; if (built == null) { error = "no such weapon"; return false; } if (!ModPrefabRegistry.Ready) { error = "prefabs are not registered (" + ModPrefabRegistry.Status() + ")"; return false; } if (!InstanceFinder.IsServerStarted) { error = "only the host can spawn items; you are a client here"; return false; } ItemManager instance = ItemManager.Instance; if ((Object)(object)instance == (Object)null) { error = "ItemManager is not available yet - load into a game first"; return false; } Item weapon = (Item)(object)built.Weapon; if ((Object)(object)weapon == (Object)null) { error = "built prefab has no Item component"; return false; } SpawnPose(out var position, out var rotation); try { if ((Object)(object)instance.SpawnNewItem(weapon, position, rotation) == (Object)null) { error = "SpawnNewItem returned null"; return false; } Plugin.Log.LogInfo((object)("Spawned '" + built.Def.Id + "' at " + ((object)(*(Vector3*)(&position))/*cast due to .constrained prefix*/).ToString())); return true; } catch (Exception ex) { error = ex.Message; Plugin.Log.LogError((object)("Spawning '" + built.Def.Id + "' threw: " + ex)); return false; } } private static void SpawnPose(out Vector3 position, out Quaternion rotation) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.LocalPlayer; Camera val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.CurCam : null); if ((Object)(object)val != (Object)null) { Transform transform = ((Component)val).transform; position = transform.position + transform.forward * 1.5f; rotation = Quaternion.LookRotation(transform.forward, Vector3.up); } else { position = Vector3.zero; rotation = Quaternion.identity; } } } }