Decompiled source of zPaulinsWeaponArsenal v1.0.1

BepInEx\plugins\HowToFish.WeaponArsenal\HowToFish.ModKit.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("HowToFish.ModKit")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+5554268e42ae4803814c23b41e24d3c196693022")]
[assembly: AssemblyProduct("HowToFish.ModKit")]
[assembly: AssemblyTitle("How to Fish - Mod Kit runtime")]
[assembly: AssemblyVersion("1.0.0.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.ModKit
{
	public static class BundleLoader
	{
		private static readonly Dictionary<string, AssetBundle> Loaded = new Dictionary<string, AssetBundle>(StringComparer.OrdinalIgnoreCase);

		public static ManualLogSource Log { get; set; }

		public static string PluginDirectoryOf(object plugin)
		{
			return Path.GetDirectoryName(plugin.GetType().Assembly.Location);
		}

		public static AssetBundle Load(object plugin, string bundleFileName)
		{
			return LoadFrom(Path.Combine(PluginDirectoryOf(plugin), bundleFileName));
		}

		public static AssetBundle LoadFrom(string fullPath)
		{
			string fullPath2 = Path.GetFullPath(fullPath);
			if (Loaded.TryGetValue(fullPath2, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if (!File.Exists(fullPath2))
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("Asset bundle not found: " + fullPath2));
				}
				return null;
			}
			AssetBundle val = AssetBundle.LoadFromFile(fullPath2);
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogError((object)("Failed to load asset bundle: " + fullPath2 + ". It was most likely built with a different Unity version than 6000.4.x."));
				}
				return null;
			}
			Loaded[fullPath2] = val;
			ManualLogSource log3 = Log;
			if (log3 != null)
			{
				log3.LogInfo((object)$"Loaded bundle {Path.GetFileName(fullPath2)} ({val.GetAllAssetNames().Length} assets)");
			}
			return val;
		}

		public static T Asset<T>(AssetBundle bundle, string name) where T : Object
		{
			if ((Object)(object)bundle == (Object)null)
			{
				return default(T);
			}
			T val = bundle.LoadAsset<T>(name);
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("Asset '" + name + "' of type " + typeof(T).Name + " not found in bundle. Available: " + string.Join(", ", bundle.GetAllAssetNames())));
				}
				return default(T);
			}
			object obj = val;
			GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
			if (val2 != null)
			{
				ShaderFix.Apply(val2);
			}
			else
			{
				object obj2 = val;
				Material val3 = (Material)((obj2 is Material) ? obj2 : null);
				if (val3 != null)
				{
					ShaderFix.Apply(val3);
				}
			}
			return val;
		}

		public static GameObject Prefab(AssetBundle bundle, string name)
		{
			return BundleLoader.Asset<GameObject>(bundle, name);
		}

		public static void UnloadAll(bool unloadLoadedObjects = false)
		{
			foreach (AssetBundle value in Loaded.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					value.Unload(unloadLoadedObjects);
				}
			}
			Loaded.Clear();
		}
	}
	public static class ShaderFix
	{
		private static readonly Dictionary<string, Shader> Cache = new Dictionary<string, Shader>();

		public static bool Enabled = true;

		public static void Apply(GameObject root)
		{
			if (!Enabled || (Object)(object)root == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				foreach (Material material in sharedMaterials)
				{
					Apply(material);
				}
			}
		}

		public static void Apply(Material material)
		{
			if (!Enabled || (Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null)
			{
				return;
			}
			string name = ((Object)material.shader).name;
			if (!Cache.TryGetValue(name, out var value))
			{
				value = Shader.Find(name);
				Cache[name] = value;
			}
			if ((Object)(object)value == (Object)null)
			{
				ManualLogSource log = BundleLoader.Log;
				if (log != null)
				{
					log.LogWarning((object)("Shader '" + name + "' is not present in the game build; material '" + ((Object)material).name + "' will render incorrectly. Author it with a URP shader the game already uses (Universal Render Pipeline/Lit)."));
				}
			}
			else
			{
				int renderQueue = material.renderQueue;
				material.shader = value;
				material.renderQueue = renderQueue;
			}
		}
	}
}

BepInEx\plugins\HowToFish.WeaponArsenal\HowToFish.WeaponArsenal.dll

Decompiled 2 hours ago
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<bool> Enabled;

		public readonly ConfigEntry<bool> VerboseLogging;

		public readonly ConfigEntry<ushort> PrefabCollectionId;

		public readonly ConfigEntry<string> ShopIslandName;

		public readonly ConfigEntry<int> ShopIslandIndex;

		public readonly ConfigEntry<float> ShopFallbackSpacing;

		public readonly ConfigEntry<bool> LiveTuning;

		public readonly ConfigEntry<string> SourceWeaponsFolder;

		public ModConfig(ConfigFile f)
		{
			Enabled = f.Bind<bool>("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<bool>("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<ushort>("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<string>("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<int>("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<float>("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<string>("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<bool>("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<ArsenalRuntime>();
			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<string, FieldInfo> FieldCache = new Dictionary<string, FieldInfo>();

		private static readonly HashSet<string> Warned = new HashSet<string>();

		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<T>(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<T>(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<ArsenalWeapon>(true);
			if ((Object)(object)componentInParent == (Object)null)
			{
				return;
			}
			WeaponDef def = componentInParent.Def;
			if (def == null || def.Attachments == null || !(Refl.Get(__instance, "_attachmentCosts") is Dictionary<AttachmentInfo, int> dictionary))
			{
				return;
			}
			int num = 0;
			AttachmentsDef attachments = def.Attachments;
			if (!attachments.Sights)
			{
				num += RemoveList<Sight>(dictionary, Refl.Get(__instance, "_sights") as IEnumerable<Sight>, 1);
			}
			if (!attachments.Barrels)
			{
				num += RemoveList<BarrelAttachment>(dictionary, Refl.Get(__instance, "_barrelAttachments") as IEnumerable<BarrelAttachment>, 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<T>(Dictionary<AttachmentInfo, int> costs, IEnumerable<T> 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 <basePrefabName|weaponId>");
				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<Item>(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 <id> [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 <id> nudge up|down|left|right|forward|back <n> | set <x> <y> <z> | 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 <x> <y> <z>");
					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 <n>");
					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 <id> [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<HandDriver>();
			foreach (HandDriver handDriver2 in array)
			{
				if (!((Object)(object)handDriver2 == (Object)null))
				{
					ArsenalWeapon componentInChildren = ((Component)handDriver2).GetComponentInChildren<ArsenalWeapon>(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 <id> [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 <id>");
				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 <id> learn|keep|clear|travel <v>|time <v>|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 + " <value>");
				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<SlideDriver>();
			foreach (SlideDriver slideDriver in array)
			{
				if (!((Object)(object)slideDriver == (Object)null))
				{
					ArsenalWeapon componentInChildren = ((Component)slideDriver).GetComponentInChildren<ArsenalWeapon>(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 <id> [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 <id> <boneName> <x> <y> <z> | 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<string, float[]> item in builtWeapon.Def.Pose)
					{
						Say("  " + item.Key + " " + Vec(item.Value));
					}
					return;
				}
			case "bones":
			{
				string text2 = ((parts.Length > 4) ? parts[4].ToLowerInvariant() : null);
				List<string> 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 + " <x> <y> <z>");
				Say("current: " + Vec3(WeaponBuilder.CurrentLocalEuler(builtWeapon, text)));
				return;
			}
			if (builtWeapon.Def.Pose == null)
			{
				builtWeapon.Def.Pose = new Dictionary<string, float[]>();
			}
			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 <id> left|right <x> <y> <z>   (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 <id> left|right|leftrot|rightrot|reloadleft|reloadleftrot <x> <y> <z>");
				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 + " <x> <y> <z>");
				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 <from> <peak> <to>");
					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 <amount>");
				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 <id>");
				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<Transform>(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 <id> <index|next|all>");
				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 <id> pos|rot <x> <y> <z> | height <m> | scale <v> | nudge <dx> <dy> <dz> | 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 <v>   (or: height <metres>)");
					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 <metres>");
					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 + " <x> <y> <z>");
					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 <id> pos|rot <x> <y> <z> | height <m> | scale <v> | nudge <dx> <dy> <dz> | 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 <id>");
				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 <id> 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 <value>");
					return;
				}
				model.Scale = value4;
				break;
			}
			case "pos":
			{
				if (!TryParseVector(parts, 4, out var value3))
				{
					Say("usage: /wa fit " + text + " pos <x> <y> <z>");
					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 <x> <y> <z>");
					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 <degrees>");
					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 <dx> <dy> <dz>");
					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 <id>         - spawn a custom weapon in front of you (host only)");
			Say("/wa inspect <name>    - 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 <id>      - log hand IK targets, fire point and ADS pose in mesh space");
			Say("/wa ik <id> left|right|leftrot|rightrot <x> <y> <z> - hand pos/rot; show|save");
			Say("/wa ik <id> reloadleft <x> <y> <z>  - steer the hand during the reload clip only");
			Say("/wa auto <id>         - solve alignment AND hand placement, then save");
			Say("/wa pose <id> <bone> <x> <y> <z>  - rotate any bone (finger curl); bones|show|clear|save");
			Say("/wa grip <id> [left|right] [save] - wrap the fingers onto the model, solved from geometry");
			Say("/wa slide <id> learn -> reload -> keep - copy the rack from the reload clip");
			Say("/wa slide <id> travel <v>|time <v>  - charging handle throw and speed; show|clear|save");
			Say("/wa charge <id>       - MEASURE the charging handle offset from a full reload; show|clear");
			Say("/wa forge <id> [charge]|restore - rebuild ReloadLast as a real clip; restore undoes it");
			Say("/wa ads <id> nudge up|down|left|right|forward|back <n> - line the iron sights up; show|save");
			Say("/wa ik <id> chargenudge left|right|up|down|forward|back <n> - nudge it as you see it");
			Say("/wa ik <id> chargewindow <from> <peak> <to> | gripreturn <t> - when the racking happens");
			Say("/wa ik <id> chargeleft <x> <y> <z>  - the same offset by hand, if the measurement misses");
			Say("                        during the racking frames of the reload only");
			Say("/wa paths <id>        - transform paths an authored AnimationClip must bind to");
			Say("/wa fit <id> nudge <dx> <dy> <dz> - move the model by a small delta");
			Say("/wa part <id> next    - show one model part at a time to identify it");
			Say("/wa fit <id> show     - current alignment numbers");
			Say("/wa fit <id> auto      - guess a rotation from the base weapon's proportions");
			Say("/wa fit <id> flip      - 180 around the barrel, for an upside-down model");
			Say("/wa fit <id> roll <d>  - any angle around the barrel");
			Say("/wa fit <id> reverse   - end for end, when the barrel points backwards");
			Say("/wa fit <id> scale <v>");
			Say("/wa fit <id> pos <x> <y> <z>");
			Say("/wa fit <id> rot <x> <y> <z>");
			Say("/wa fit <id> 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<InventorySlot, SlotState> States = new Dictionary<InventorySlot, SlotState>();

		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) ? "<none>" : ((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<ArsenalWeapon>(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<ArsenalWeapon>(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<ArsenalWeapon>(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<Object>(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>(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<AudioClip>(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<SkinnedMeshRenderer>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				mesh = componentInChildren.sharedMesh;
				materials = ((Renderer)componentInChildren).sharedMaterials;
				return;
			}
			MeshFilter componentInChildren2 = val.GetComponentInChildren<MeshFilter>(true);
			if (!((Object)(object)componentInChildren2 == (Object)null))
			{
				mesh = componentInChildren2.sharedMesh;
				MeshRenderer component = ((Component)componentInChildren2).GetComponent<MeshRenderer>();
				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<string, int> 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<GltfPrimitive> 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<GltfScene> Scenes;

		[JsonProperty("nodes")]
		public List<GltfNode> Nodes;

		[JsonProperty("meshes")]
		public List<GltfMesh> Meshes;

		[JsonProperty("accessors")]
		public List<GltfAccessor> Accessors;

		[JsonProperty("bufferViews")]
		public List<GltfBufferView> BufferViews;

		[JsonProperty("buffers")]
		public List<GltfBuffer> Buffers;

		[JsonProperty("materials")]
		public List<GltfMaterial> Materials;

		[JsonProperty("textures")]
		public List<GltfTexture> Textures;

		[JsonProperty("images")]
		public List<GltfImage> 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<GltfRoot>(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<Vector3> list = new List<Vector3>();
			List<int> list2 = new List<int>();
			int groupCounter = 0;
			List<Vector3> list3 = new List<Vector3>();
			List<Vector2> list4 = new List<Vector2>();
			Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
			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<int> list5 = new List<int>(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<int> 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<int> list = new List<int>();
			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<Vector3> positions, List<Vector3> normals, List<Vector2> uvs, Dictionary<int, List<int>> perMaterial, List<int> 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],