Decompiled source of ULTRAKILL V1 Survivor v0.2.0

plugins\UltrakillV1.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.GolemMonster;
using HG.BlendableTypes;
using KinematicCharacterController;
using Microsoft.CodeAnalysis;
using On.EntityStates.GolemMonster;
using On.RoR2;
using On.RoR2.Items;
using On.RoR2.Orbs;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using R2API.Utils;
using RoR2;
using RoR2.ConVar;
using RoR2.Items;
using RoR2.Orbs;
using RoR2.Projectile;
using RoR2.Skills;
using TMPro;
using UltrakillV1.Components;
using UltrakillV1.Hooks;
using UltrakillV1.Modules;
using UltrakillV1.Modules.AssetSetup;
using UltrakillV1.Setup.Pipeline;
using UltrakillV1.SkillStates;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("RoR2")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Saidrog")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("ULTRAKILL V1 Survivor")]
[assembly: AssemblyTitle("UltrakillV1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace UltrakillV1
{
	[BepInPlugin("com.ultrakill.v1survivor", "UltrakillV1Survivor", "0.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class UltrakillV1Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.ultrakill.v1survivor";

		public const string PluginName = "UltrakillV1Survivor";

		public const string PluginVersion = "0.2.0";

		private bool _setupBroken;

		public static UltrakillV1Plugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Initializing ULTRAKILL V1 Survivor for Risk of Rain 2...");
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			Tokens.RegisterTokens();
			ModDamageTypes.Init();
			V1Explosions.Init();
			V1SlamLaunch.Init();
			V1Network.Init();
			try
			{
				V1AssetSetup.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			}
			catch (Exception ex)
			{
				_setupBroken = true;
				((BaseUnityPlugin)this).Logger.LogError((object)("Asset setup unavailable: " + ex));
			}
			ModAssets.Init();
			ModSounds.Init();
			ModItems.Init();
			Prefabs.Init();
			Skills.Init();
			BloodHealHooks.Init();
			V1NearCameraFade.Init();
			V1CameraShake.Init();
			CoinChargebackHooks.Init();
			BossDropHooks.Init();
			ItemCompatHooks.Init();
			V1Ragdoll.Init();
			StatRecalculationHooks.Init();
			V1MovementController.InitHooks();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ULTRAKILL V1 Survivor successfully initialized! MANKIND IS DEAD. BLOOD IS FUEL. HELL IS FULL.");
		}

		private void Update()
		{
			ModSounds.Update();
			if (_setupBroken)
			{
				return;
			}
			try
			{
				V1AssetSetup.Update();
			}
			catch (Exception ex)
			{
				_setupBroken = true;
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void LateUpdate()
		{
			if (_setupBroken)
			{
				return;
			}
			try
			{
				FolderPicker.UpdateCursor();
			}
			catch (Exception ex)
			{
				_setupBroken = true;
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void OnGUI()
		{
			if (_setupBroken)
			{
				return;
			}
			try
			{
				V1AssetSetup.OnGUI();
			}
			catch (Exception ex)
			{
				_setupBroken = true;
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void OnDestroy()
		{
			V1AudioMixer.Shutdown();
		}
	}
}
namespace UltrakillV1.SkillStates
{
	public class FeedbackerPunch : BaseSkillState
	{
		public static float BaseDuration = 0.4f;

		public const int MaxStamina = 2;

		public const float StaminaPerSecond = 1.25f;

		public const float FistCooldown = 0.25f;

		public static float DamageCoefficient = 3.5f;

		public static float PunchRange = 4.5f;

		private float _duration;

		private bool _hasAttacked;

		private ParryZone _parryZone;

		public override void OnEnter()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).OnEnter();
			_duration = BaseDuration / ((BaseState)this).attackSpeedStat;
			V1WeaponManager component = ((EntityState)this).GetComponent<V1WeaponManager>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.LastPunchTime = Time.time;
			}
			_parryZone = ((EntityState)this).gameObject.GetComponentInChildren<ParryZone>();
			if ((Object)(object)_parryZone == (Object)null)
			{
				GameObject val = new GameObject("ParryZone");
				val.transform.SetParent(((EntityState)this).transform, false);
				_parryZone = val.AddComponent<ParryZone>();
				_parryZone.Owner = ((EntityState)this).gameObject;
			}
			_parryZone.IsActive = true;
			_parryZone.ResetParried();
			ModSounds.Play(ModSounds.PunchSwing, ((EntityState)this).gameObject);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Punch");
			((EntityState)this).PlayAnimation("Gesture, Override", "Punch", "Punch.playbackRate", _duration, 0f);
			if (((EntityState)this).isAuthority)
			{
				TryBoostShotgunPellet(((BaseState)this).GetAimRay());
			}
		}

		private void TryBoostShotgunPellet(Ray aimRay)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			Vector3 center = ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * _parryZone.ParryReach;
			V1ShotgunPellet v1ShotgunPellet = V1ShotgunPellet.FindPunchable(((EntityState)this).gameObject, center, _parryZone.ParryRadius, ((Ray)(ref aimRay)).origin);
			if (Object.op_Implicit((Object)(object)v1ShotgunPellet))
			{
				Vector3 point = ((Ray)(ref aimRay)).GetPoint(1000f);
				Ray val = aimRay;
				LayerIndex val2 = LayerIndex.world;
				int num = LayerMask.op_Implicit(((LayerIndex)(ref val2)).mask);
				val2 = LayerIndex.entityPrecise;
				RaycastHit val3 = default(RaycastHit);
				if (Physics.Raycast(val, ref val3, 1000f, num | LayerMask.op_Implicit(((LayerIndex)(ref val2)).mask), (QueryTriggerInteraction)1))
				{
					point = ((RaycastHit)(ref val3)).point;
				}
				Vector3 direction = point - v1ShotgunPellet.Position;
				if (((Vector3)(ref direction)).sqrMagnitude < 0.01f)
				{
					direction = ((Ray)(ref aimRay)).direction;
				}
				v1ShotgunPellet.Boost(direction, ((BaseState)this).damageStat * 6f, ((BaseState)this).RollCrit());
				V1Hitstop component = ((EntityState)this).GetComponent<V1Hitstop>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.ParryFlash();
				}
				ModSounds.Play(ModSounds.PunchHit, ((EntityState)this).gameObject);
				V1ViewmodelController.TryPlay(((EntityState)this).gameObject, "Hook", 0.065f);
			}
		}

		public override void FixedUpdate()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			((EntityState)this).FixedUpdate();
			Ray aimRay = ((BaseState)this).GetAimRay();
			if ((((EntityState)this).isAuthority || NetworkServer.active) && (Object)(object)_parryZone != (Object)null && ((EntityState)this).fixedAge <= _duration * 0.6f)
			{
				_parryZone.CheckAndPerformParry(aimRay, NetworkServer.active, ((EntityState)this).isAuthority);
			}
			if (!_hasAttacked && ((EntityState)this).fixedAge >= _duration * 0.25f)
			{
				_hasAttacked = true;
				FireMeleeHit(aimRay);
			}
			if (((EntityState)this).fixedAge >= _duration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		private void FireMeleeHit(Ray aimRay)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			if (!NetworkServer.active)
			{
				if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)FindPunchTarget(aimRay)))
				{
					ModSounds.Play(ModSounds.PunchHit, ((EntityState)this).gameObject);
				}
			}
			else
			{
				if (!NetworkServer.active)
				{
					return;
				}
				BullseyeSearch val = new BullseyeSearch
				{
					searchOrigin = ((Ray)(ref aimRay)).origin,
					searchDirection = ((Ray)(ref aimRay)).direction,
					minDistanceFilter = 0f,
					maxDistanceFilter = PunchRange,
					teamMaskFilter = TeamMask.GetUnprotectedTeams(((EntityState)this).teamComponent.teamIndex),
					sortMode = (SortMode)1
				};
				val.RefreshCandidates();
				val.FilterOutGameObject(((EntityState)this).gameObject);
				foreach (HurtBox result in val.GetResults())
				{
					if (Object.op_Implicit((Object)(object)result) && Object.op_Implicit((Object)(object)result.healthComponent))
					{
						DamageInfo val2 = new DamageInfo
						{
							attacker = ((EntityState)this).gameObject,
							inflictor = ((EntityState)this).gameObject,
							damage = ((BaseState)this).damageStat * DamageCoefficient,
							crit = ((BaseState)this).RollCrit(),
							damageType = DamageTypeCombo.op_Implicit((DamageSource)8),
							position = ((Component)result).transform.position,
							force = ((Ray)(ref aimRay)).direction * 3000f,
							procCoefficient = 1f
						};
						result.healthComponent.TakeDamage(val2);
						GlobalEventManager.instance.OnHitEnemy(val2, ((Component)result.healthComponent).gameObject);
						ModSounds.Play(ModSounds.PunchHit, ((EntityState)this).gameObject);
						break;
					}
				}
			}
		}

		private HurtBox FindPunchTarget(Ray aimRay)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			BullseyeSearch val = new BullseyeSearch
			{
				searchOrigin = ((Ray)(ref aimRay)).origin,
				searchDirection = ((Ray)(ref aimRay)).direction,
				minDistanceFilter = 0f,
				maxDistanceFilter = PunchRange,
				teamMaskFilter = TeamMask.GetUnprotectedTeams(((EntityState)this).teamComponent.teamIndex),
				sortMode = (SortMode)1
			};
			val.RefreshCandidates();
			val.FilterOutGameObject(((EntityState)this).gameObject);
			foreach (HurtBox result in val.GetResults())
			{
				if (Object.op_Implicit((Object)(object)result) && Object.op_Implicit((Object)(object)result.healthComponent))
				{
					return result;
				}
			}
			return null;
		}

		public override void OnExit()
		{
			if (Object.op_Implicit((Object)(object)_parryZone))
			{
				_parryZone.IsActive = false;
			}
			((EntityState)this).OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class NailgunFire : BaseSkillState
	{
		public const float UkSpread = 10f;

		public const float SpawnDistance = 0.52f;

		private V1Nailgun _nailgun;

		private float _timer;

		private bool _wasEmpty;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			_nailgun = ((EntityState)this).GetComponent<V1Nailgun>();
			if (Object.op_Implicit((Object)(object)_nailgun))
			{
				_nailgun.Firing = true;
			}
			_timer = 0f;
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			((BaseState)this).StartAimMode(1f, false);
			if (!((EntityState)this).isAuthority)
			{
				return;
			}
			if (!((BaseSkillState)this).IsKeyDownAuthority())
			{
				((EntityState)this).outer.SetNextStateToMain();
				return;
			}
			float num = 0.04f / Mathf.Max(0.1f, ((BaseState)this).attackSpeedStat);
			_timer -= Time.fixedDeltaTime;
			while (_timer <= 0f)
			{
				if (Object.op_Implicit((Object)(object)_nailgun) && _nailgun.Ammo < 1f)
				{
					ModSounds.Play(ModSounds.WeaponSwap, ((EntityState)this).gameObject, _wasEmpty ? 0.7f : 1f);
					_wasEmpty = true;
					_timer += num * 2f;
				}
				else
				{
					_wasEmpty = false;
					FireNail();
					_timer += num;
				}
			}
		}

		private void FireNail()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_nailgun))
			{
				_nailgun.Ammo -= 1f;
				_nailgun.RecordShot();
			}
			ModSounds.Play(ModSounds.NailgunFire, ((EntityState)this).gameObject, Random.Range(0.95f, 1.05f));
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Fire");
			V1ViewmodelController.TryUltrakillMuzzleFlash(((EntityState)this).gameObject, ModAssets.UkNailgunMuzzleTemplate, 0.35f, 0.6f, withLight: false, 0.05f);
			Ray aimRay = ((BaseState)this).GetAimRay();
			float num = 3.3333333f;
			Quaternion val = Quaternion.Euler(Random.Range(0f - num, num), Random.Range(0f - num, num), 0f);
			Vector3 val2 = Util.QuaternionSafeLookRotation(((Ray)(ref aimRay)).direction) * val * Vector3.forward;
			Vector3 position = ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * 0.52f;
			Ray val3 = aimRay;
			LayerIndex world = LayerIndex.world;
			if (Physics.Raycast(val3, 0.52f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
			{
				position = ((Ray)(ref aimRay)).origin;
			}
			V1Nail.Spawn(((EntityState)this).gameObject, position, val2 * 104f, ((BaseState)this).RollCrit());
		}

		public override void OnExit()
		{
			if (Object.op_Implicit((Object)(object)_nailgun))
			{
				_nailgun.Firing = false;
			}
			((EntityState)this).OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class NailgunHeatsink : BaseSkillState
	{
		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			if (((EntityState)this).isAuthority)
			{
				V1Nailgun component = ((EntityState)this).GetComponent<V1Nailgun>();
				if (Object.op_Implicit((Object)(object)component) && component.TryBurnOut())
				{
					ModSounds.Play(ModSounds.CoreChargeLoop, ((EntityState)this).gameObject, 1.6f, 0.8f);
					ModSounds.Play(ModSounds.ShotgunPump1, ((EntityState)this).gameObject, 0.8f);
					((EntityState)this).outer.SetNextState((EntityState)(object)new NailgunOverheatFire());
				}
				else
				{
					((EntityState)this).outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class NailgunMagnet : BaseSkillState
	{
		public static float BaseDuration = 0.1f;

		public override void OnEnter()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).OnEnter();
			if (!((EntityState)this).isAuthority)
			{
				return;
			}
			V1Nailgun component = ((EntityState)this).GetComponent<V1Nailgun>();
			if (Object.op_Implicit((Object)(object)component) && component.MagnetCharge < 1f)
			{
				ModSounds.Play(ModSounds.WeaponSwap, ((EntityState)this).gameObject, 0.7f);
				return;
			}
			if (Object.op_Implicit((Object)(object)component))
			{
				component.MagnetCharge -= 1f;
			}
			ModSounds.Play(ModSounds.MagnetThrow, ((EntityState)this).gameObject);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Fire");
			Ray aimRay = ((BaseState)this).GetAimRay();
			((BaseState)this).StartAimMode(aimRay, 2f, false);
			Vector3 position = ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * 0.52f;
			Ray val = aimRay;
			LayerIndex world = LayerIndex.world;
			if (Physics.Raycast(val, 0.52f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
			{
				position = ((Ray)(ref aimRay)).origin;
			}
			V1Magnet.Throw(((EntityState)this).gameObject, position, ((Ray)(ref aimRay)).direction);
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (((EntityState)this).fixedAge >= BaseDuration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class NailgunOverheatFire : BaseSkillState
	{
		public const float UkSpread = 20f;

		public const float DamageCoefficient = 0.23689024f;

		private V1Nailgun _nailgun;

		private float _timer;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			_nailgun = ((EntityState)this).GetComponent<V1Nailgun>();
			_timer = 0f;
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			((BaseState)this).StartAimMode(1f, false);
			if (!((EntityState)this).isAuthority || !Object.op_Implicit((Object)(object)_nailgun))
			{
				return;
			}
			bool flag = Object.op_Implicit((Object)(object)((EntityState)this).inputBank) && ((EntityState)this).inputBank.skill1.down;
			_nailgun.OverheatFiring = flag && !_nailgun.BurnOut;
			if (!flag && !_nailgun.BurnOut)
			{
				((EntityState)this).outer.SetNextStateToMain();
				return;
			}
			_timer -= Time.fixedDeltaTime;
			while (_timer <= 0f)
			{
				FireNail();
				_timer += _nailgun.OverheatInterval / Mathf.Max(0.1f, ((BaseState)this).attackSpeedStat);
			}
		}

		private void FireNail()
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			_nailgun.RecordShot();
			bool burnOut = _nailgun.BurnOut;
			bool flag = _nailgun.HeatSinks < 1f && !burnOut;
			float pitch = (burnOut ? 2f : (flag ? 0.75f : Random.Range(0.95f, 1.05f)));
			ModSounds.Play(ModSounds.NailgunFire, ((EntityState)this).gameObject, pitch, flag ? 0.4f : 1f);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Fire");
			GameObject template = ((burnOut && Object.op_Implicit((Object)(object)ModAssets.UkNailgunMuzzle2Template)) ? ModAssets.UkNailgunMuzzle2Template : ModAssets.UkNailgunMuzzleTemplate);
			V1ViewmodelController.TryUltrakillMuzzleFlash(((EntityState)this).gameObject, template, 0.35f, 0.6f, withLight: false, 0.05f);
			Ray aimRay = ((BaseState)this).GetAimRay();
			float num = (burnOut ? 40f : 20f) / 3f;
			Quaternion val = Quaternion.Euler(Random.Range(0f - num, num), Random.Range(0f - num, num), 0f);
			Vector3 val2 = Util.QuaternionSafeLookRotation(((Ray)(ref aimRay)).direction) * val * Vector3.forward;
			Vector3 position = ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * 0.52f;
			Ray val3 = aimRay;
			LayerIndex world = LayerIndex.world;
			if (Physics.Raycast(val3, 0.52f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
			{
				position = ((Ray)(ref aimRay)).origin;
			}
			V1Nail.Spawn(((EntityState)this).gameObject, position, val2 * 104f, ((BaseState)this).RollCrit(), 0.23689024f, burnOut);
		}

		public override void OnExit()
		{
			if (Object.op_Implicit((Object)(object)_nailgun))
			{
				_nailgun.OverheatFiring = false;
			}
			((EntityState)this).OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (Object.op_Implicit((Object)(object)_nailgun) && _nailgun.BurnOut)
			{
				return (InterruptPriority)7;
			}
			return (InterruptPriority)1;
		}
	}
	public class RailcannonFire : BaseSkillState
	{
		public const float DamageCoefficient = 20f;

		public const float Duration = 0.5f;

		public override void OnEnter()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).OnEnter();
			ModSounds.Play(ModSounds.RailcannonFire, ((EntityState)this).gameObject);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Fire");
			if (((EntityState)this).isAuthority)
			{
				V1Railcannon component = ((EntityState)this).GetComponent<V1Railcannon>();
				if (!Object.op_Implicit((Object)(object)component) || !component.TryFire())
				{
					((EntityState)this).outer.SetNextStateToMain();
					return;
				}
				Ray aimRay = ((BaseState)this).GetAimRay();
				((BaseState)this).StartAimMode(aimRay, 2f, false);
				((BaseState)this).AddRecoil(-4f, -6f, -1f, 1f);
				V1Electricity.FireBeam(((EntityState)this).gameObject, ((Ray)(ref aimRay)).origin, ((Ray)(ref aimRay)).direction, 520f, ((BaseState)this).damageStat * 20f, ((BaseState)this).RollCrit(), fromGun: true);
			}
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (((EntityState)this).isAuthority && ((EntityState)this).fixedAge >= 0.5f)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class RevolverCoinToss : BaseSkillState
	{
		public static float BaseDuration = 0.25f;

		private float _duration;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			_duration = BaseDuration / ((BaseState)this).attackSpeedStat;
			if (((EntityState)this).isAuthority)
			{
				V1CoinCharges component = ((EntityState)this).GetComponent<V1CoinCharges>();
				if (Object.op_Implicit((Object)(object)component) && component.TryConsume())
				{
					TossCoin();
					ModSounds.Play(ModSounds.CoinToss, ((EntityState)this).gameObject);
					V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "CoinToss");
				}
				else
				{
					ModSounds.Play(ModSounds.WeaponSwap, ((EntityState)this).gameObject);
				}
			}
		}

		private void TossCoin()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)ModAssets.CoinPrefab))
			{
				Ray aimRay = ((BaseState)this).GetAimRay();
				Vector3 val = Quaternion.LookRotation(((Ray)(ref aimRay)).direction) * Vector3.up;
				Vector3 val2 = ((Ray)(ref aimRay)).origin - val * 0.26f;
				CoinController component = Object.Instantiate<GameObject>(ModAssets.CoinPrefab, val2, Quaternion.identity).GetComponent<CoinController>();
				if ((Object)(object)component != (Object)null)
				{
					Vector3 playerVelocity = (Object.op_Implicit((Object)(object)((EntityState)this).characterMotor) ? ((EntityState)this).characterMotor.velocity : Vector3.zero);
					component.Toss(((EntityState)this).gameObject, val2, ((Ray)(ref aimRay)).direction, playerVelocity);
				}
			}
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (((EntityState)this).fixedAge >= _duration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class RevolverPiercerCharge : BaseSkillState
	{
		public static float BaseChargeDuration = 0.5714286f;

		private const float MinLoopPitch = 0.05f;

		private float _chargeDuration;

		private bool _fullyCharged;

		private V1WeaponManager _weaponManager;

		private V1ViewmodelController _viewmodel;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			_chargeDuration = BaseChargeDuration / ((BaseState)this).attackSpeedStat;
			_weaponManager = ((EntityState)this).GetComponent<V1WeaponManager>();
			_viewmodel = ((EntityState)this).GetComponent<V1ViewmodelController>();
			ModSounds.StartLoop(ModSounds.PiercerChargeLoop, ((EntityState)this).gameObject);
			ModSounds.SetLoop(ModSounds.PiercerChargeLoop, ((EntityState)this).gameObject, 0.25f, 0.05f);
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			((BaseState)this).StartAimMode(2f, false);
			float num = Mathf.Clamp01(((EntityState)this).fixedAge / _chargeDuration);
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)_weaponManager))
			{
				_weaponManager.PiercerCharge = num;
			}
			if (Object.op_Implicit((Object)(object)_viewmodel))
			{
				_viewmodel.SetCharge(num);
			}
			ModSounds.SetLoop(ModSounds.PiercerChargeLoop, ((EntityState)this).gameObject, 0.25f + num * 0.5f, Mathf.Max(0.05f, num * 0.5f));
			if (!_fullyCharged && ((EntityState)this).fixedAge >= _chargeDuration)
			{
				_fullyCharged = true;
				ModSounds.Play(ModSounds.PiercerCharged, ((EntityState)this).gameObject);
			}
			if (((EntityState)this).isAuthority && !((BaseSkillState)this).IsKeyDownAuthority())
			{
				if (_fullyCharged)
				{
					((EntityState)this).outer.SetNextState((EntityState)(object)new RevolverPiercerFire
					{
						IsCharged = true
					});
				}
				else
				{
					((EntityState)this).outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			ModSounds.StopLoop(ModSounds.PiercerChargeLoop, ((EntityState)this).gameObject);
			if (Object.op_Implicit((Object)(object)_weaponManager))
			{
				_weaponManager.PiercerCharge = 0f;
			}
			if (Object.op_Implicit((Object)(object)_viewmodel))
			{
				_viewmodel.SetCharge(-1f);
			}
			((EntityState)this).OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class RevolverPiercerFire : BaseSkillState
	{
		public static float BaseDuration = 0.5f;

		public static float DamageCoefficient = 2.5f;

		public static float ChargedDamageCoefficient = 7.5f;

		public bool IsCharged;

		private float _duration;

		private DamageSource Source
		{
			get
			{
				if (IsCharged)
				{
					return (DamageSource)2;
				}
				return (DamageSource)1;
			}
		}

		public override void OnEnter()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).OnEnter();
			_duration = BaseDuration / ((BaseState)this).attackSpeedStat;
			V1WeaponManager component = ((EntityState)this).GetComponent<V1WeaponManager>();
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)component))
			{
				component.LockGun(_duration);
				if (IsCharged)
				{
					component.PiercerBeamCharge = 0f;
				}
			}
			ModSounds.Play(IsCharged ? ModSounds.PiercerChargedFire : ModSounds.PiercerFire, ((EntityState)this).gameObject);
			if (IsCharged)
			{
				V1ViewmodelController component2 = ((EntityState)this).GetComponent<V1ViewmodelController>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					component2.ClearCharge();
				}
			}
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, IsCharged ? "FireCharged" : "Fire");
			if (!ModAssets.HasUltrakillBeams)
			{
				V1ViewmodelController.TryMuzzleFlash(((EntityState)this).gameObject, IsCharged ? ModAssets.PiercerChargedColor : ModAssets.PiercerColor, IsCharged ? 0.35f : 0.18f);
			}
			Ray aimRay = ((BaseState)this).GetAimRay();
			FireRevolver(aimRay);
		}

		private void FireRevolver(Ray aimRay)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: 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)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Expected O, but got Unknown
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).StartAimMode(aimRay, 2f, false);
			if (!((EntityState)this).isAuthority)
			{
				return;
			}
			float maxDistance = FirstStopDistance(aimRay, IsCharged);
			V1CoreEject v1CoreEject = V1CoreEject.FindOnRay(aimRay, maxDistance);
			float distance;
			CoinController coinController = CoinController.FindOnRay(aimRay, maxDistance, out distance);
			float num = (Object.op_Implicit((Object)(object)v1CoreEject) ? Vector3.Distance(((Ray)(ref aimRay)).origin, ((Component)v1CoreEject).transform.position) : float.MaxValue);
			GameObject val = (IsCharged ? ModAssets.PiercerChargedTracer : ModAssets.PiercerTracer);
			float num2 = ((BaseState)this).damageStat * (IsCharged ? ChargedDamageCoefficient : DamageCoefficient);
			bool flag = ((BaseState)this).RollCrit();
			List<(V1Magnet, float)> list = V1Magnet.FindOnRay(aimRay, maxDistance);
			float num3 = ((list.Count > 0) ? list[0].Item2 : float.MaxValue);
			if (IsCharged)
			{
				foreach (var item2 in list)
				{
					item2.Item1.Shoot();
				}
			}
			else if (num3 < Mathf.Min(distance, num))
			{
				V1Magnet item = list[0].Item1;
				if (Object.op_Implicit((Object)(object)val))
				{
					EffectManager.SpawnEffect(val, new EffectData
					{
						origin = item.Center,
						start = ((Ray)(ref aimRay)).origin
					}, true);
				}
				item.Shoot();
				return;
			}
			if (Object.op_Implicit((Object)(object)v1CoreEject) && (!Object.op_Implicit((Object)(object)coinController) || num < distance))
			{
				if (IsCharged)
				{
					FirePiercingSegment(aimRay, num, num2, flag);
				}
				else if (Object.op_Implicit((Object)(object)val))
				{
					EffectManager.SpawnEffect(val, new EffectData
					{
						origin = ((Component)v1CoreEject).transform.position,
						start = ((Ray)(ref aimRay)).origin
					}, true);
				}
				V1Explosions.RequestCoreDetonation(v1CoreEject, ((EntityState)this).gameObject);
				V1Hitstop component = ((EntityState)this).GetComponent<V1Hitstop>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.ParryFlash();
				}
				return;
			}
			if (Object.op_Implicit((Object)(object)coinController))
			{
				if (IsCharged)
				{
					FirePiercingSegment(aimRay, distance, num2, flag);
				}
				else if (Object.op_Implicit((Object)(object)val))
				{
					EffectManager.SpawnEffect(val, new EffectData
					{
						origin = ((Component)coinController).transform.position,
						start = ((Ray)(ref aimRay)).origin
					}, true);
				}
				coinController.HitByShot(new CoinController.CoinShot
				{
					Attacker = ((EntityState)this).gameObject,
					Kind = (IsCharged ? CoinController.ShotKind.Piercing : CoinController.ShotKind.Revolver),
					Source = Source,
					BeamDamage = num2
				});
				return;
			}
			BulletAttack val2 = new BulletAttack
			{
				owner = ((EntityState)this).gameObject,
				weapon = ((EntityState)this).gameObject,
				origin = ((Ray)(ref aimRay)).origin,
				aimVector = ((Ray)(ref aimRay)).direction,
				minSpread = 0f,
				maxSpread = 0f,
				damage = num2,
				damageType = DamageTypeCombo.op_Implicit(Source),
				force = 800f,
				tracerEffectPrefab = (IsCharged ? ModAssets.PiercerChargedTracer : ModAssets.PiercerTracer),
				hitEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/HitsparkBandit2Pistol"),
				isCrit = flag,
				procCoefficient = 1f,
				maxDistance = 500f,
				smartCollision = true,
				muzzleName = "MuzzleRight"
			};
			LayerMask stopperMask;
			if (!IsCharged)
			{
				stopperMask = BulletAttack.defaultStopperMask;
			}
			else
			{
				LayerIndex world = LayerIndex.world;
				stopperMask = ((LayerIndex)(ref world)).mask;
			}
			val2.stopperMask = stopperMask;
			val2.Fire();
		}

		private float FirstStopDistance(Ray aimRay, bool piercing)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			LayerIndex val = LayerIndex.world;
			int num = LayerMask.op_Implicit(((LayerIndex)(ref val)).mask);
			int num2;
			if (!piercing)
			{
				val = LayerIndex.entityPrecise;
				num2 = LayerMask.op_Implicit(((LayerIndex)(ref val)).mask);
			}
			else
			{
				num2 = 0;
			}
			int num3 = num | num2;
			RaycastHit[] array = Physics.RaycastAll(aimRay, 500f, num3, (QueryTriggerInteraction)2);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			TeamIndex val2 = (TeamIndex)((!Object.op_Implicit((Object)(object)((EntityState)this).teamComponent)) ? 1 : ((int)((EntityState)this).teamComponent.teamIndex));
			RaycastHit[] array2 = array;
			for (int num4 = 0; num4 < array2.Length; num4++)
			{
				RaycastHit val3 = array2[num4];
				val = LayerIndex.world;
				if ((LayerMask.op_Implicit(((LayerIndex)(ref val)).mask) & (1 << ((Component)((RaycastHit)(ref val3)).collider).gameObject.layer)) != 0)
				{
					if (!((RaycastHit)(ref val3)).collider.isTrigger)
					{
						return ((RaycastHit)(ref val3)).distance;
					}
					continue;
				}
				HurtBox component = ((Component)((RaycastHit)(ref val3)).collider).GetComponent<HurtBox>();
				if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.healthComponent) && (Object)(object)((Component)component.healthComponent).gameObject != (Object)(object)((EntityState)this).gameObject && component.teamIndex != val2)
				{
					return ((RaycastHit)(ref val3)).distance;
				}
			}
			return 500f;
		}

		private void FirePiercingSegment(Ray aimRay, float distance, float damage, bool crit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			BulletAttack val = new BulletAttack
			{
				owner = ((EntityState)this).gameObject,
				weapon = ((EntityState)this).gameObject,
				origin = ((Ray)(ref aimRay)).origin,
				aimVector = ((Ray)(ref aimRay)).direction,
				minSpread = 0f,
				maxSpread = 0f,
				damage = damage,
				damageType = DamageTypeCombo.op_Implicit(Source),
				force = 800f,
				tracerEffectPrefab = ModAssets.PiercerChargedTracer,
				hitEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/HitsparkBandit2Pistol"),
				isCrit = crit,
				procCoefficient = 1f,
				maxDistance = distance,
				smartCollision = true,
				muzzleName = "MuzzleRight"
			};
			LayerIndex world = LayerIndex.world;
			val.stopperMask = ((LayerIndex)(ref world)).mask;
			val.Fire();
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (((EntityState)this).fixedAge >= _duration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class SawbladeFire : BaseSkillState
	{
		public const float AttractorDamage = 1.875f;

		public const float OverheatDamage = 1.5f;

		public const float AttractorHits = 3.9f;

		public const float MaxSpread = 45f;

		private V1Nailgun _nailgun;

		private bool _overheat;

		private float _timer;

		private bool _wasEmpty;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			_nailgun = ((EntityState)this).GetComponent<V1Nailgun>();
			V1WeaponManager component = ((EntityState)this).GetComponent<V1WeaponManager>();
			_overheat = Object.op_Implicit((Object)(object)component) && component.CurrentWeapon == V1WeaponManager.WeaponType.SawbladeOverheat;
			if (Object.op_Implicit((Object)(object)_nailgun))
			{
				if (_overheat)
				{
					_nailgun.SawFiring = true;
				}
				else
				{
					_nailgun.Firing = true;
				}
			}
			_timer = 0f;
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			((BaseState)this).StartAimMode(1f, false);
			if (!((EntityState)this).isAuthority || !Object.op_Implicit((Object)(object)_nailgun))
			{
				return;
			}
			if (!((BaseSkillState)this).IsKeyDownAuthority())
			{
				((EntityState)this).outer.SetNextStateToMain();
				return;
			}
			_timer -= Time.fixedDeltaTime;
			while (_timer <= 0f)
			{
				float num = _nailgun.SawInterval(_overheat) / Mathf.Max(0.1f, ((BaseState)this).attackSpeedStat);
				if (!_overheat && _nailgun.Saws < 1f)
				{
					ModSounds.Play(ModSounds.WeaponSwap, ((EntityState)this).gameObject, _wasEmpty ? 0.7f : 1f);
					_wasEmpty = true;
					_timer += num * 2f;
				}
				else
				{
					_wasEmpty = false;
					FireSaw();
					_timer += num;
				}
			}
		}

		private void FireSaw()
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: 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_01d7: 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_01fd: 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)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			_nailgun.RecordShot();
			_nailgun.LastSawShot = Time.time;
			ModSounds.Play(ModSounds.SawFire, ((EntityState)this).gameObject, Random.Range(0.95f, 1.05f));
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Fire");
			V1ViewmodelController.TryUltrakillMuzzleFlash(((EntityState)this).gameObject, ModAssets.UkSawMuzzleTemplate, 0.6f, 0.8f, withLight: false);
			float num = 0f;
			float hitAmount = 3.9f;
			GameObject val = ModAssets.UkSawTemplate;
			float damageCoefficient = 1.875f;
			if (_overheat)
			{
				bool num2 = _nailgun.SawHeatSinks >= 1f;
				num = (num2 ? Mathf.Lerp(0f, 45f, Mathf.Max(0f, _nailgun.SawHeat - 0.25f)) : 45f);
				hitAmount = (num2 ? Mathf.Lerp(3f, 1f, _nailgun.SawHeat) : 1f);
				val = (Object.op_Implicit((Object)(object)ModAssets.UkSawOverheatTemplate) ? ModAssets.UkSawOverheatTemplate : val);
				damageCoefficient = 1.5f;
				if (num2)
				{
					_nailgun.SawHeat = Mathf.MoveTowards(_nailgun.SawHeat, 1f, 0.125f);
				}
			}
			else
			{
				_nailgun.Saws -= 1f;
			}
			Ray aimRay = ((BaseState)this).GetAimRay();
			float num3 = num / 3f;
			Quaternion val2 = Quaternion.Euler(Random.Range(0f - num3, num3), Random.Range(0f - num3, num3), 0f);
			Vector3 val3 = Util.QuaternionSafeLookRotation(((Ray)(ref aimRay)).direction) * val2 * Vector3.forward;
			Vector3 position = ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * 0.52f;
			Ray val4 = aimRay;
			LayerIndex world = LayerIndex.world;
			if (Physics.Raycast(val4, 0.52f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
			{
				position = ((Ray)(ref aimRay)).origin;
			}
			V1Sawblade v1Sawblade = V1Sawblade.Spawn(((EntityState)this).gameObject, val, position, val3 * 104f, ((BaseState)this).RollCrit(), damageCoefficient);
			v1Sawblade.HitAmount = hitAmount;
			v1Sawblade.FodderDamageBoost = !_overheat;
		}

		public override void OnExit()
		{
			if (Object.op_Implicit((Object)(object)_nailgun))
			{
				if (_overheat)
				{
					_nailgun.SawFiring = false;
				}
				else
				{
					_nailgun.Firing = false;
				}
			}
			((EntityState)this).OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class ShotgunBomb : BaseSkillState
	{
		public const float DamageCoefficient = 6f;

		public const float BaseDuration = 2.0566666f;

		public float Force;

		private float _duration;

		public override void OnEnter()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).OnEnter();
			_duration = Mathf.Min(2.0566666f, 1f) / ((BaseState)this).attackSpeedStat;
			ModSounds.Play(ModSounds.CoreEject, ((EntityState)this).gameObject);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Secondary Fire");
			V1ViewmodelController.TryUltrakillMuzzleFlash(((EntityState)this).gameObject, ModAssets.UkShotgunMuzzleTemplate);
			Ray aimRay = ((BaseState)this).GetAimRay();
			((BaseState)this).StartAimMode(aimRay, 2f, false);
			if (((EntityState)this).isAuthority)
			{
				V1WeaponManager component = ((EntityState)this).GetComponent<V1WeaponManager>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.LastCoreTime = Time.time;
					component.CoreCharges = Mathf.Max(0f, component.CoreCharges - 1f);
					component.GunReadyTime = Time.time + _duration;
				}
				Vector3 val = ((Ray)(ref aimRay)).direction + Vector3.up * (Force * 0.002f);
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				ProjectileManager instance = ProjectileManager.instance;
				FireProjectileInfo val2 = new FireProjectileInfo
				{
					projectilePrefab = (Object.op_Implicit((Object)(object)ModAssets.CoreEjectProjectile) ? ModAssets.CoreEjectProjectile : LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/CommandoGrenadeProjectile")),
					position = ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * 0.5f,
					rotation = Util.QuaternionSafeLookRotation(normalized),
					owner = ((EntityState)this).gameObject,
					damage = ((BaseState)this).damageStat * 6f,
					force = 2000f,
					crit = ((BaseState)this).RollCrit(),
					damageTypeOverride = DamageTypeCombo.op_Implicit((DamageSource)2)
				};
				((FireProjectileInfo)(ref val2)).speedOverride = (Force + 10f) * 0.52f;
				instance.FireProjectile(val2);
			}
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (((EntityState)this).fixedAge >= _duration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class ShotgunCoreCharge : BaseSkillState
	{
		public const float MaxForce = 60f;

		public const float ForcePerSecond = 60f;

		public const float MinTimeBetweenCores = 0.5f;

		private const float MinLoopPitch = 0.05f;

		private float _force;

		private V1WeaponManager _weapons;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			_weapons = ((EntityState)this).GetComponent<V1WeaponManager>();
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)_weapons) && (Time.time - _weapons.LastCoreTime < 0.5f || _weapons.CoreCharges < 1f))
			{
				((EntityState)this).outer.SetNextStateToMain();
				return;
			}
			ModSounds.StartLoop(ModSounds.CoreChargeLoop, ((EntityState)this).gameObject);
			ModSounds.SetLoop(ModSounds.CoreChargeLoop, ((EntityState)this).gameObject, 1f, 0.05f);
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			((BaseState)this).StartAimMode(2f, false);
			_force = Mathf.MoveTowards(_force, 60f, 60f * Time.fixedDeltaTime * ((BaseState)this).attackSpeedStat);
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)_weapons))
			{
				_weapons.CoreCharge = _force / 60f;
			}
			ModSounds.SetLoop(ModSounds.CoreChargeLoop, ((EntityState)this).gameObject, 1f, Mathf.Max(0.05f, _force / 60f));
			if (((EntityState)this).isAuthority && !((BaseSkillState)this).IsKeyDownAuthority())
			{
				((EntityState)this).outer.SetNextState((EntityState)(object)new ShotgunBomb
				{
					Force = _force
				});
			}
		}

		public override void OnExit()
		{
			ModSounds.StopLoop(ModSounds.CoreChargeLoop, ((EntityState)this).gameObject);
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)_weapons))
			{
				_weapons.CoreCharge = 0f;
			}
			((EntityState)this).OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)2;
		}
	}
	public class ShotgunFire : BaseSkillState
	{
		public const float PelletDamageCoefficient = 0.6f;

		public const float PointBlankPellets = 4f;

		public const float PointBlankRange = 2.08f;

		public const float BaseSpread = 10f;

		public const float CoreFireDuration = 1.2120908f;

		public const float PumpFireDuration = 0.9031818f;

		public const float OverpumpDistance = 0.52f;

		public const float OverpumpRadiusMultiplier = 1.5f;

		public const float OverpumpDamageCoefficient = 6f;

		public const int CorePellets = 12;

		public const float PelletProcCoefficient = 0.5f;

		private static readonly int[] PumpPellets = new int[3] { 10, 16, 24 };

		private static readonly float[] PumpSpread = new float[3] { 6.6666665f, 10f, 20f };

		public const float AutoPump1Time = 0.40190908f;

		public const float AutoPump2Time = 0.67736363f;

		private float _duration;

		private bool _pumpVariant;

		private bool _pump1Played;

		private bool _pump2Played;

		public const float OverchargeDamagePerLevel = 0.5f;

		public const float OverchargeRadiusPerLevel = 0.25f;

		public override void OnEnter()
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).OnEnter();
			V1WeaponManager component = ((EntityState)this).GetComponent<V1WeaponManager>();
			bool flag = Object.op_Implicit((Object)(object)component) && component.CurrentWeapon == V1WeaponManager.WeaponType.ShotgunPump;
			_duration = (flag ? 0.9031818f : 1.2120908f) / ((BaseState)this).attackSpeedStat;
			_pumpVariant = flag;
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)component))
			{
				component.LockGun(_duration);
			}
			if (Object.op_Implicit((Object)(object)component))
			{
				component.LastShotgunShot = Time.time;
			}
			ModSounds.Play(ModSounds.ShotgunFire, ((EntityState)this).gameObject);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, flag ? "PumpFire" : "Fire");
			V1ViewmodelController.TryUltrakillMuzzleFlash(((EntityState)this).gameObject, ModAssets.UkShotgunMuzzleTemplate);
			((BaseState)this).StartAimMode(2f, false);
			if (((EntityState)this).isAuthority)
			{
				Ray aimRay = ((BaseState)this).GetAimRay();
				int num = (flag ? component.ShotgunPumps : 0);
				if (flag)
				{
					component.ShotgunPumps = 0;
				}
				if (flag && num >= 3)
				{
					Overpump(aimRay, num - 3);
					return;
				}
				int pellets = (flag ? PumpPellets[num] : 12);
				float spread = (flag ? PumpSpread[num] : 10f);
				FirePellets(aimRay, pellets, spread, 1f);
				FirePointBlank(aimRay);
			}
		}

		private void FirePellets(Ray aimRay, int pellets, float spread, float damageMultiplier)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			Quaternion val = Util.QuaternionSafeLookRotation(((Ray)(ref aimRay)).direction);
			float damage = ((BaseState)this).damageStat * 0.6f * damageMultiplier;
			bool crit = ((BaseState)this).RollCrit();
			for (int i = 0; i < pellets; i++)
			{
				Quaternion val2 = Quaternion.Euler(Random.Range(0f - spread, spread), Random.Range(0f - spread, spread), Random.Range(0f - spread, spread));
				V1ShotgunPellet.Spawn(((EntityState)this).gameObject, ((Ray)(ref aimRay)).origin, val * val2 * Vector3.forward, damage, 0.5f, crit);
			}
		}

		private void FirePointBlank(Ray aimRay)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			BulletAttack val = new BulletAttack
			{
				owner = ((EntityState)this).gameObject,
				weapon = ((EntityState)this).gameObject,
				origin = ((Ray)(ref aimRay)).origin,
				aimVector = ((Ray)(ref aimRay)).direction,
				bulletCount = 1u,
				radius = 0.6f,
				damage = ((BaseState)this).damageStat * 0.6f * 4f,
				damageType = DamageTypeCombo.op_Implicit((DamageSource)1),
				force = 1500f,
				isCrit = ((BaseState)this).RollCrit(),
				procCoefficient = 1f,
				maxDistance = 2.08f
			};
			LayerIndex world = LayerIndex.world;
			val.stopperMask = ((LayerIndex)(ref world)).mask;
			val.smartCollision = true;
			val.Fire();
		}

		private void Overpump(Ray aimRay, int overcharge)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.52f;
			Ray val = aimRay;
			LayerIndex world = LayerIndex.world;
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(val, ref val2, 0.52f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
			{
				num = Mathf.Max(0f, ((RaycastHit)(ref val2)).distance - 0.1f);
			}
			V1Explosions.RequestExplosion(((EntityState)this).gameObject, ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * num, 10.5f * (1f + (float)overcharge * 0.25f), ((BaseState)this).damageStat * 6f * (1f + (float)overcharge * 0.5f), ((BaseState)this).RollCrit(), overcharge > 0, 0.5f, (DamageSource)1);
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (_pumpVariant)
			{
				float num = ((EntityState)this).fixedAge * ((BaseState)this).attackSpeedStat;
				if (!_pump1Played && num >= 0.40190908f)
				{
					_pump1Played = true;
					ShotgunPump.PlayPump1(((EntityState)this).gameObject, 0);
				}
				if (!_pump2Played && num >= 0.67736363f)
				{
					_pump2Played = true;
					ModSounds.Play(ModSounds.ShotgunPump, ((EntityState)this).gameObject, Random.Range(0.95f, 1.05f));
				}
			}
			if (((EntityState)this).fixedAge >= _duration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class ShotgunPump : BaseSkillState
	{
		public const int MaxPumps = 3;

		public const float BaseDuration = 0.38818184f;

		public const float Pump1SoundTime = 0.061030302f;

		public const float Pump2SoundTime = 0.30503032f;

		private float _duration;

		private bool _pump1Played;

		private bool _pump2Played;

		private int _pumps;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			_duration = 0.38818184f / ((BaseState)this).attackSpeedStat;
			V1WeaponManager component = ((EntityState)this).GetComponent<V1WeaponManager>();
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)component))
			{
				component.LockGun(_duration);
			}
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)component) && component.ShotgunPumps < component.MaxPumps)
			{
				component.ShotgunPumps++;
				if (component.ShotgunPumps >= 3)
				{
					ModSounds.Play(ModSounds.OverpumpBeep, ((EntityState)this).gameObject, 1f + (float)component.Overcharge * 0.15f);
				}
			}
			_pumps = ((!Object.op_Implicit((Object)(object)component)) ? 1 : component.ShotgunPumps);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "Pump");
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			float num = ((EntityState)this).fixedAge * ((BaseState)this).attackSpeedStat;
			if (!_pump1Played && num >= 0.061030302f)
			{
				_pump1Played = true;
				PlayPump1(((EntityState)this).gameObject, _pumps);
			}
			if (!_pump2Played && num >= 0.30503032f)
			{
				_pump2Played = true;
				ModSounds.Play(ModSounds.ShotgunPump, ((EntityState)this).gameObject, Random.Range(0.95f, 1.05f));
			}
			if (((EntityState)this).fixedAge >= _duration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public static void PlayPump1(GameObject source, int pumps)
		{
			ModSounds.Play(ModSounds.ShotgunPump1, source, Random.Range(0.95f, 1.05f));
			ModSounds.Play(ModSounds.ShotgunPumpCharge, source, 1f + (float)pumps / 5f);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class SuperSaw : BaseSkillState
	{
		public const float DamageCoefficient = 2.5f;

		public const float Hits = 20.9f;

		public const float Duration = 0.2f;

		public override void OnEnter()
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			((BaseState)this).OnEnter();
			if (!((EntityState)this).isAuthority)
			{
				return;
			}
			V1Nailgun component = ((EntityState)this).GetComponent<V1Nailgun>();
			if (!Object.op_Implicit((Object)(object)component) || component.SawHeatSinks < 1f || component.SawHeat < 0.1f)
			{
				ModSounds.Play(ModSounds.WeaponSwap, ((EntityState)this).gameObject, 0.7f);
				return;
			}
			int num = Mathf.RoundToInt(component.SawHeat * 3f);
			component.SawHeatSinks -= 1f;
			component.SawHeat = 0f;
			component.LastSawShot = Time.time;
			ModSounds.Play(ModSounds.SawFire, ((EntityState)this).gameObject, 0.8f, 1.3f);
			V1ViewmodelController.TryTrigger(((EntityState)this).gameObject, "SuperShoot");
			V1ViewmodelController.TryUltrakillMuzzleFlash(((EntityState)this).gameObject, ModAssets.UkSawMuzzle2Template, 0.8f, 1f, withLight: true, 0.12f);
			((BaseState)this).AddRecoil(-1.5f, -2f, -0.5f, 0.5f);
			Ray aimRay = ((BaseState)this).GetAimRay();
			((BaseState)this).StartAimMode(aimRay, 2f, false);
			Vector3 position = ((Ray)(ref aimRay)).origin + ((Ray)(ref aimRay)).direction * 0.52f;
			Ray val = aimRay;
			LayerIndex world = LayerIndex.world;
			if (Physics.Raycast(val, 0.52f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1))
			{
				position = ((Ray)(ref aimRay)).origin;
			}
			GameObject template = (Object.op_Implicit((Object)(object)ModAssets.UkSawHeatedTemplate) ? ModAssets.UkSawHeatedTemplate : ModAssets.UkSawOverheatTemplate);
			V1Sawblade v1Sawblade = V1Sawblade.Spawn(((EntityState)this).gameObject, template, position, ((Ray)(ref aimRay)).direction * 104f, ((BaseState)this).RollCrit(), 2.5f);
			v1Sawblade.HitAmount = 20.9f;
			v1Sawblade.MultiHitAmount = Mathf.Max(1, num);
			v1Sawblade.BounceToSurfaceNormal = true;
			v1Sawblade.Heated = true;
			v1Sawblade.Source = (DamageSource)2;
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (((EntityState)this).isAuthority && ((EntityState)this).fixedAge >= 0.2f)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)1;
		}
	}
	public class V1DashState : BaseSkillState
	{
		public static float BaseDuration = 0.25f;

		public override void OnEnter()
		{
			((BaseState)this).OnEnter();
			V1MovementController component = ((EntityState)this).GetComponent<V1MovementController>();
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)component))
			{
				component.TryDash();
			}
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			if (((EntityState)this).fixedAge >= BaseDuration && ((EntityState)this).isAuthority)
			{
				((EntityState)this).outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)2;
		}
	}
	public class V1MainState : GenericCharacterMain
	{
		private V1MovementController _movementController;

		private V1Hitstop _hitstop;

		private bool IsFrozen
		{
			get
			{
				if (Object.op_Implicit((Object)(object)_hitstop))
				{
					return _hitstop.IsFrozen;
				}
				return false;
			}
		}

		public override void OnEnter()
		{
			((GenericCharacterMain)this).OnEnter();
			_movementController = ((EntityState)this).GetComponent<V1MovementController>();
			_hitstop = ((EntityState)this).GetComponent<V1Hitstop>();
		}

		public override void HandleMovements()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (IsFrozen)
			{
				if (((BaseCharacterMain)this).hasCharacterMotor)
				{
					((EntityState)this).characterMotor.moveDirection = Vector3.zero;
				}
			}
			else
			{
				((GenericCharacterMain)this).HandleMovements();
			}
		}

		public override void GatherInputs()
		{
			((GenericCharacterMain)this).GatherInputs();
			base.sprintInputReceived = false;
		}

		public override void FixedUpdate()
		{
			((GenericCharacterMain)this).FixedUpdate();
			if (((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)((EntityState)this).characterBody) && Object.op_Implicit((Object)(object)_movementController))
			{
				((EntityState)this).characterBody.isSprinting = _movementController.IsSliding;
			}
		}

		public override void ProcessJump()
		{
			if (IsFrozen)
			{
				base.jumpInputReceived = false;
				return;
			}
			if (base.jumpInputReceived && ((BaseCharacterMain)this).hasCharacterMotor && Object.op_Implicit((Object)(object)_movementController) && ((EntityState)this).isAuthority)
			{
				if (_movementController.TryJump() || _movementController.TryWallJump())
				{
					base.jumpInputReceived = false;
					return;
				}
				if (!((EntityState)this).characterMotor.isGrounded && ((EntityState)this).characterMotor.jumpCount == 0)
				{
					((EntityState)this).characterMotor.jumpCount = 1;
				}
			}
			((GenericCharacterMain)this).ProcessJump();
		}
	}
	public class V1ParryFreezeState : EntityState
	{
		public float Duration = 0.25f;

		private Animator _animator;

		private float _animatorSpeed = 1f;

		private bool _gravityDisabled;

		public static void Apply(CharacterBody body, float duration)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)body) || body.isPlayerControlled || duration <= 0f)
			{
				return;
			}
			SetStateOnHurt component = ((Component)body).GetComponent<SetStateOnHurt>();
			if (!Object.op_Implicit((Object)(object)component) || !component.canBeStunned || !Object.op_Implicit((Object)(object)component.targetStateMachine))
			{
				return;
			}
			component.targetStateMachine.SetInterruptState((EntityState)(object)new V1ParryFreezeState
			{
				Duration = duration
			}, (InterruptPriority)7);
			if (component.idleStateMachine == null)
			{
				return;
			}
			EntityStateMachine[] idleStateMachine = component.idleStateMachine;
			foreach (EntityStateMachine val in idleStateMachine)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					val.SetNextState((EntityState)new Idle());
				}
			}
		}

		public override void OnEnter()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			((EntityState)this).OnEnter();
			_animator = ((EntityState)this).GetModelAnimator();
			if (Object.op_Implicit((Object)(object)_animator))
			{
				_animatorSpeed = _animator.speed;
				_animator.speed = 0f;
			}
			if (Object.op_Implicit((Object)(object)((EntityState)this).characterMotor))
			{
				CharacterGravityParameters gravityParameters = ((EntityState)this).characterMotor.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount++;
				((EntityState)this).characterMotor.gravityParameters = gravityParameters;
				_gravityDisabled = true;
			}
			Hold();
		}

		public override void FixedUpdate()
		{
			((EntityState)this).FixedUpdate();
			Hold();
			if (((EntityState)this).isAuthority && ((EntityState)this).fixedAge >= Duration)
			{
				base.outer.SetNextStateToMain();
			}
		}

		private void Hold()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)((EntityState)this).characterMotor))
			{
				((EntityState)this).characterMotor.velocity = Vector3.zero;
				((EntityState)this).characterMotor.moveDirection = Vector3.zero;
			}
			if (Object.op_Implicit((Object)(object)((EntityState)this).rigidbodyMotor))
			{
				((EntityState)this).rigidbodyMotor.moveVector = Vector3.zero;
			}
			if (Object.op_Implicit((Object)(object)((EntityState)this).rigidbody) && !((EntityState)this).rigidbody.isKinematic)
			{
				((EntityState)this).rigidbody.velocity = Vector3.zero;
			}
		}

		public override void OnExit()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_animator))
			{
				_animator.speed = _animatorSpeed;
			}
			if (_gravityDisabled && Object.op_Implicit((Object)(object)((EntityState)this).characterMotor))
			{
				CharacterGravityParameters gravityParameters = ((EntityState)this).characterMotor.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount--;
				((EntityState)this).characterMotor.gravityParameters = gravityParameters;
			}
			((EntityState)this).OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			((EntityState)this).OnSerialize(writer);
			writer.Write(Duration);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			((EntityState)this).OnDeserialize(reader);
			Duration = reader.ReadSingle();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return (InterruptPriority)7;
		}
	}
}
namespace UltrakillV1.Modules
{
	public static class ModAssets
	{
		public static class Names
		{
			public const string BodyModel = "mdlV1";

			public const string DisplayModel = "mdlV1Display";

			public const string Viewmodel = "V1Viewmodel";

			public const string CoinModel = "mdlV1Coin";

			public const string CoreEjectGhost = "V1CoreEjectGhost";

			public const string PiercerTracer = "V1PiercerTracer";

			public const string PiercerChargedTracer = "V1PiercerChargedTracer";

			public const string CoinRicochetTracer = "V1CoinRicochetTracer";

			public const string NailTracer = "V1NailTracer";

			public const string SlamShockwave = "V1SlamShockwave";

			public const string Portrait = "texV1Icon";

			public const string UkRevolverBeam = "ukfx_RevolverBeam";

			public const string UkRevolverBeamSuper = "ukfx_RevolverBeamSuper";

			public const string UkRicochetBeam = "ukfx_RicochetBeam";

			public const string UkCoinFlash = "ukfx_CoinFlash";

			public const string UkDodge = "ukfx_Dodge";

			public const string UkSlide = "ukfx_Slide";

			public const string UkFall = "ukfx_Fall";

			public const string UkDustBig = "ukfx_DustBig";

			public const string UkShockwave = "ukfx_Shockwave";

			public const string UkShotgunMuzzle = "ukfx_ShotgunMuzzle";

			public const string UkNailgunMuzzle = "ukfx_NailgunMuzzle";

			public const string UkExplosion = "ukfx_Explosion";

			public const string UkExplosionSuper = "ukfx_ExplosionSuper";

			public const string UkShotgunPellet = "ukfx_ShotgunPellet";

			public const string UkBulletSpark = "ukfx_BulletSpark";

			public const string UkNail = "ukfx_Nail";

			public const string UkMagnet = "ukfx_Magnet";

			public const string UkNailHeated = "ukfx_NailHeated";

			public const string UkNailgunMuzzle2 = "ukfx_NailgunMuzzle2";

			public const string UkRailcannonBeam = "ukfx_RailcannonBeam";

			public const string UkSaw = "ukfx_Saw";

			public const string UkSawOverheat = "ukfx_SawOverheat";

			public const string UkSawHeated = "ukfx_SawHeated";

			public const string UkSawMuzzle = "ukfx_SawMuzzle";

			public const string UkSawMuzzle2 = "ukfx_SawMuzzle2";

			public const string UkSawBounce = "ukfx_SawBounce";

			public const string UkSawBreak = "ukfx_SawBreak";

			public const string UkRailcannonHit = "ukfx_RailcannonHit";

			public const string UkZapImpact = "ukfx_ZapImpact";
		}

		public static AssetBundle MainAssetBundle;

		public const string BundleName = "ultrakillv1.bundle";

		public static readonly Color PiercerColor = new Color(0.25f, 0.9f, 1f);

		public static readonly Color PiercerChargedColor = new Color(1f, 0.15f, 0.1f);

		public static readonly Color RicochetColor = new Color(1f, 0.85f, 0.25f);

		public static readonly Color NailColor = new Color(0.75f, 0.85f, 1f);

		public static readonly Color CoreEjectColor = new Color(1f, 0.55f, 0.1f);

		public static readonly Color SlamColor = new Color(1f, 0.8f, 0.2f);

		public static GameObject BodyModelPrefab;

		public static GameObject DisplayModelPrefab;

		public static GameObject ViewmodelPrefab;

		public static Texture2D PortraitIcon;

		public static GameObject CoinPrefab;

		public static GameObject PiercerTracer;

		public static GameObject PiercerChargedTracer;

		public static GameObject CoinRicochetTracer;

		public static GameObject NailTracer;

		public static GameObject RailcannonTracer;

		public static GameObject RailcannonRicochetTracer;

		public static GameObject RailcannonHitEffect;

		public static GameObject ZapImpactEffect;

		public static GameObject ElectricArcTracer;

		public static GameObject SlamShockwaveEffect;

		public static GameObject CoreEjectProjectile;

		public const float WorldFxScale = 0.52f;

		public static GameObject UkDodgeEffect;

		public static GameObject UkDustEffect;

		public static GameObject UkShockwaveEffect;

		public static GameObject UkExplosionEffect;

		public static GameObject UkExplosionSuperEffect;

		public static GameObject UkShotgunPelletTemplate;

		public static GameObject UkBulletSparkEffect;

		public static GameObject UkNailTemplate;

		public static GameObject UkMagnetTemplate;

		public static GameObject UkNailHeatedTemplate;

		public static GameObject UkNailgunMuzzle2Template;

		public static GameObject UkSawTemplate;

		public static GameObject UkSawOverheatTemplate;

		public static GameObject UkSawHeatedTemplate;

		public static GameObject UkSawMuzzleTemplate;

		public static GameObject UkSawMuzzle2Template;

		public static GameObject UkSawBounceEffect;

		public static GameObject UkSawBreakEffect;

		public static GameObject UkSlideTemplate;

		public static GameObject UkFallTemplate;

		public static GameObject UkCoinFlashTemplate;

		public static GameObject UkShotgunMuzzleTemplate;

		public static GameObject UkNailgunMuzzleTemplate;

		private static GameObject _ukRevolverBeam;

		private static GameObject _ukRevolverBeamSuper;

		private static GameObject _ukRailcannonBeam;

		private static GameObject _ukRicochetBeam;

		public static Material V1BluePlatingMaterial;

		public static Material V1WingsMaterial;

		private static Shader _hgStandard;

		private static readonly Dictionary<Material, Material> ConvertedMaterials = new Dictionary<Material, Material>();

		public const float CoinVisualDiameter = 0.5f;

		public static bool HasUltrakillBeams => Object.op_Implicit((Object)(object)_ukRevolverBeam);

		private static Shader HGStandard
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)_hgStandard))
				{
					_hgStandard = LoadShader("RoR2/Base/Shaders/HGStandard.shader");
				}
				return _hgStandard;
			}
		}

		public static void Init()
		{
			RunStep("LoadAssetBundle", LoadAssetBundle);
			RunStep("CreateMaterials", CreateMaterials);
			RunStep("LoadCharacterVisuals", LoadCharacterVisuals);
			RunStep("LoadUltrakillEffects", LoadUltrakillEffects);
			RunStep("CreateTracers", CreateTracers);
			RunStep("CreateCoinPrefab", CreateCoinPrefab);
			RunStep("CreateSlamShockwave", CreateSlamShockwave);
			RunStep("CreateCoreEjectProjectile", CreateCoreEjectProjectile);
		}

		private static void RunStep(string name, Action step)
		{
			try
			{
				step();
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[UltrakillV1] Asset step " + name + " failed: " + ex));
			}
		}

		private static void LoadAssetBundle()
		{
			string bundlePath = V1AssetSetup.BundlePath;
			if (!string.IsNullOrEmpty(bundlePath) && File.Exists(bundlePath))
			{
				MainAssetBundle = AssetBundle.LoadFromFile(bundlePath);
				if (Object.op_Implicit((Object)(object)MainAssetBundle))
				{
					Debug.Log((object)("[UltrakillV1] Loaded AssetBundle from " + bundlePath));
				}
				else
				{
					Debug.LogWarning((object)("[UltrakillV1] Could not load " + bundlePath + ". Using procedural fallbacks."));
				}
			}
			else
			{
				Debug.LogWarning((object)"[UltrakillV1] ULTRAKILL assets not set up yet. Using procedural fallbacks (run the setup from the title screen).");
			}
		}

		public static T LoadAsset<T>(string name) where T : Object
		{
			if (!Object.op_Implicit((Object)(object)MainAssetBundle))
			{
				return default(T);
			}
			return MainAssetBundle.LoadAsset<T>(name);
		}

		public static GameObject LoadBundlePrefab(string name)
		{
			GameObject val = ModAssets.LoadAsset<GameObject>(name);
			if (Object.op_Implicit((Object)(object)val))
			{
				ConvertMaterials(val);
			}
			return val;
		}

		private static Shader LoadShader(string address)
		{
			//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)
			try
			{
				return Addressables.LoadAssetAsync<Shader>((object)address).WaitForCompletion();
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[UltrakillV1] Could not load shader " + address + ": " + ex.Message));
				return null;
			}
		}

		public static void ConvertMaterials(GameObject root)
		{
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					sharedMaterials[j] = ConvertMaterial(sharedMaterials[j]);
				}
				val.sharedMaterials = sharedMaterials;
			}
		}

		private static Material ConvertMaterial(Material material)
		{
			//IL_00f7: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_017a: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)material) || !Object.op_Implicit((Object)(object)material.shader))
			{
				return material;
			}
			if (ConvertedMaterials.TryGetValue(material, out var value))
			{
				return value;
			}
			string name = ((Object)material.shader).name;
			if (name.StartsWith("Stubbed"))
			{
				Shader val = LoadShader(name.Substring("Stubbed".Length) + ".shader");
				if (Object.op_Implicit((Object)(object)val))
				{
					material.shader = val;
				}
			}
			else if (name == "Standard" && Object.op_Implicit((Object)(object)HGStandard))
			{
				Texture texture = material.GetTexture("_MainTex");
				Texture val2 = (material.HasProperty("_BumpMap") ? material.GetTexture("_BumpMap") : null);
				Tex

plugins\UltrakillV1.Setup.Core.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using AssetsTools.NET;
using AssetsTools.NET.Extra;
using AssetsTools.NET.Extra.Decompressors.LZ4;
using LZ4ps;
using Microsoft.CodeAnalysis;
using NVorbis;
using NVorbis.Ogg;
using SevenZip;
using SevenZip.Compression.LZ;
using SevenZip.Compression.LZMA;
using SevenZip.Compression.RangeCoder;
using UltrakillV1.Setup.Audio;
using UltrakillV1.Setup.Imaging;
using UltrakillV1.Setup.Json;
using UltrakillV1.Setup.Render;
using UltrakillV1.Setup.Unity;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("UltrakillV1.Setup.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("UltrakillV1.Setup.Core")]
[assembly: AssemblyTitle("UltrakillV1.Setup.Core")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[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 UltrakillV1.Setup.Unity
{
	public static class CopyRules
	{
		private static readonly HashSet<string> TextureKeep = new HashSet<string>
		{
			"m_Name", "m_ForcedFallbackFormat", "m_DownscaleFallback", "m_IsAlphaChannelOptional", "m_IsReadable", "m_IsPreProcessed", "m_IgnoreMasterTextureLimit", "m_IgnoreMipmapLimit", "m_MipmapLimitGroupName", "m_StreamingMipmaps",
			"m_StreamingMipmapsPriority", "m_TextureSettings", "m_LightmapFormat", "m_ColorSpace", "m_PlatformBlob"
		};

		private static readonly HashSet<string> MeshKeep = new HashSet<string> { "m_Name", "m_IsReadable", "m_KeepVertices", "m_KeepIndices" };

		private static readonly HashSet<string> NameOnly = new HashSet<string> { "m_Name" };

		public static readonly AssetClassID[] CopiedTypes = new AssetClassID[5]
		{
			AssetClassID.Texture2D,
			AssetClassID.Mesh,
			AssetClassID.AnimationClip,
			AssetClassID.Avatar,
			AssetClassID.AnimatorController
		};

		public static HashSet<string> KeepFor(AssetClassID type)
		{
			return type switch
			{
				AssetClassID.Texture2D => TextureKeep, 
				AssetClassID.Mesh => MeshKeep, 
				_ => NameOnly, 
			};
		}

		public static void InlineStreamData(AssetClassID type, AssetTypeValueField target, AssetTypeValueField source, Func<string, long, long, byte[]> readResource)
		{
			AssetTypeValueField assetTypeValueField = source["m_StreamData"];
			if (assetTypeValueField.IsDummy)
			{
				return;
			}
			long asULong = (long)assetTypeValueField["size"].AsULong;
			if (asULong > 0)
			{
				byte[] bytes = readResource(assetTypeValueField["path"].AsString, (long)assetTypeValueField["offset"].AsULong, asULong);
				switch (type)
				{
				case AssetClassID.Texture2D:
					FieldCopier.WriteBytes(target["image data"], bytes);
					break;
				case AssetClassID.Mesh:
					FieldCopier.WriteBytes(target["m_VertexData"]["m_DataSize"], bytes);
					break;
				}
			}
			ClearStream(target);
		}

		public static void Downgrade(AssetClassID type, AssetTypeValueField target)
		{
			if (type != AssetClassID.Mesh)
			{
				return;
			}
			foreach (AssetTypeValueField child in target["m_VertexData"]["m_Channels"]["Array"].Children)
			{
				child["dimension"].AsByte &= 15;
			}
		}

		public static void ClearStream(AssetTypeValueField target)
		{
			AssetTypeValueField assetTypeValueField = target["m_StreamData"];
			if (!assetTypeValueField.IsDummy)
			{
				assetTypeValueField["offset"].AsULong = 0uL;
				assetTypeValueField["size"].AsUInt = 0u;
				assetTypeValueField["path"].AsString = "";
			}
		}
	}
	public sealed class ReferenceMap
	{
		private readonly Dictionary<(string cab, long pathId), long> _map = new Dictionary<(string, long), long>();

		public Func<string, long, long?> Fallback;

		public void Add(string sourceCab, long sourcePathId, long templatePathId)
		{
			_map[(sourceCab.ToLowerInvariant(), sourcePathId)] = templatePathId;
		}

		public Func<int, long, long?> For(AssetsFile sourceFile, string sourceCab)
		{
			return delegate(int fileId, long pathId)
			{
				string text;
				if (fileId == 0)
				{
					text = sourceCab;
				}
				else
				{
					List<AssetsFileExternal> externals = sourceFile.Metadata.Externals;
					if (fileId - 1 >= externals.Count)
					{
						return (long?)null;
					}
					text = Path.GetFileName(externals[fileId - 1].PathName.Replace("archive:/", "").Replace('/', Path.DirectorySeparatorChar));
				}
				long value;
				return _map.TryGetValue((text.ToLowerInvariant(), pathId), out value) ? new long?(value) : Fallback?.Invoke(text, pathId);
			};
		}
	}
	public sealed class FieldCopier
	{
		public Func<int, long, long?> RemapPPtr;

		public HashSet<string> Keep = new HashSet<string>();

		public int DroppedFields { get; private set; }

		public int UnresolvedReferences { get; private set; }

		public void Copy(AssetTypeValueField target, AssetTypeValueField source)
		{
			CopyField(target, source, "");
		}

		private void CopyField(AssetTypeValueField dst, AssetTypeValueField src, string path)
		{
			if (path.Length > 0 && Keep.Contains(path))
			{
				return;
			}
			if (IsPPtr(dst))
			{
				AssetTypeValueField assetTypeValueField = dst["m_FileID"];
				AssetTypeValueField assetTypeValueField2 = dst["m_PathID"];
				long asLong = src["m_PathID"].AsLong;
				if (asLong == 0L)
				{
					assetTypeValueField.AsInt = 0;
					assetTypeValueField2.AsLong = 0L;
					return;
				}
				long? num = RemapPPtr?.Invoke(src["m_FileID"].AsInt, asLong);
				if (num.HasValue)
				{
					assetTypeValueField.AsInt = 0;
					assetTypeValueField2.AsLong = num.Value;
				}
				else
				{
					UnresolvedReferences++;
				}
				return;
			}
			AssetTypeValue value = dst.Value;
			if (value != null && value.ValueType == AssetValueType.ByteArray)
			{
				dst.AsByteArray = ReadBytes(src);
				return;
			}
			if (value != null && value.ValueType == AssetValueType.Array)
			{
				CopyArray(dst, src, path);
				return;
			}
			if (value != null && dst.Children.Count == 0)
			{
				if (src.Value == null)
				{
					DroppedFields++;
				}
				else
				{
					SetScalar(dst, src.Value);
				}
				return;
			}
			foreach (AssetTypeValueField child in dst.Children)
			{
				AssetTypeValueField assetTypeValueField3 = src[child.FieldName];
				if (assetTypeValueField3.IsDummy)
				{
					DroppedFields++;
				}
				else
				{
					CopyField(child, assetTypeValueField3, (path.Length == 0) ? child.FieldName : (path + "." + child.FieldName));
				}
			}
		}

		private void CopyArray(AssetTypeValueField dst, AssetTypeValueField src, string path)
		{
			AssetTypeValueField assetTypeValueField = ((src.Value != null && src.Value.ValueType == AssetValueType.Array) ? src : src["Array"]);
			if (assetTypeValueField.IsDummy)
			{
				AssetTypeValue value = src.Value;
				if (value != null && value.ValueType == AssetValueType.ByteArray)
				{
					assetTypeValueField = src;
				}
			}
			if (assetTypeValueField.Value != null && assetTypeValueField.Value.ValueType == AssetValueType.ByteArray)
			{
				byte[] asByteArray = assetTypeValueField.AsByteArray;
				List<AssetTypeValueField> list = new List<AssetTypeValueField>(asByteArray.Length);
				byte[] array = asByteArray;
				foreach (byte asByte in array)
				{
					AssetTypeValueField assetTypeValueField2 = ValueBuilder.DefaultValueFieldFromArrayTemplate(dst);
					assetTypeValueField2.AsByte = asByte;
					list.Add(assetTypeValueField2);
				}
				dst.Children = list;
				dst.AsArray = new AssetTypeArrayInfo(list.Count);
			}
			else
			{
				int count = assetTypeValueField.Children.Count;
				List<AssetTypeValueField> list2 = new List<AssetTypeValueField>(count);
				for (int j = 0; j < count; j++)
				{
					AssetTypeValueField assetTypeValueField3 = ((j < dst.Children.Count) ? dst.Children[j] : ValueBuilder.DefaultValueFieldFromArrayTemplate(dst));
					CopyField(assetTypeValueField3, assetTypeValueField.Children[j], path + "[]");
					list2.Add(assetTypeValueField3);
				}
				dst.Children = list2;
				dst.AsArray = new AssetTypeArrayInfo(count);
			}
		}

		public static bool IsPPtr(AssetTypeValueField field)
		{
			if (field.TypeName != null && field.TypeName.StartsWith("PPtr<"))
			{
				return !field["m_PathID"].IsDummy;
			}
			return false;
		}

		public static byte[] ReadBytes(AssetTypeValueField field)
		{
			if (field.Value != null && field.Value.ValueType == AssetValueType.ByteArray)
			{
				return field.AsByteArray;
			}
			AssetTypeValueField assetTypeValueField = ((field.Value != null && field.Value.ValueType == AssetValueType.Array) ? field : field["Array"]);
			if (assetTypeValueField.Value != null && assetTypeValueField.Value.ValueType == AssetValueType.ByteArray)
			{
				return assetTypeValueField.AsByteArray;
			}
			byte[] array = new byte[assetTypeValueField.Children.Count];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = assetTypeValueField.Children[i].AsByte;
			}
			return array;
		}

		public static void WriteBytes(AssetTypeValueField field, byte[] bytes)
		{
			if (field.Value != null && field.Value.ValueType == AssetValueType.ByteArray)
			{
				field.AsByteArray = bytes;
				return;
			}
			AssetTypeValueField assetTypeValueField = ((field.Value != null && field.Value.ValueType == AssetValueType.Array) ? field : field["Array"]);
			if (assetTypeValueField.Value != null && assetTypeValueField.Value.ValueType == AssetValueType.ByteArray)
			{
				assetTypeValueField.AsByteArray = bytes;
				return;
			}
			List<AssetTypeValueField> list = new List<AssetTypeValueField>(bytes.Length);
			foreach (byte asByte in bytes)
			{
				AssetTypeValueField assetTypeValueField2 = ValueBuilder.DefaultValueFieldFromArrayTemplate(assetTypeValueField);
				assetTypeValueField2.AsByte = asByte;
				list.Add(assetTypeValueField2);
			}
			assetTypeValueField.Children = list;
			assetTypeValueField.AsArray = new AssetTypeArrayInfo(list.Count);
		}

		private static void SetScalar(AssetTypeValueField dst, AssetTypeValue src)
		{
			object asObject = src.AsObject;
			if (src.ValueType == AssetValueType.String || dst.Value.ValueType == AssetValueType.String)
			{
				dst.Value = src.Clone();
				return;
			}
			if (dst.Value.ValueType == AssetValueType.Float || dst.Value.ValueType == AssetValueType.Double)
			{
				double num = Convert.ToDouble(asObject, CultureInfo.InvariantCulture);
				if (dst.Value.ValueType == AssetValueType.Float)
				{
					dst.AsFloat = (float)num;
				}
				else
				{
					dst.AsDouble = num;
				}
				return;
			}
			long num2 = ((asObject is ulong num3) ? ((long)num3) : ((asObject is bool flag) ? (flag ? 1 : 0) : ((asObject is float num4) ? ((long)num4) : ((asObject is double num5) ? ((long)num5) : Convert.ToInt64(asObject, CultureInfo.InvariantCulture)))));
			switch (dst.Value.ValueType)
			{
			case AssetValueType.Bool:
				dst.AsBool = num2 != 0;
				break;
			case AssetValueType.Int8:
				dst.AsSByte = (sbyte)num2;
				break;
			case AssetValueType.UInt8:
				dst.AsByte = (byte)num2;
				break;
			case AssetValueType.Int16:
				dst.AsShort = (short)num2;
				break;
			case AssetValueType.UInt16:
				dst.AsUShort = (ushort)num2;
				break;
			case AssetValueType.Int32:
				dst.AsInt = (int)num2;
				break;
			case AssetValueType.UInt32:
				dst.AsUInt = (uint)num2;
				break;
			case AssetValueType.Int64:
				dst.AsLong = num2;
				break;
			case AssetValueType.UInt64:
				dst.AsULong = (ulong)num2;
				break;
			default:
				dst.Value = src.Clone();
				break;
			}
		}

		public void Clear(AssetTypeValueField target)
		{
			ClearField(target, "");
		}

		private void ClearField(AssetTypeValueField f, string path)
		{
			if (path.Length > 0 && Keep.Contains(path))
			{
				return;
			}
			if (IsPPtr(f))
			{
				f["m_FileID"].AsInt = 0;
				f["m_PathID"].AsLong = 0L;
				return;
			}
			AssetTypeValue value = f.Value;
			if (value != null && (f.Children.Count == 0 || value.ValueType == AssetValueType.Array || value.ValueType == AssetValueType.ByteArray))
			{
				switch (value.ValueType)
				{
				case AssetValueType.ByteArray:
					f.AsByteArray = Array.Empty<byte>();
					break;
				case AssetValueType.Array:
					f.Children = new List<AssetTypeValueField>();
					f.AsArray = new AssetTypeArrayInfo(0);
					break;
				case AssetValueType.String:
					f.AsString = "";
					break;
				case AssetValueType.Bool:
					f.AsBool = false;
					break;
				case AssetValueType.Float:
					f.AsFloat = 0f;
					break;
				case AssetValueType.Double:
					f.AsDouble = 0.0;
					break;
				default:
					f.Value = new AssetTypeValue(value.ValueType, Convert.ChangeType(0, ClrType(value.ValueType)));
					break;
				}
				return;
			}
			foreach (AssetTypeValueField child in f.Children)
			{
				ClearField(child, (path.Length == 0) ? child.FieldName : (path + "." + child.FieldName));
			}
		}

		private static Type ClrType(AssetValueType t)
		{
			return t switch
			{
				AssetValueType.Int8 => typeof(sbyte), 
				AssetValueType.UInt8 => typeof(byte), 
				AssetValueType.Int16 => typeof(short), 
				AssetValueType.UInt16 => typeof(ushort), 
				AssetValueType.Int32 => typeof(int), 
				AssetValueType.UInt32 => typeof(uint), 
				AssetValueType.Int64 => typeof(long), 
				AssetValueType.UInt64 => typeof(ulong), 
				_ => typeof(int), 
			};
		}
	}
	public sealed class MeshVertexData
	{
		public struct Channel
		{
			public int Stream;

			public int Offset;

			public int Format;

			public int Dimension;

			public bool Present => Dimension > 0;
		}

		public const int Position = 0;

		public const int Normal = 1;

		public const int Tangent = 2;

		public const int Color = 3;

		public const int UV0 = 4;

		public const int BlendWeight = 12;

		public const int BlendIndices = 13;

		public readonly int VertexCount;

		public readonly Channel[] Channels;

		public readonly int[] StreamOffset;

		public readonly int[] StreamStride;

		public byte[] Data;

		public int RequiredSize
		{
			get
			{
				int num = 0;
				for (int i = 0; i < StreamStride.Length; i++)
				{
					num = Math.Max(num, StreamOffset[i] + StreamStride[i] * VertexCount);
				}
				return num;
			}
		}

		public MeshVertexData(AssetTypeValueField vertexData)
		{
			VertexCount = (int)vertexData["m_VertexCount"].AsUInt;
			List<Channel> list = new List<Channel>();
			foreach (AssetTypeValueField child in vertexData["m_Channels"]["Array"].Children)
			{
				list.Add(new Channel
				{
					Stream = child["stream"].AsByte,
					Offset = child["offset"].AsByte,
					Format = child["format"].AsByte,
					Dimension = (child["dimension"].AsByte & 0xF)
				});
			}
			Channels = list.ToArray();
			int num = 0;
			Channel[] channels = Channels;
			for (int i = 0; i < channels.Length; i++)
			{
				Channel channel = channels[i];
				if (channel.Present)
				{
					num = Math.Max(num, channel.Stream + 1);
				}
			}
			StreamStride = new int[num];
			StreamOffset = new int[num];
			channels = Channels;
			for (int i = 0; i < channels.Length; i++)
			{
				Channel channel2 = channels[i];
				if (channel2.Present)
				{
					StreamStride[channel2.Stream] = Math.Max(StreamStride[channel2.Stream], channel2.Offset + FormatSize(channel2.Format) * channel2.Dimension);
				}
			}
			int num2 = 0;
			for (int j = 0; j < num; j++)
			{
				num2 = (num2 + 15) & -16;
				StreamOffset[j] = num2;
				num2 += StreamStride[j] * VertexCount;
			}
			Data = FieldCopier.ReadBytes(vertexData["m_DataSize"]);
		}

		public bool Has(int channel)
		{
			if (channel < Channels.Length)
			{
				return Channels[channel].Present;
			}
			return false;
		}

		public int Dimension(int channel)
		{
			if (!Has(channel))
			{
				return 0;
			}
			return Channels[channel].Dimension;
		}

		public static int FormatSize(int format)
		{
			switch (format)
			{
			case 0:
			case 10:
			case 11:
				return 4;
			case 1:
			case 4:
			case 5:
			case 8:
			case 9:
				return 2;
			default:
				return 1;
			}
		}

		private int Address(int channel, int vertex, int component)
		{
			Channel channel2 = Channels[channel];
			return StreamOffset[channel2.Stream] + StreamStride[channel2.Stream] * vertex + channel2.Offset + FormatSize(channel2.Format) * component;
		}

		public float Get(int channel, int vertex, int component)
		{
			Channel channel2 = Channels[channel];
			int num = Address(channel, vertex, component);
			return channel2.Format switch
			{
				0 => BitConverter.ToSingle(Data, num), 
				1 => HalfToFloat(BitConverter.ToUInt16(Data, num)), 
				2 => (float)(int)Data[num] / 255f, 
				3 => Math.Max((float)(sbyte)Data[num] / 127f, -1f), 
				4 => (float)(int)BitConverter.ToUInt16(Data, num) / 65535f, 
				5 => Math.Max((float)BitConverter.ToInt16(Data, num) / 32767f, -1f), 
				6 => (int)Data[num], 
				7 => (sbyte)Data[num], 
				8 => (int)BitConverter.ToUInt16(Data, num), 
				9 => BitConverter.ToInt16(Data, num), 
				10 => BitConverter.ToUInt32(Data, num), 
				11 => BitConverter.ToInt32(Data, num), 
				_ => throw new NotSupportedException("Vertex format " + channel2.Format), 
			};
		}

		public void Set(int channel, int vertex, int component, float value)
		{
			Channel channel2 = Channels[channel];
			int num = Address(channel, vertex, component);
			switch (channel2.Format)
			{
			case 0:
				WriteBytes(BitConverter.GetBytes(value), num);
				break;
			case 1:
				WriteBytes(BitConverter.GetBytes(FloatToHalf(value)), num);
				break;
			case 2:
				Data[num] = (byte)Math.Round(Clamp(value, 0f, 1f) * 255f);
				break;
			case 3:
				Data[num] = (byte)(sbyte)Math.Round(Clamp(value, -1f, 1f) * 127f);
				break;
			case 4:
				WriteBytes(BitConverter.GetBytes((ushort)Math.Round(Clamp(value, 0f, 1f) * 65535f)), num);
				break;
			case 5:
				WriteBytes(BitConverter.GetBytes((short)Math.Round(Clamp(value, -1f, 1f) * 32767f)), num);
				break;
			case 6:
				Data[num] = (byte)value;
				break;
			case 7:
				Data[num] = (byte)(sbyte)value;
				break;
			case 8:
				WriteBytes(BitConverter.GetBytes((ushort)value), num);
				break;
			case 9:
				WriteBytes(BitConverter.GetBytes((short)value), num);
				break;
			case 10:
				WriteBytes(BitConverter.GetBytes((uint)value), num);
				break;
			case 11:
				WriteBytes(BitConverter.GetBytes((int)value), num);
				break;
			default:
				throw new NotSupportedException("Vertex format " + channel2.Format);
			}
		}

		private void WriteBytes(byte[] bytes, int at)
		{
			Buffer.BlockCopy(bytes, 0, Data, at, bytes.Length);
		}

		private static float Clamp(float v, float min, float max)
		{
			if (!(v < min))
			{
				if (!(v > max))
				{
					return v;
				}
				return max;
			}
			return min;
		}

		public static float HalfToFloat(ushort h)
		{
			int num = (h >> 15) & 1;
			int num2 = (h >> 10) & 0x1F;
			int num3 = h & 0x3FF;
			float num4 = num2 switch
			{
				0 => (float)((double)num3 / 1024.0 * Math.Pow(2.0, -14.0)), 
				31 => (num3 == 0) ? float.PositiveInfinity : float.NaN, 
				_ => (float)((1.0 + (double)num3 / 1024.0) * Math.Pow(2.0, num2 - 15)), 
			};
			if (num != 1)
			{
				return num4;
			}
			return 0f - num4;
		}

		public static ushort FloatToHalf(float f)
		{
			int num = BitConverter.ToInt32(BitConverter.GetBytes(f), 0);
			int num2 = (num >> 16) & 0x8000;
			int num3 = ((num >> 23) & 0xFF) - 127 + 15;
			int num4 = num & 0x7FFFFF;
			if (num3 <= 0)
			{
				return (ushort)num2;
			}
			if (num3 >= 31)
			{
				return (ushort)(num2 | 0x7C00);
			}
			return (ushort)(num2 | (num3 << 10) | (num4 >> 13));
		}
	}
	public static class Signatures
	{
		public static string Of(AssetClassID type, AssetTypeValueField f)
		{
			switch (type)
			{
			case AssetClassID.Mesh:
				return "v" + f["m_VertexData"]["m_VertexCount"].AsUInt + "/i" + FieldCopier.ReadBytes(f["m_IndexBuffer"]).Length + "/s" + f["m_SubMeshes"]["Array"].Children.Count + "/b" + f["m_BindPose"]["Array"].Children.Count;
			case AssetClassID.Texture2D:
				return f["m_Width"].AsInt + "x" + f["m_Height"].AsInt;
			case AssetClassID.AnimationClip:
			{
				AssetTypeValueField assetTypeValueField2 = f["m_MuscleClip"];
				return "t" + (assetTypeValueField2["m_StopTime"].AsFloat - assetTypeValueField2["m_StartTime"].AsFloat).ToString("F3", CultureInfo.InvariantCulture) + "/b" + f["m_ClipBindingConstant"]["genericBindings"]["Array"].Children.Count;
			}
			case AssetClassID.Avatar:
				return "n" + f["m_Avatar"]["m_AvatarSkeleton"]["data"]["m_Node"]["Array"].Children.Count + "/t" + f["m_TOS"]["Array"].Children.Count;
			case AssetClassID.AnimatorController:
				return "c" + f["m_AnimationClips"]["Array"].Children.Count + "/t" + f["m_TOS"]["Array"].Children.Count;
			case AssetClassID.AudioClip:
				return f["m_Channels"].AsInt + "ch/" + f["m_Frequency"].AsInt;
			case AssetClassID.Sprite:
			{
				AssetTypeValueField assetTypeValueField = f["m_RD"]["textureRect"];
				return Round(assetTypeValueField["width"].AsFloat) + "x" + Round(assetTypeValueField["height"].AsFloat);
			}
			default:
				return "";
			}
		}

		private static string Round(float v)
		{
			return Math.Round(v).ToString(CultureInfo.InvariantCulture);
		}
	}
	public sealed class SourceBundles : IDisposable
	{
		private readonly AssetsManager _manager = new AssetsManager();

		private readonly Dictionary<string, BundleFileInstance> _bundles = new Dictionary<string, BundleFileInstance>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, AssetsFileInstance> _files = new Dictionary<string, AssetsFileInstance>(StringComparer.OrdinalIgnoreCase);

		public string Root { get; }

		public SourceBundles(string addressablesRoot)
		{
			Root = addressablesRoot;
		}

		public static string AddressablesFolder(string gameFolder)
		{
			return Path.Combine(gameFolder, "ULTRAKILL_Data", "StreamingAssets", "aa", "StandaloneWindows64");
		}

		public string BundlePath(string relative)
		{
			string fullPath = Path.GetFullPath(Path.Combine(Root, relative.Replace('/', Path.DirectorySeparatorChar)));
			string text = Path.GetFullPath(Root).TrimEnd(new char[1] { Path.DirectorySeparatorChar });
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string value = text + directorySeparatorChar;
			if (!fullPath.StartsWith(value, StringComparison.OrdinalIgnoreCase))
			{
				throw new InvalidDataException("Bundle path outside the game folder: " + relative);
			}
			return fullPath;
		}

		public BundleFileInstance Bundle(string relative)
		{
			if (!_bundles.TryGetValue(relative, out var value))
			{
				string text = BundlePath(relative);
				if (!File.Exists(text))
				{
					throw new FileNotFoundException("ULTRAKILL file not found", text);
				}
				value = _manager.LoadBundleFile(text, unpackIfPacked: false);
				_bundles[relative] = value;
			}
			return value;
		}

		public AssetsFileInstance File0(string relative)
		{
			if (_files.TryGetValue(relative, out var value))
			{
				return value;
			}
			BundleFileInstance bundleFileInstance = Bundle(relative);
			for (int i = 0; i < bundleFileInstance.file.BlockAndDirInfo.DirectoryInfos.Count; i++)
			{
				if (bundleFileInstance.file.IsAssetsFile(i))
				{
					value = _manager.LoadAssetsFileFromBundle(bundleFileInstance, i);
					_files[relative] = value;
					return value;
				}
			}
			throw new InvalidDataException("No serialized file in " + relative);
		}

		public string CabName(string relative)
		{
			BundleFileInstance bundleFileInstance = Bundle(relative);
			for (int i = 0; i < bundleFileInstance.file.BlockAndDirInfo.DirectoryInfos.Count; i++)
			{
				if (bundleFileInstance.file.IsAssetsFile(i))
				{
					return bundleFileInstance.file.GetFileName(i);
				}
			}
			return null;
		}

		public string UnityVersion(string relative)
		{
			return File0(relative).file.Metadata.UnityVersion;
		}

		public AssetFileInfo Info(string relative, long pathId)
		{
			return File0(relative).file.GetAssetInfo(pathId);
		}

		public AssetTypeValueField Read(string relative, long pathId)
		{
			AssetsFileInstance assetsFileInstance = File0(relative);
			AssetFileInfo assetInfo = assetsFileInstance.file.GetAssetInfo(pathId);
			if (assetInfo != null)
			{
				return _manager.GetBaseField(assetsFileInstance, assetInfo);
			}
			return null;
		}

		public AssetTypeValueField Read(string relative, AssetFileInfo info)
		{
			return _manager.GetBaseField(File0(relative), info);
		}

		public IList<AssetFileInfo> Objects(string relative)
		{
			return File0(relative).file.AssetInfos;
		}

		public byte[] RawBytes(string relative, AssetFileInfo info)
		{
			AssetsFileInstance assetsFileInstance = File0(relative);
			lock (assetsFileInstance.file.Reader)
			{
				assetsFileInstance.file.Reader.Position = info.GetAbsoluteByteOffset(assetsFileInstance.file);
				return assetsFileInstance.file.Reader.ReadBytes((int)info.ByteSize);
			}
		}

		public byte[] ReadResource(string relative, string archivePath, long offset, long size)
		{
			if (size <= 0)
			{
				return Array.Empty<byte>();
			}
			string fileName = Path.GetFileName(archivePath.Replace("archive:/", "").Replace('/', Path.DirectorySeparatorChar));
			BundleFileInstance bundleFileInstance = Bundle(relative);
			int fileIndex = bundleFileInstance.file.GetFileIndex(fileName);
			if (fileIndex < 0)
			{
				throw new InvalidDataException("Resource " + fileName + " not in " + relative);
			}
			bundleFileInstance.file.GetFileRange(fileIndex, out var offset2, out var length);
			if (offset < 0 || offset + size > length)
			{
				throw new InvalidDataException("Resource range outside " + fileName);
			}
			AssetsFileReader dataReader = bundleFileInstance.file.DataReader;
			lock (dataReader)
			{
				dataReader.Position = offset2 + offset;
				return dataReader.ReadBytes((int)size);
			}
		}

		public static string Sha256(params byte[][] parts)
		{
			using SHA256 sHA = SHA256.Create();
			foreach (byte[] array in parts)
			{
				sHA.TransformBlock(array, 0, array.Length, null, 0);
			}
			sHA.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
			return BitConverter.ToString(sHA.Hash).Replace("-", "").ToLowerInvariant();
		}

		public void Dispose()
		{
			_manager.UnloadAll(unloadClassData: true);
			_bundles.Clear();
			_files.Clear();
		}
	}
	public static class TextureCodec
	{
		public const int Alpha8 = 1;

		public const int ARGB4444 = 2;

		public const int RGB24 = 3;

		public const int RGBA32 = 4;

		public const int ARGB32 = 5;

		public const int RGB565 = 7;

		public const int DXT1 = 10;

		public const int DXT5 = 12;

		public const int RGBA4444 = 13;

		public const int BGRA32 = 14;

		public const int R8 = 63;

		public static bool CanDecode(int format)
		{
			switch (format)
			{
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 7:
			case 10:
			case 12:
			case 13:
			case 14:
			case 63:
				return true;
			default:
				return false;
			}
		}

		public static RgbaImage Decode(int format, int width, int height, byte[] data)
		{
			RgbaImage rgbaImage = new RgbaImage(width, height);
			float[] pixels = rgbaImage.Pixels;
			int num = width * height;
			switch (format)
			{
			case 1:
			{
				for (int num9 = 0; num9 < num; num9++)
				{
					Set(pixels, num9, 1f, 1f, 1f, (float)(int)data[num9] / 255f);
				}
				break;
			}
			case 63:
			{
				for (int l = 0; l < num; l++)
				{
					Set(pixels, l, (float)(int)data[l] / 255f, 0f, 0f, 1f);
				}
				break;
			}
			case 3:
			{
				for (int n = 0; n < num; n++)
				{
					Set(pixels, n, (float)(int)data[n * 3] / 255f, (float)(int)data[n * 3 + 1] / 255f, (float)(int)data[n * 3 + 2] / 255f, 1f);
				}
				break;
			}
			case 4:
			{
				for (int j = 0; j < num * 4; j++)
				{
					pixels[j] = (float)(int)data[j] / 255f;
				}
				break;
			}
			case 5:
			{
				for (int num8 = 0; num8 < num; num8++)
				{
					Set(pixels, num8, (float)(int)data[num8 * 4 + 1] / 255f, (float)(int)data[num8 * 4 + 2] / 255f, (float)(int)data[num8 * 4 + 3] / 255f, (float)(int)data[num8 * 4] / 255f);
				}
				break;
			}
			case 14:
			{
				for (int m = 0; m < num; m++)
				{
					Set(pixels, m, (float)(int)data[m * 4 + 2] / 255f, (float)(int)data[m * 4 + 1] / 255f, (float)(int)data[m * 4] / 255f, (float)(int)data[m * 4 + 3] / 255f);
				}
				break;
			}
			case 7:
			{
				for (int k = 0; k < num; k++)
				{
					int num7 = data[k * 2] | (data[k * 2 + 1] << 8);
					Set(pixels, k, (float)((num7 >> 11) & 0x1F) / 31f, (float)((num7 >> 5) & 0x3F) / 63f, (float)(num7 & 0x1F) / 31f, 1f);
				}
				break;
			}
			case 2:
			case 13:
			{
				for (int i = 0; i < num; i++)
				{
					int num2 = data[i * 2] | (data[i * 2 + 1] << 8);
					float num3 = (float)((num2 >> 12) & 0xF) / 15f;
					float num4 = (float)((num2 >> 8) & 0xF) / 15f;
					float num5 = (float)((num2 >> 4) & 0xF) / 15f;
					float num6 = (float)(num2 & 0xF) / 15f;
					if (format == 2)
					{
						Set(pixels, i, num4, num5, num6, num3);
					}
					else
					{
						Set(pixels, i, num3, num4, num5, num6);
					}
				}
				break;
			}
			case 10:
			case 12:
				DecodeBlocks(format, width, height, data, pixels);
				break;
			default:
				throw new NotSupportedException("Texture format " + format);
			}
			return rgbaImage.FlipVertical();
		}

		private static void Set(float[] p, int i, float r, float g, float b, float a)
		{
			p[i * 4] = r;
			p[i * 4 + 1] = g;
			p[i * 4 + 2] = b;
			p[i * 4 + 3] = a;
		}

		private static void DecodeBlocks(int format, int width, int height, byte[] data, float[] p)
		{
			int num = ((format == 10) ? 8 : 16);
			int num2 = (width + 3) / 4;
			int num3 = (height + 3) / 4;
			float[,] array = new float[4, 4];
			float[] array2 = new float[8];
			for (int i = 0; i < num3; i++)
			{
				for (int j = 0; j < num2; j++)
				{
					int num4 = (i * num2 + j) * num;
					int num5 = num4;
					ulong num6 = 0uL;
					if (format == 12)
					{
						float num7 = (float)(int)data[num4] / 255f;
						float num8 = (float)(int)data[num4 + 1] / 255f;
						array2[0] = num7;
						array2[1] = num8;
						if (num7 > num8)
						{
							for (int k = 1; k < 7; k++)
							{
								array2[k + 1] = ((float)(7 - k) * num7 + (float)k * num8) / 7f;
							}
						}
						else
						{
							for (int l = 1; l < 5; l++)
							{
								array2[l + 1] = ((float)(5 - l) * num7 + (float)l * num8) / 5f;
							}
							array2[6] = 0f;
							array2[7] = 1f;
						}
						for (int m = 0; m < 6; m++)
						{
							num6 |= (ulong)data[num4 + 2 + m] << 8 * m;
						}
						num5 = num4 + 8;
					}
					int num9 = data[num5] | (data[num5 + 1] << 8);
					int num10 = data[num5 + 2] | (data[num5 + 3] << 8);
					Rgb565(num9, array, 0);
					Rgb565(num10, array, 1);
					bool flag = num9 > num10 || format == 12;
					for (int n = 0; n < 3; n++)
					{
						if (flag)
						{
							array[2, n] = (2f * array[0, n] + array[1, n]) / 3f;
							array[3, n] = (array[0, n] + 2f * array[1, n]) / 3f;
						}
						else
						{
							array[2, n] = (array[0, n] + array[1, n]) / 2f;
							array[3, n] = 0f;
						}
					}
					array[0, 3] = (array[1, 3] = (array[2, 3] = 1f));
					array[3, 3] = (flag ? 1 : 0);
					uint num11 = (uint)(data[num5 + 4] | (data[num5 + 5] << 8) | (data[num5 + 6] << 16) | (data[num5 + 7] << 24));
					for (int num12 = 0; num12 < 4; num12++)
					{
						for (int num13 = 0; num13 < 4; num13++)
						{
							int num14 = j * 4 + num13;
							int num15 = i * 4 + num12;
							if (num14 < width && num15 < height)
							{
								int num16 = num12 * 4 + num13;
								int num17 = (int)((num11 >> 2 * num16) & 3);
								int num18 = (num15 * width + num14) * 4;
								p[num18] = array[num17, 0];
								p[num18 + 1] = array[num17, 1];
								p[num18 + 2] = array[num17, 2];
								p[num18 + 3] = ((format == 12) ? array2[(uint)((num6 >> 3 * num16) & 7)] : array[num17, 3]);
							}
						}
					}
				}
			}
		}

		private static void Rgb565(int v, float[,] colors, int index)
		{
			colors[index, 0] = (float)((v >> 11) & 0x1F) / 31f;
			colors[index, 1] = (float)((v >> 5) & 0x3F) / 63f;
			colors[index, 2] = (float)(v & 0x1F) / 31f;
		}

		public static RgbaImage Decode(AssetTypeValueField texture)
		{
			int asInt = texture["m_TextureFormat"].AsInt;
			if (!CanDecode(asInt))
			{
				throw new NotSupportedException(string.Format("Texture {0}: format {1} not supported", texture["m_Name"].AsString, asInt));
			}
			return Decode(asInt, texture["m_Width"].AsInt, texture["m_Height"].AsInt, FieldCopier.ReadBytes(texture["image data"]));
		}

		public static void Write(AssetTypeValueField texture, RgbaImage image, bool withAlpha = true)
		{
			RgbaImage rgbaImage = image.FlipVertical();
			int num = image.Width * image.Height;
			byte[] array;
			if (withAlpha)
			{
				array = rgbaImage.ToRgba32();
			}
			else
			{
				array = new byte[num * 3];
				for (int i = 0; i < num; i++)
				{
					array[i * 3] = RgbaImage.ToByte(rgbaImage.Pixels[i * 4]);
					array[i * 3 + 1] = RgbaImage.ToByte(rgbaImage.Pixels[i * 4 + 1]);
					array[i * 3 + 2] = RgbaImage.ToByte(rgbaImage.Pixels[i * 4 + 2]);
				}
			}
			texture["m_Width"].AsInt = image.Width;
			texture["m_Height"].AsInt = image.Height;
			texture["m_CompleteImageSize"].AsUInt = (uint)array.Length;
			texture["m_TextureFormat"].AsInt = (withAlpha ? 4 : 3);
			texture["m_MipCount"].AsInt = 1;
			if (!texture["m_ImageCount"].IsDummy)
			{
				texture["m_ImageCount"].AsInt = 1;
			}
			if (!texture["m_MipsStripped"].IsDummy)
			{
				texture["m_MipsStripped"].AsInt = 0;
			}
			FieldCopier.WriteBytes(texture["image data"], array);
			CopyRules.ClearStream(texture);
		}
	}
}
namespace UltrakillV1.Setup.Render
{
	public sealed class PickupIconRenderer
	{
		private sealed class Shading
		{
			public bool Skip;

			public RgbaImage Texture;

			public double ScaleU = 1.0;

			public double ScaleV = 1.0;

			public double OffsetU;

			public double OffsetV;

			public double R = 1.0;

			public double G = 1.0;

			public double B = 1.0;

			public RgbaImage Emission;

			public double ER;

			public double EG;

			public double EB;

			public double Cutoff = -1.0;
		}

		public const int Size = 256;

		private const double ModelSize = 1.6;

		private const double Fov = 30.0;

		public double Ambient = 0.3;

		public double Light = 0.9;

		public double Specular = 0.25;

		public double AmbientBlue = 0.33;

		public bool CounterClockwiseFront;

		public string[] SkipMaterials = new string[0];

		private readonly SceneReader _scene;

		private readonly Dictionary<long, RgbaImage> _textures = new Dictionary<long, RgbaImage>();

		public PickupIconRenderer(SceneReader scene)
		{
			_scene = scene;
		}

		public RgbaImage Render(long rootGameObject, float r, float g, float b)
		{
			return Compose(RenderModel(rootGameObject), r, g, b);
		}

		public static RgbaImage Compose(RgbaImage gun, float r, float g, float b)
		{
			RgbaImage rgbaImage = new RgbaImage(256, 256);
			float num = 128f;
			for (int i = 0; i < 256; i++)
			{
				for (int j = 0; j < 256; j++)
				{
					float num2 = (float)j - num;
					float num3 = (float)i - num;
					float num4 = (float)Math.Sqrt(num2 * num2 + num3 * num3) / num;
					float val = Math.Max(0f, Math.Min(1f, 1f - num4)) * 0.55f;
					int num5 = gun.Index(j, 255 - i);
					float num6 = gun.Pixels[num5 + 3];
					int num7 = rgbaImage.Index(j, 255 - i);
					rgbaImage.Pixels[num7] = r + (gun.Pixels[num5] - r) * num6;
					rgbaImage.Pixels[num7 + 1] = g + (gun.Pixels[num5 + 1] - g) * num6;
					rgbaImage.Pixels[num7 + 2] = b + (gun.Pixels[num5 + 2] - b) * num6;
					rgbaImage.Pixels[num7 + 3] = Math.Max(num6, val);
				}
			}
			return rgbaImage;
		}

		public RgbaImage RenderModel(long rootGameObject)
		{
			(double, double, double) tuple = Normalize(-0.85, 0.35, -0.6);
			double num = 1.6 / (2.0 * Math.Tan(Math.PI / 12.0)) * 1.15;
			(double, double, double) eye = (tuple.Item1 * num, tuple.Item2 * num, tuple.Item3 * num);
			(double, double, double) lightForward = Normalize(0.0 - tuple.Item1, 0.0 - tuple.Item2 - 0.5, 0.0 - tuple.Item3);
			return RenderDrawables(_scene.Drawables(rootGameObject), eye, (x: 0.0, y: 0.0, z: 0.0), 30.0, lightForward);
		}

		public RgbaImage RenderDrawables(IEnumerable<SceneReader.Drawable> drawables, (double x, double y, double z) eye, (double x, double y, double z) target, double fov, (double x, double y, double z) lightForward)
		{
			RgbaImage rgbaImage = new RgbaImage(256, 256);
			double[] array = new double[65536];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = double.MaxValue;
			}
			(double, double, double) tuple = Normalize(target.x - eye.x, target.y - eye.y, target.z - eye.z);
			(double, double, double) b = Normalize(Cross((x: 0.0, y: 1.0, z: 0.0), tuple));
			(double, double, double) b2 = Cross(tuple, b);
			lightForward = Normalize(lightForward);
			(double, double, double) toLight = (0.0 - lightForward.x, 0.0 - lightForward.y, 0.0 - lightForward.z);
			double num = 1.0 / Math.Tan(fov * 0.5 * Math.PI / 180.0);
			foreach (SceneReader.Drawable drawable in drawables)
			{
				MeshVertexData meshVertexData = new MeshVertexData(drawable.Mesh["m_VertexData"]);
				int vertexCount = meshVertexData.VertexCount;
				if (!meshVertexData.Has(0) || meshVertexData.Data.Length < meshVertexData.RequiredSize)
				{
					continue;
				}
				double[] array2 = new double[vertexCount];
				double[] array3 = new double[vertexCount];
				double[] array4 = new double[vertexCount];
				double[] array5 = new double[vertexCount];
				double[] array6 = new double[vertexCount];
				double[] array7 = new double[vertexCount];
				double[] array8 = new double[vertexCount];
				double[] array9 = new double[vertexCount];
				Mat4 world = drawable.World;
				bool flag = world.Determinant3() < 0.0;
				for (int j = 0; j < vertexCount; j++)
				{
					world = drawable.World;
					(double x, double y, double z) tuple2 = world.Point(meshVertexData.Get(0, j, 0), meshVertexData.Get(0, j, 1), meshVertexData.Get(0, j, 2));
					double item = tuple2.x - eye.x;
					double item2 = tuple2.y - eye.y;
					double item3 = tuple2.z - eye.z;
					double num2 = Dot((x: item, y: item2, z: item3), b);
					double num3 = Dot((x: item, y: item2, z: item3), b2);
					double num4 = (array4[j] = Dot((x: item, y: item2, z: item3), tuple));
					array2[j] = (num2 / num4 * num * 0.5 + 0.5) * 256.0;
					array3[j] = (0.5 - num3 / num4 * num * 0.5) * 256.0;
					if (meshVertexData.Has(1))
					{
						world = drawable.World;
						(double, double, double) tuple3 = world.Vector(meshVertexData.Get(1, j, 0), meshVertexData.Get(1, j, 1), meshVertexData.Get(1, j, 2));
						(double, double, double) tuple4 = Normalize(tuple3.Item1, tuple3.Item2, tuple3.Item3);
						array5[j] = tuple4.Item1;
						array6[j] = tuple4.Item2;
						array7[j] = tuple4.Item3;
					}
					if (meshVertexData.Has(4))
					{
						array8[j] = meshVertexData.Get(4, j, 0);
						array9[j] = meshVertexData.Get(4, j, 1);
					}
				}
				byte[] buffer = FieldCopier.ReadBytes(drawable.Mesh["m_IndexBuffer"]);
				bool flag2 = drawable.Mesh["m_IndexFormat"].AsInt == 1;
				List<AssetTypeValueField> children = drawable.Mesh["m_SubMeshes"]["Array"].Children;
				for (int k = 0; k < children.Count; k++)
				{
					AssetTypeValueField assetTypeValueField = children[k];
					if (assetTypeValueField["topology"].AsInt != 0)
					{
						continue;
					}
					AssetTypeValueField assetTypeValueField2 = ((k < drawable.Materials.Count) ? drawable.Materials[k] : ((drawable.Materials.Count > 0) ? drawable.Materials[drawable.Materials.Count - 1] : null));
					string materialName = ((assetTypeValueField2 == null) ? "" : assetTypeValueField2["m_Name"].AsString);
					if (Array.Exists(SkipMaterials, (string prefix) => materialName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
					{
						continue;
					}
					Shading shading = ShadingOf(assetTypeValueField2);
					if (shading.Skip)
					{
						continue;
					}
					int num5 = (int)assetTypeValueField["firstByte"].AsUInt / (flag2 ? 4 : 2);
					int asUInt = (int)assetTypeValueField["indexCount"].AsUInt;
					int asUInt2 = (int)assetTypeValueField["baseVertex"].AsUInt;
					for (int num6 = 0; num6 + 2 < asUInt; num6 += 3)
					{
						int num7 = Index(buffer, num5 + num6, flag2) + asUInt2;
						int num8 = Index(buffer, num5 + num6 + 1, flag2) + asUInt2;
						int num9 = Index(buffer, num5 + num6 + 2, flag2) + asUInt2;
						if (num7 < vertexCount && num8 < vertexCount && num9 < vertexCount && !(array4[num7] <= 0.01) && !(array4[num8] <= 0.01) && !(array4[num9] <= 0.01) && (array2[num8] - array2[num7]) * (array3[num9] - array3[num7]) - (array2[num9] - array2[num7]) * (array3[num8] - array3[num7]) <= 0.0 == (flag ^ CounterClockwiseFront))
						{
							Rasterize(rgbaImage, array, array2, array3, array4, array5, array6, array7, array8, array9, num7, num8, num9, shading, toLight);
						}
					}
				}
			}
			return rgbaImage;
		}

		private Shading ShadingOf(AssetTypeValueField material)
		{
			Shading shading = new Shading();
			if (material == null)
			{
				return shading;
			}
			string text = _scene.ShaderName(material);
			if (text.StartsWith("Legacy Shaders/Particles"))
			{
				shading.Skip = true;
				return shading;
			}
			AssetTypeValueField assetTypeValueField = SceneReader.Property(material, "m_TexEnvs", "_MainTex");
			if (assetTypeValueField != null)
			{
				shading.Texture = Texture(SceneReader.PathOf(assetTypeValueField["m_Texture"]));
				shading.ScaleU = assetTypeValueField["m_Scale"]["x"].AsFloat;
				shading.ScaleV = assetTypeValueField["m_Scale"]["y"].AsFloat;
				shading.OffsetU = assetTypeValueField["m_Offset"]["x"].AsFloat;
				shading.OffsetV = assetTypeValueField["m_Offset"]["y"].AsFloat;
			}
			AssetTypeValueField assetTypeValueField2 = SceneReader.Property(material, "m_Colors", "_Color");
			if (assetTypeValueField2 != null)
			{
				shading.R = assetTypeValueField2["r"].AsFloat;
				shading.G = assetTypeValueField2["g"].AsFloat;
				shading.B = assetTypeValueField2["b"].AsFloat;
			}
			if (_scene.HasKeyword(material, "_EMISSION"))
			{
				AssetTypeValueField assetTypeValueField3 = SceneReader.Property(material, "m_Colors", "_EmissionColor");
				AssetTypeValueField assetTypeValueField4 = SceneReader.Property(material, "m_TexEnvs", "_EmissionMap");
				if (assetTypeValueField3 != null)
				{
					shading.ER = assetTypeValueField3["r"].AsFloat;
					shading.EG = assetTypeValueField3["g"].AsFloat;
					shading.EB = assetTypeValueField3["b"].AsFloat;
				}
				if (assetTypeValueField4 != null)
				{
					shading.Emission = Texture(SceneReader.PathOf(assetTypeValueField4["m_Texture"]));
				}
			}
			if (text.Contains("Cutout"))
			{
				AssetTypeValueField assetTypeValueField5 = SceneReader.Property(material, "m_Floats", "_Cutoff");
				shading.Cutoff = ((assetTypeValueField5 != null) ? ((double)assetTypeValueField5.AsFloat) : 0.5);
			}
			return shading;
		}

		private RgbaImage Texture(long pathId)
		{
			if (pathId == 0L)
			{
				return null;
			}
			if (_textures.TryGetValue(pathId, out var value))
			{
				return value;
			}
			RgbaImage rgbaImage = null;
			try
			{
				AssetTypeValueField assetTypeValueField = _scene.Get(pathId);
				if (assetTypeValueField != null && TextureCodec.CanDecode(assetTypeValueField["m_TextureFormat"].AsInt) && FieldCopier.ReadBytes(assetTypeValueField["image data"]).Length != 0)
				{
					rgbaImage = TextureCodec.Decode(assetTypeValueField);
				}
			}
			catch (NotSupportedException)
			{
			}
			_textures[pathId] = rgbaImage;
			return rgbaImage;
		}

		private void Rasterize(RgbaImage image, double[] depth, double[] sx, double[] sy, double[] sz, double[] nx, double[] ny, double[] nz, double[] u, double[] v, int i0, int i1, int i2, Shading s, (double x, double y, double z) toLight)
		{
			int num = Math.Max(0, (int)Math.Floor(Math.Min(sx[i0], Math.Min(sx[i1], sx[i2]))));
			int num2 = Math.Min(255, (int)Math.Ceiling(Math.Max(sx[i0], Math.Max(sx[i1], sx[i2]))));
			int num3 = Math.Max(0, (int)Math.Floor(Math.Min(sy[i0], Math.Min(sy[i1], sy[i2]))));
			int num4 = Math.Min(255, (int)Math.Ceiling(Math.Max(sy[i0], Math.Max(sy[i1], sy[i2]))));
			double num5 = (sx[i1] - sx[i0]) * (sy[i2] - sy[i0]) - (sx[i2] - sx[i0]) * (sy[i1] - sy[i0]);
			if (Math.Abs(num5) < 1E-12)
			{
				return;
			}
			double num6 = 1.0 / sz[i0];
			double num7 = 1.0 / sz[i1];
			double num8 = 1.0 / sz[i2];
			for (int j = num3; j <= num4; j++)
			{
				for (int k = num; k <= num2; k++)
				{
					double num9 = (double)k + 0.5;
					double num10 = (double)j + 0.5;
					double num11 = ((sx[i1] - num9) * (sy[i2] - num10) - (sx[i2] - num9) * (sy[i1] - num10)) / num5;
					double num12 = ((sx[i2] - num9) * (sy[i0] - num10) - (sx[i0] - num9) * (sy[i2] - num10)) / num5;
					double num13 = 1.0 - num11 - num12;
					if (num11 < 0.0 || num12 < 0.0 || num13 < 0.0)
					{
						continue;
					}
					double num14 = num11 * num6 + num12 * num7 + num13 * num8;
					double num15 = 1.0 / num14;
					int num16 = j * 256 + k;
					if (num15 >= depth[num16])
					{
						continue;
					}
					double num17 = num11 * num6 / num14;
					double num18 = num12 * num7 / num14;
					double num19 = num13 * num8 / num14;
					double num20 = num17 * u[i0] + num18 * u[i1] + num19 * u[i2];
					double num21 = num17 * v[i0] + num18 * v[i1] + num19 * v[i2];
					double num22 = s.R;
					double num23 = s.G;
					double num24 = s.B;
					double num25 = 1.0;
					if (s.Texture != null)
					{
						Sample(s.Texture, num20 * s.ScaleU + s.OffsetU, num21 * s.ScaleV + s.OffsetV, out var r, out var g, out var b, out var a);
						num22 *= r;
						num23 *= g;
						num24 *= b;
						num25 = a;
					}
					if (!(s.Cutoff >= 0.0) || !(num25 < s.Cutoff))
					{
						(double, double, double) a2 = Normalize(num17 * nx[i0] + num18 * nx[i1] + num19 * nx[i2], num17 * ny[i0] + num18 * ny[i1] + num19 * ny[i2], num17 * nz[i0] + num18 * nz[i1] + num19 * nz[i2]);
						double num26 = Math.Max(0.0, Dot(a2, toLight));
						double num27 = Ambient + Light * num26;
						double num28 = Ambient + Light * num26;
						double num29 = AmbientBlue + Light * num26;
						double num30 = Specular * Math.Pow(num26, 8.0) * Light;
						double num31 = s.ER;
						double num32 = s.EG;
						double num33 = s.EB;
						if (s.Emission != null)
						{
							Sample(s.Emission, num20, num21, out var r2, out var g2, out var b2, out var _);
							num31 *= r2;
							num32 *= g2;
							num33 *= b2;
						}
						depth[num16] = num15;
						int num34 = image.Index(k, j);
						image.Pixels[num34] = (float)Math.Min(1.0, num22 * num27 + num30 + num31);
						image.Pixels[num34 + 1] = (float)Math.Min(1.0, num23 * num28 + num30 + num32);
						image.Pixels[num34 + 2] = (float)Math.Min(1.0, num24 * num29 + num30 + num33);
						image.Pixels[num34 + 3] = 1f;
					}
				}
			}
		}

		private static void Sample(RgbaImage tex, double u, double v, out double r, out double g, out double b, out double a)
		{
			double num = (u - Math.Floor(u)) * (double)tex.Width - 0.5;
			double num2 = (1.0 - (v - Math.Floor(v))) * (double)tex.Height - 0.5;
			int num3 = (int)Math.Floor(num);
			int num4 = (int)Math.Floor(num2);
			double num5 = num - (double)num3;
			double num6 = num2 - (double)num4;
			r = (g = (b = (a = 0.0)));
			for (int i = 0; i < 2; i++)
			{
				for (int j = 0; j < 2; j++)
				{
					int x = ((num3 + j) % tex.Width + tex.Width) % tex.Width;
					int y = ((num4 + i) % tex.Height + tex.Height) % tex.Height;
					double num7 = ((j == 0) ? (1.0 - num5) : num5) * ((i == 0) ? (1.0 - num6) : num6);
					int num8 = tex.Index(x, y);
					r += (double)tex.Pixels[num8] * num7;
					g += (double)tex.Pixels[num8 + 1] * num7;
					b += (double)tex.Pixels[num8 + 2] * num7;
					a += (double)tex.Pixels[num8 + 3] * num7;
				}
			}
		}

		private static int Index(byte[] buffer, int i, bool wide)
		{
			if (!wide)
			{
				return BitConverter.ToUInt16(buffer, i * 2);
			}
			return BitConverter.ToInt32(buffer, i * 4);
		}

		private static (double x, double y, double z) Normalize(double x, double y, double z)
		{
			double num = Math.Sqrt(x * x + y * y + z * z);
			if (!(num < 1E-12))
			{
				return (x: x / num, y: y / num, z: z / num);
			}
			return (x: 0.0, y: 0.0, z: 0.0);
		}

		private static (double x, double y, double z) Normalize((double x, double y, double z) a)
		{
			return Normalize(a.x, a.y, a.z);
		}

		private static (double x, double y, double z) Cross((double x, double y, double z) a, (double x, double y, double z) b)
		{
			return (x: a.y * b.z - a.z * b.y, y: a.z * b.x - a.x * b.z, z: a.x * b.y - a.y * b.x);
		}

		private static double Dot((double x, double y, double z) a, (double x, double y, double z) b)
		{
			return a.x * b.x + a.y * b.y + a.z * b.z;
		}
	}
	public sealed class PortraitRenderer
	{
		public double TargetY = 1.4;

		public double Distance = 1.45;

		public double Yaw = 32.0;

		public double Pitch = -8.0;

		public double Fov = 28.0;

		public (double x, double y, double z) Light = (x: 0.45, y: -0.55, z: -0.7);

		public string[] SkipMaterials = new string[1] { "V1Wing" };

		public RgbaImage Render(SceneReader scene, long rootGameObject, RgbaImage plate, RgbaImage border)
		{
			PickupIconRenderer obj = new PickupIconRenderer(scene)
			{
				Ambient = 0.35,
				AmbientBlue = 0.38,
				Light = 0.95,
				Specular = 0.3,
				SkipMaterials = SkipMaterials
			};
			double num = Yaw * Math.PI / 180.0;
			double num2 = Pitch * Math.PI / 180.0;
			RgbaImage model = obj.RenderDrawables(target: (x: 0.0, y: TargetY, z: 0.0), eye: (x: Math.Sin(num) * Math.Cos(num2) * Distance, y: TargetY + Math.Sin(num2) * Distance, z: Math.Cos(num) * Math.Cos(num2) * Distance), drawables: scene.Drawables(rootGameObject, includeSkinned: true), fov: Fov, lightForward: Light);
			return Compose(plate, model, border);
		}

		public static RgbaImage Compose(RgbaImage plate, RgbaImage model, RgbaImage border)
		{
			RgbaImage rgbaImage = ((plate != null) ? plate.Clone() : RgbaImage.Solid(model.Width, model.Height, 0.06f, 0.07f, 0.1f, 1f));
			Mask mask = Mask.AlphaOf(rgbaImage);
			model = model.Clone();
			for (int i = 0; i < mask.Values.Length; i++)
			{
				model.Pixels[i * 4 + 3] *= mask.Values[i];
			}
			Mask mask2 = ImageOps.GaussianBlur(ImageOps.MaxFilter(Mask.AlphaOf(model), 9), 6.0);
			for (int j = 0; j < mask.Values.Length; j++)
			{
				mask2.Values[j] *= mask.Values[j];
			}
			ImageOps.AlphaComposite(rgbaImage, ImageOps.Tinted(mask2, 0f, 0f, 0f, 150));
			ImageOps.AlphaComposite(rgbaImage, model);
			if (border != null)
			{
				ImageOps.AlphaComposite(rgbaImage, border);
			}
			return rgbaImage;
		}
	}
	public struct Mat4
	{
		public double[] M;

		public double this[int row, int col]
		{
			get
			{
				return M[col * 4 + row];
			}
			set
			{
				M[col * 4 + row] = value;
			}
		}

		public static Mat4 Identity()
		{
			Mat4 result = new Mat4
			{
				M = new double[16]
			};
			result.M[0] = (result.M[5] = (result.M[10] = (result.M[15] = 1.0)));
			return result;
		}

		public static Mat4 FromColumnMajor(IList<double> values)
		{
			Mat4 result = new Mat4
			{
				M = new double[16]
			};
			for (int i = 0; i < 16; i++)
			{
				result.M[i] = values[i];
			}
			return result;
		}

		public static Mat4 operator *(Mat4 a, Mat4 b)
		{
			Mat4 result = new Mat4
			{
				M = new double[16]
			};
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 4; j++)
				{
					double num = 0.0;
					for (int k = 0; k < 4; k++)
					{
						num += a[i, k] * b[k, j];
					}
					result[i, j] = num;
				}
			}
			return result;
		}

		public static Mat4 TRS(double px, double py, double pz, double qx, double qy, double qz, double qw, double sx, double sy, double sz)
		{
			Mat4 result = Identity();
			double num = qx * qx;
			double num2 = qy * qy;
			double num3 = qz * qz;
			double num4 = qx * qy;
			double num5 = qx * qz;
			double num6 = qy * qz;
			double num7 = qw * qx;
			double num8 = qw * qy;
			double num9 = qw * qz;
			result[0, 0] = (1.0 - 2.0 * (num2 + num3)) * sx;
			result[0, 1] = 2.0 * (num4 - num9) * sy;
			result[0, 2] = 2.0 * (num5 + num8) * sz;
			result[1, 0] = 2.0 * (num4 + num9) * sx;
			result[1, 1] = (1.0 - 2.0 * (num + num3)) * sy;
			result[1, 2] = 2.0 * (num6 - num7) * sz;
			result[2, 0] = 2.0 * (num5 - num8) * sx;
			result[2, 1] = 2.0 * (num6 + num7) * sy;
			result[2, 2] = (1.0 - 2.0 * (num + num2)) * sz;
			result[0, 3] = px;
			result[1, 3] = py;
			result[2, 3] = pz;
			return result;
		}

		public (double x, double y, double z) Point(double x, double y, double z)
		{
			return (x: this[0, 0] * x + this[0, 1] * y + this[0, 2] * z + this[0, 3], y: this[1, 0] * x + this[1, 1] * y + this[1, 2] * z + this[1, 3], z: this[2, 0] * x + this[2, 1] * y + this[2, 2] * z + this[2, 3]);
		}

		public (double x, double y, double z) Vector(double x, double y, double z)
		{
			return (x: this[0, 0] * x + this[0, 1] * y + this[0, 2] * z, y: this[1, 0] * x + this[1, 1] * y + this[1, 2] * z, z: this[2, 0] * x + this[2, 1] * y + this[2, 2] * z);
		}

		public double Determinant3()
		{
			return this[0, 0] * (this[1, 1] * this[2, 2] - this[1, 2] * this[2, 1]) - this[0, 1] * (this[1, 0] * this[2, 2] - this[1, 2] * this[2, 0]) + this[0, 2] * (this[1, 0] * this[2, 1] - this[1, 1] * this[2, 0]);
		}
	}
	public sealed class SceneReader
	{
		public struct Drawable
		{
			public Mat4 World;

			public AssetTypeValueField Mesh;

			public List<AssetTypeValueField> Materials;
		}

		private readonly AssetsManager _manager;

		private readonly AssetsFileInstance _file;

		private readonly IDictionary<long, AssetTypeValueField> _overrides;

		private bool _includeSkinned;

		public SceneReader(AssetsManager manager, AssetsFileInstance file, IDictionary<long, AssetTypeValueField> overrides)
		{
			_manager = manager;
			_file = file;
			_overrides = overrides;
		}

		public AssetTypeValueField Get(long pathId)
		{
			if (pathId == 0L)
			{
				return null;
			}
			if (_overrides != null && _overrides.TryGetValue(pathId, out var value))
			{
				return value;
			}
			AssetFileInfo assetInfo = _file.file.GetAssetInfo(pathId);
			if (assetInfo != null)
			{
				return _manager.GetBaseField(_file, assetInfo);
			}
			return null;
		}

		public int TypeOf(long pathId)
		{
			return _file.file.GetAssetInfo(pathId)?.TypeId ?? (-1);
		}

		public static long PathOf(AssetTypeValueField pptr)
		{
			if (pptr != null && !pptr.IsDummy && pptr["m_FileID"].AsInt == 0)
			{
				return pptr["m_PathID"].AsLong;
			}
			return 0L;
		}

		public long FindRoot(string name)
		{
			foreach (AssetFileInfo item in _file.file.GetAssetsOfType(AssetClassID.GameObject))
			{
				AssetTypeValueField assetTypeValueField = Get(item.PathId);
				if (!(assetTypeValueField["m_Name"].AsString != name))
				{
					long num = Component(assetTypeValueField, 4);
					if (num != 0L && PathOf(Get(num)["m_Father"]) == 0L)
					{
						return item.PathId;
					}
				}
			}
			return 0L;
		}

		public long Component(AssetTypeValueField gameObject, int typeId)
		{
			foreach (AssetTypeValueField child in gameObject["m_Component"]["Array"].Children)
			{
				long num = PathOf(child["component"]);
				if (num != 0L && TypeOf(num) == typeId)
				{
					return num;
				}
			}
			return 0L;
		}

		public List<Drawable> Drawables(long rootGameObject, bool includeSkinned = false)
		{
			List<Drawable> result = new List<Drawable>();
			AssetTypeValueField gameObject = Get(rootGameObject);
			_includeSkinned = includeSkinned;
			Walk(Component(gameObject, 4), Mat4.Identity(), result);
			return result;
		}

		private void Walk(long transformId, Mat4 parent, List<Drawable> result)
		{
			AssetTypeValueField assetTypeValueField = Get(transformId);
			AssetTypeValueField assetTypeValueField2 = Get(PathOf(assetTypeValueField["m_GameObject"]));
			if (assetTypeValueField2 == null || !assetTypeValueField2["m_IsActive"].AsBool)
			{
				return;
			}
			AssetTypeValueField assetTypeValueField3 = assetTypeValueField["m_LocalPosition"];
			AssetTypeValueField assetTypeValueField4 = assetTypeValueField["m_LocalRotation"];
			AssetTypeValueField assetTypeValueField5 = assetTypeValueField["m_LocalScale"];
			Mat4 mat = parent * Mat4.TRS(assetTypeValueField3["x"].AsFloat, assetTypeValueField3["y"].AsFloat, assetTypeValueField3["z"].AsFloat, assetTypeValueField4["x"].AsFloat, assetTypeValueField4["y"].AsFloat, assetTypeValueField4["z"].AsFloat, assetTypeValueField4["w"].AsFloat, assetTypeValueField5["x"].AsFloat, assetTypeValueField5["y"].AsFloat, assetTypeValueField5["z"].AsFloat);
			long num = Component(assetTypeValueField2, 23);
			long num2 = Component(assetTypeValueField2, 33);
			if (num != 0L && num2 != 0L)
			{
				AssetTypeValueField assetTypeValueField6 = Get(num);
				AssetTypeValueField assetTypeValueField7 = Get(PathOf(Get(num2)["m_Mesh"]));
				if (assetTypeValueField6["m_Enabled"].AsBool && assetTypeValueField7 != null)
				{
					List<AssetTypeValueField> list = new List<AssetTypeValueField>();
					foreach (AssetTypeValueField child in assetTypeValueField6["m_Materials"]["Array"].Children)
					{
						list.Add(Get(PathOf(child)));
					}
					result.Add(new Drawable
					{
						World = mat,
						Mesh = assetTypeValueField7,
						Materials = list
					});
				}
			}
			long num3 = (_includeSkinned ? Component(assetTypeValueField2, 137) : 0);
			if (num3 != 0L)
			{
				AssetTypeValueField assetTypeValueField8 = Get(num3);
				AssetTypeValueField assetTypeValueField9 = Get(PathOf(assetTypeValueField8["m_Mesh"]));
				if (assetTypeValueField8["m_Enabled"].AsBool && assetTypeValueField9 != null)
				{
					List<AssetTypeValueField> list2 = new List<AssetTypeValueField>();
					foreach (AssetTypeValueField child2 in assetTypeValueField8["m_Materials"]["Array"].Children)
					{
						list2.Add(Get(PathOf(child2)));
					}
					result.Add(new Drawable
					{
						World = mat,
						Mesh = assetTypeValueField9,
						Materials = list2
					});
				}
			}
			foreach (AssetTypeValueField child3 in assetTypeValueField["m_Children"]["Array"].Children)
			{
				Walk(PathOf(child3), mat, result);
			}
		}

		public static AssetTypeValueField Property(AssetTypeValueField material, string list, string name)
		{
			if (material == null)
			{
				return null;
			}
			foreach (AssetTypeValueField child in material["m_SavedProperties"][list]["Array"].Children)
			{
				if (child["first"].AsString == name)
				{
					return child["second"];
				}
			}
			return null;
		}

		public bool HasKeyword(AssetTypeValueField material, string keyword)
		{
			if (material == null)
			{
				return false;
			}
			AssetTypeValueField assetTypeValueField = material["m_ShaderKeywords"];
			if (!assetTypeValueField.IsDummy && assetTypeValueField.Value != null)
			{
				return (" " + assetTypeValueField.AsString + " ").Contains(" " + keyword + " ");
			}
			AssetTypeValueField assetTypeValueField2 = material["m_ValidKeywords"];
			if (!assetTypeValueField2.IsDummy)
			{
				foreach (AssetTypeValueField child in assetTypeValueField2["Array"].Children)
				{
					if (child.AsString == keyword)
					{
						return true;
					}
				}
			}
			return false;
		}

		public string ShaderName(AssetTypeValueField material)
		{
			AssetTypeValueField assetTypeValueField = ((material == null) ? null : Get(PathOf(material["m_Shader"])));
			if (assetTypeValueField == null)
			{
				return "";
			}
			AssetTypeValueField assetTypeValueField2 = assetTypeValueField["m_ParsedForm"];
			if (!assetTypeValueField2.IsDummy)
			{
				return assetTypeValueField2["m_Name"].AsString;
			}
			return "";
		}
	}
}
namespace UltrakillV1.Setup.Pipeline
{
	public sealed class BuildProgress
	{
		public Action<double, string> Report = delegate
		{
		};

		public Action<string> Log = delegate
		{
		};

		public CancellationToken Cancel = CancellationToken.None;
	}
	public sealed class BuildResult
	{
		public bool Success;

		public string ErrorKey;

		public string ErrorDetail;

		public readonly List<string> Warnings = new List<string>();

		public int ChangedSources;

		public int SkippedOptional;

		public string GameUnityVersion;
	}
	public sealed class SetupException : Exception
	{
		public readonly string Key;

		public SetupException(string key, string message, Exception inner = null)
			: base(message, inner)
		{
			Key = key;
		}
	}
	public sealed class AssetBuilder
	{
		private sealed class Resolved
		{
			public string Bundle;

			public AssetFileInfo Info;

			public AssetTypeValueField Field;
		}

		private Recipe _recipe;

		private SourceBundles _sources;

		private AssetsManager _manager;

		private AssetsFileInstance _template;

		private readonly Dictionary<long, AssetTypeValueField> _overrides = new Dictionary<long, AssetTypeValueField>();

		private readonly Dictionary<RecipeStep, Resolved> _resolved = new Dictionary<RecipeStep, Resolved>();

		private readonly Dictionary<RecipeStep, Resolved> _resolvedGlow = new Dictionary<RecipeStep, Resolved>();

		private BuildProgress _progress;

		private BuildResult _result;

		public BuildResult Build(Recipe recipe, string gameFolder, string outputPath, BuildProgress progress)
		{
			_recipe = recipe;
			_progress = progress ?? new BuildProgress();
			_result = new BuildResult();
			try
			{
				Run(gameFolder, outputPath);
				_result.Success = true;
			}
			catch (OperationCanceledException)
			{
				_result.ErrorKey = "setup.error.cancelled";
				_result.ErrorDetail = "Cancelled";
			}
			catch (SetupException ex2)
			{
				_result.ErrorKey = ex2.Key;
				_result.ErrorDetail = ex2.Message + ((ex2.InnerException != null) ? (" (" + ex2.InnerException.Message + ")") : "");
				_progress.Log("ERROR " + _result.ErrorDetail + ((ex2.InnerException != null) ? ("\n" + ex2.InnerException) : ""));
			}
			catch (Exception ex3)
			{
				_result.ErrorKey = "setup.error.unexpected";
				_result.ErrorDetail = ex3.GetType().Name + ": " + ex3.Message;
				_progress.Log("ERROR " + ex3);
			}
			finally
			{
				_sources?.Dispose();
				_manager?.UnloadAll(unloadClassData: true);
				_overrides.Clear();
			}
			return _result;
		}

		private void Run(string gameFolder, string outputPath)
		{
			_progress.Report(0.01, "stage.check");
			string text = _recipe.PathOf(_recipe.TemplateFile);
			if (!File.Exists(text))
			{
				throw new SetupException("setup.error.template", "Template bundle missing: " + text);
			}
			string text2 = SourceBundles.Sha256(File.ReadAllBytes(text));
			if (!string.IsNullOrEmpty(_recipe.TemplateSha256) && text2 != _recipe.TemplateSha256)
			{
				throw new SetupException("setup.error.template", "Template bundle damaged (checksum mismatch)");
			}
			string text3 = SourceBundles.AddressablesFolder(gameFolder);
			if (!Directory.Exists(text3))
			{
				throw new SetupException("setup.error.gamefiles", "ULTRAKILL data folder not found: " + text3);
			}
			_sources = new SourceBundles(text3);
			foreach (KeyValuePair<string, (string, string)> bundle in _recipe.Bundles)
			{
				if (!File.Exists(_sources.BundlePath(bundle.Value.Item1)))
				{
					throw new SetupException("setup.error.gamefiles", "ULTRAKILL file missing: " + bundle.Value.Item1);
				}
			}
			try
			{
				_result.GameUnityVersion = _sources.UnityVersion(_recipe.Bundles.Values.First().path);
			}
			catch (Exception inner)
			{
				throw new SetupException("setup.error.gamefiles", "Cannot read ULTRAKILL's files", inner);
			}
			if (!string.IsNullOrEmpty(_recipe.GameUnityVersion) && _result.GameUnityVersion != _recipe.GameUnityVersion)
			{
				_result.Warnings.Add("ULTRAKILL uses Unity " + _result.GameUnityVersion + ", the recipe was made with " + _recipe.GameUnityVersion);
			}
			_manager = new AssetsManager();
			BundleFileInstance bundleFileInstance = _manager.LoadBundleFile(text);
			_template = _manager.LoadAssetsFileFromBundle(bundleFileInstance, 0);
			ResolveAll();
			ReferenceMap referenceMap = new ReferenceMap();
			foreach (KeyValuePair<RecipeStep, Resolved> item2 in _resolved)
			{
				if (!(item2.Key.Op != "copy"))
				{
					referenceMap.Add(_sources.CabName(item2.Value.Bundle), item2.Value.Info.PathId, item2.Key.Target);
					string item = _recipe.Bundles[item2.Key.Source.Bundle].cab;
					if (!string.IsNullOrEmpty(item))
					{
						referenceMap.Add(item, item2.Key.Source.PathId, item2.Key.Target);
					}
				}
			}
			Dictionary<(string type, string name, string sig), long> byDescription = new Dictionary<(string, string, string), long>();
			foreach (RecipeStep step in _recipe.Steps)
			{
				if (step.Op == "copy" && step.Source != null)
				{
					byDescription[(step.Source.Type, step.Source.Name, step.Source.Signature)] = step.Target;
				}
			}
			referenceMap.Fallback = delegate(string cab, long pathId)
			{
				foreach (var value2 in _recipe.Bundles.Values)
				{
					if (string.Equals(_sources.CabName(value2.path), cab, StringComparison.OrdinalIgnoreCase))
					{
						AssetFileInfo assetFileInfo = _sources.Info(value2.path, pathId);
						if (assetFileInfo == null)
						{
							return (long?)null;
						}
						AssetClassID typeId = (AssetClassID)assetFileInfo.TypeId;
						AssetTypeValueField assetTypeValueField = _sources.Read(value2.path, assetFileInfo);
						long value;
						return byDescription.TryGetValue((typeId.ToString(), assetTypeValueField["m_Name"].AsString, Signatures.Of(typeId, assetTypeValueField)), out value) ? new long?(value) : ((long?)null);
					}
				}
				return (long?)null;
			};
			int num = 0;
			foreach (RecipeStep step2 in _recipe.Steps)
			{
				_progress.Cancel.ThrowIfCancellationRequested();
				_progress.Report(0.15 + 0.75 * (double)num++ / (double)_recipe.Steps.Count, "stage." + StageOf(step2.Op));
				try
				{
					Execute(step2, referenceMap);
				}
				catch (Exception ex) when (step2.Optional && !(ex is OperationCanceledException))
				{
					_result.SkippedOptional++;
					_result.Warnings.Add(step2.Op + " " + step2.Label + " skipped: " + ex.Message);
					_progress.Log($"WARN optional {step2.Op} {step2.Label} failed: {ex}");
				}
				catch (Exception ex2) when (!(ex2 is SetupException) && !(ex2 is OperationCanceledException))
				{
					throw new SetupException("setup.error.convert", step2.Op + " " + step2.Label + " failed", ex2);
				}
			}
			_progress.Report(0.92, "stage.write");
			foreach (KeyValuePair<long, AssetTypeValueField> @override in _overrides)
			{
				_template.file.GetAssetInfo(@override.Key).SetNewData(@override.Value);
			}
			bundleFileInstance.file.BlockAndDirInfo.DirectoryInfos[0].SetNewData(_template.file);
			string text4 = outputPath + ".raw";
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(outputPath)));
				using (AssetsFileWriter writer = new AssetsFileWriter(text4))
				{
					bundleFileInstance.file.Write(writer, 0L);
				}
				AssetBundleFile assetBundleFile = new AssetBundleFile();
				using AssetsFileReader reader = new AssetsFileReader(File.OpenRead(text4));
				assetBundleFile.Read(reader);
				using (AssetsFileWriter writer2 = new AssetsFileWriter(outputPath))
				{
					assetBundleFile.Pack(writer2, AssetBundleCompressionType.LZ4, blockDirAtEnd: false);
				}
				assetBundleFile.Close();
			}
			catch (IOException ex3)
			{
				throw new SetupException("setup.error.write", "Cannot write the generated bundle: " + ex3.Message, ex3);
			}
			finally
			{
				try
				{
					File.Delete(text4);
				}
				catch (IOException)
				{
				}
			}
			_progress.Log($"Wrote {outputPath} ({new FileInfo(outputPath).Length / 1024} KB); {_result.ChangedSources} source objects differ from the recipe's ULTRAKILL version, {_result.SkippedOptional} optional steps skipped");
		}

		private static string StageOf(string op)
		{
			return op switch
			{
				"copy" => "copy", 
				"sound" => "sound", 
				"bake" => "mesh", 
				_ => "image", 
			};
		}

		private void ResolveAll()
		{
			int num = 0;
			foreach (RecipeStep step in _recipe.Steps)
			{
				_progress.Cancel.ThrowIfCancellationRequested();
				if (num++ % 16 == 0)
				{
					_progress.Report(0.02 + 0.13 * (double)num / (double)_recipe.Steps.Count, "stage.read");
				}
				try
				{
					if (step.Source != null)
					{
						_resolved[step] = Resolve(step.Source, step.Op == "copy" || step.Op == "sound");
					}
					if (step.Glow != null)
					{
						_resolvedGlow[step] = Resolve(step.Glow, withResource: false);
					}
				}
				catch (SetupException) when (step.Optional)
				{
				}
			}
		}

		private Resolved Resolve(SourceRef source, bool withResource)
		{
			if (!_recipe.Bundles.TryGetValue(source.Bundle, out (string, string) value))
			{
				throw new SetupException("setup.error.recipe", "Unknown bundle key " + source.Bundle);
			}
			AssetClassID assetClassID = (AssetClassID)Enum.Parse(typeof(AssetClassID), source.Type);
			AssetFileInfo assetFileInfo;
			try
			{
				assetFileInfo = _sources.Info(value.Item1, source.PathId);
			}
			catch (Exception inner)
			{
				throw new SetupException("setup.error.gamefiles", "Cannot read " + value.Item1, inner);
			}
			AssetTypeValueField assetTypeValueField = null;
			if (assetFileInfo != null && assetFileInfo.TypeId == (int)assetClassID)
			{
				assetTypeValueField = _sources.Read(value.Item1, assetFileInfo);
				if (Signatures.Of(assetClassID, assetTypeValueField) != source.Signature || assetTypeValueField["m_Name"].AsString != source.Name)
				{
					assetTypeValueField = null;
				}
			}
			if (assetTypeValueField == null)
			{
				foreach (AssetFileInfo item in _sources.File0(value.Item1).file.GetAssetsOfType(assetClassID))
				{
					AssetTypeValueField assetTypeValueField2 = _sources.Read(value.Item1, item);
					if (assetTypeValueField2["m_Name"].AsString == source.Name && Signatures.Of(assetClassID, assetTypeValueField2) == source.Signature)
					{
						assetFileInfo = item;
						assetTypeValueField = assetTypeValueField2;
						_result.Warnings.Add($"{source} found at path id {item.PathId}");
						break;
					}
				}
				if (assetTypeValueField == null)
				{
					throw new SetupException("setup.error.version", $"{source} not found in your ULTRAKILL files (different game version?)");
				}
			}
			if (!string.IsNullOrEmpty(source.Sha256) && ContentHash(value.Item1, assetFileInfo, assetTypeValueField, withResource) != source.Sha256)
			{
				_result.ChangedSources++;
				_progress.Log($"NOTE {source}: content differs from the recipe's ULTRAKILL version (structure matches, using it)");
			}
			return new Resolved
			{
				Bundle = value.Item1,
				Info = assetFileInfo,
				Field = assetTypeValueField
			};
		}

		public static string ContentHash(SourceBundles sources, string bundle, AssetFileInfo info, AssetTypeValueField field, bool withResource)
		{
			byte[] array = sources.RawBytes(bundle, info);
			byte[] array2 = Array.Empty<byte>();
			if (withResource)
			{
				AssetTypeValueField assetTypeValueField = field["m_StreamData"];
				AssetTypeValueField assetTypeValueField2 = field["m_Resource"];
				if (!assetTypeValueField.IsDummy && assetTypeValueField["size"].AsULong != 0)
				{
					array2 = sources.ReadResource(bundle, assetTypeValueField["path"].AsString, (long)assetTypeValueField["offset"].AsULong, (long)assetTypeValueField["size"].AsULong);
				}
				else if (!assetTypeValueField2.IsDummy && assetTypeValueField2["m_Size"].AsULong != 0)
				{
					array2 = sources.ReadResource(bundle, assetTypeValueField2["m_Source"].AsString, (long)assetTypeValueField2["m_Offset"].AsULong, (long)assetTypeValueField2["m_Size"].AsULong);
				}
			}
			return SourceBundles.Sha256(array, array2);
		}

		private string ContentHash(string bundle, AssetFileInfo info, AssetTypeValueField field, bool withResource)
		{
			return ContentHash(_sources, bundle, info, field, withResource);
		}

		private Resolved Get(RecipeStep step)
		{
			if (!_resolved.TryGetValue(step, out var value))
			{
				throw new SetupException("setup.error.version", "Source of " + step.Label + " not found");
			}
			return value;
		}

		private AssetTypeValueField Target(long pathId)
		{
			if (_overrides.TryGetValue(pathId, out var value))
			{
				return value;
			}
			AssetFileInfo assetInfo = _template.file.GetAssetInfo(pathId);
			if (assetInfo == null)
			{
				throw new SetupException("setup.error.template", "Template object " + pathId + " missing");
			}
			value = _manager.GetBaseField(_template, assetInfo);
			_overrides[pathId] = value;
			return value;
		}

		private AssetClassID TargetType(long pathId)
		{
			return (AssetClassID)_template.file.GetAssetInfo(pathId).TypeId;
		}

		private void Execute(RecipeStep step, ReferenceMap references)
		{
			switch (step.Op)
			{
			case "copy":
				Copy(step, references);
				break;
			case "sound":
				Sound(step);
				break;
			case "emissiveMask":
				EmissiveMask(step);
				break;
			case "skillIcon":
				SkillIcon(step);
				break;
			case "portrait":
				Portrait(step);
				break;
			case "portrait3d":
				Portrait3D(step);
				break;
			case "bake":
				Bake(step);
				break;
			case "pickupIcon":
				PickupIcon(step);
				break;
			default:
				throw new SetupException("setup.error.recipe", "Unknown recipe step " + step.Op);
			}
		}

		private void Copy(RecipeStep step, ReferenceMap references)
		{
			Resolved source = Get(step);
			AssetClassID type = TargetType(step.Target);
			AssetTypeValueField target = Target(step.Target);
			FieldCopier fieldCopier = new FieldCopier
			{
				Keep = CopyRules.KeepFor(type),
				RemapPPtr = references.For(_sources.File0(source.Bundle).file, _sources.CabName(source.Bundle))
			};
			fieldCopier.Copy(target, source.Field);
			if (fieldCopier.UnresolvedReferences > 0)
			{
				_result.Warnings.Add($"{step.Label}: {fieldCopier.UnresolvedReferences} reference(s) to ULTRAKILL objects the mod doesn't use");
			}
			CopyRules.InlineStreamData(type, target, source.Field, (string path, long offset, long size) => _sources.ReadResource(source.Bundle, path, offset, size));
			CopyRules.Downgrade(type, target);
		}

		private void Sound(RecipeStep step)
		{
			Resolved resolved = Get(step);
			AssetTypeValueField assetTypeValueField = resolved.Field["m_Resource"];
			string value2;
			byte[] value = FsbVorbisDecoder.DecodeToWav(_sources.ReadResource(resolved.Bundle, assetTypeValueField["m_Source"].AsString, (long)assetTypeValueField["m_Offset"].AsULong, (long)assetTypeValueField["m_Size"].AsULong), (uint crc) => (!_recipe.VorbisSetups.TryGetValue(crc, out value2)) ? null : File.ReadAllBytes(_recipe.PathOf(value2)));
			Target(step.Target)["m_Script"].Value = new AssetTypeValue(value, asString: true);
		}

		private void EmissiveMask(RecipeStep step)
		{
			RgbaImage rgbaImage = TextureCodec.Decode(Target(step.Id("from")));
			RgbaImage rgbaImage2 = new RgbaImage(rgbaImage.Width, rgbaImage.Height);
			for (int i = 0; i < rgbaImage.Pixels.Length; i += 4)
			{
				int num = RgbaImage.ToByte(rgbaImage.Pixels[i]);
				int num2 = RgbaImage.ToByte(rgbaImage.Pixels[i + 1]);
				int num3 = RgbaImage.ToByte(rgbaImage.Pixels[i + 2]);
				bool flag = num > 180 && num2 > 120 && num3 < 110 && num - num3 > 110;
				rgbaImage2.Pixels[i] = (flag ? rgbaImage.Pixels[i] : 0f);
				rgbaImage2.Pixels[i + 1] = (flag ? rgbaImage.Pixels[i + 1] : 0f);
				rgbaImage2.Pixels[i + 2] = (flag ? rgbaImage.Pixels[i + 2] : 0f);
				rgbaImage2.Pixels[i + 3] = 1f;
			}
			TextureCodec.Write(Target(step.Target), rgbaImage2, withAlpha: false);
		}

		private RgbaImage SpriteImage(Resolved sprite)
		{
			AssetTypeValueField assetTypeValueField = sprite.Field["m_RD"];
			AssetTypeValueField assetTypeValueField2 = assetTypeValueField["texture"];
			if (assetTypeValueField2["m_FileID"].AsInt != 0)
			{
				throw new SetupException("setup.error.version", "Sprite texture in another file");
			}
			AssetTypeValueField assetTypeValueField3 = _sources.Read(sprite.Bundle, assetTypeValueField2["m_PathID"].AsLong);
			if (assetTypeValueField3 == null)
			{
				throw new SetupException("setup.error.version", "Sprite texture missing");
			}
			AssetTypeValueField assetTypeValueField4 = _sources.Read(sprite.Bundle, assetTypeValueField2["m_PathID"].AsLong);
			CopyRules.InlineStreamData(AssetClassID.Texture2D, assetTypeValueField4, assetTypeValueField3, (string path, long offset, long size) => _sources.ReadResource(sprite.Bundle, path, offset, size));
			RgbaImage rgbaImage = TextureCodec.Decode(assetTypeValueField4);
			AssetTypeValueField assetTypeValueField5 = assetTypeValueField["textureRect"];
			int x = (int)Math.Round(assetTypeValueField5["x"].AsFloat);
			int x2 = (int)Math.Round(assetTypeValueField5["x"].AsFloat + assetTypeValueField5["width"].AsFloat);
			int num = (int)Math.Round(assetTypeValueField5["y"].AsFloat);
			int num2 = (int)Math.Round(assetTypeValueField5["y"].AsFloat + assetTypeValueField5["height"].AsFloat);
			return ImageOps.Crop(rgbaImage, x, rgbaImage.Height - num2, x2, rgbaImage.Height - num);
		}

		private RgbaImage Layer(string file)
		{
			if (!string.IsNullOrEmpty(file))
			{
				return RgbaImage.ReadPng(File.ReadAllBytes(_recipe.PathOf(file)));
			}
			return null;
		}

		private static Mask Fit(Mask alpha, double angle, double box)
		{
			Mask mask = ImageOps.Rotate(alpha, angle);
			(int, int, int, int)? tuple = ImageOps.BoundingBox(mask);
			if (tuple.HasValue)
			{
				mask = ImageOps.Crop(mask, tuple.Value.Item1, tuple.Value.Item2, tuple.Value.Item3, tuple.Value.Item4);
			}
			double num = box / (double)Math.Max(mask.Width, mask.Height);
			return ImageOps.Resize(mask, Math.Max(1, (int)((double)mask.Width * num)), Math.Max(1, (int)((double)mask.Height * num)));
		}

		private void SkillIcon(RecipeStep step)
		{
			float[] array = step.Color("color");
			double angle = step.Num("angle", 32.0);
			double num = step.Num("box", 212.0);
			RgbaImage rgbaImage = Layer(step.Str("under"));
			Mask mask = Mask.AlphaOf(SpriteImage(Get(step)));
			Mask mask2 = Fit(mask, angle, num);
			int width = rgbaImage.Width;
			if (step.Glow != null)
			{
				if (!_resolvedGlow.TryGetValue(step, out var value))
				{
					throw new SetupException("setup.error.version", "Glow sprite of " + step.Label + " not found");
				}
				Mask mask3 = Mask.AlphaOf(SpriteImage(value));
				Mask mask4 = Fit(mask3, angle, num * (double)Math.Max(mask3.Width, mask3.Height) / (double)Math.Max(mask.Width, mask.Height));
				ImageOps.AlphaComposite(rgbaImage, ImageOps.Tinted(ImageOps.GaussianBlur(mask4, 3.0), array[0] / 255f, array[1] / 255f, array[2] / 255f), (width - mask4.Width) / 2, (width - mask4.Height) / 2);
			}
			int ox = (width - mask2.Width) / 2;
			int oy = (width - mask2.Height) / 2;
			ImageOps.AlphaComposite(rgbaImage, ImageOps.Tinted(ImageOps.MaxFilter(mask2, 7), 0f, 0f, 0f, 200), ox, oy);
			ImageOps.AlphaComposite(rgbaImage, ImageOps.Tinted(mask2, 1f, 1f, 1f), ox, oy);
			RgbaImage rgbaImage2 = Layer(step.Str("over"));
			if (rgbaImage2 != null)
			{
				ImageOps.AlphaComposite(rgbaImage, rgbaImage2);
			}
			TextureCodec.Write(Target(step.Target), rgbaImage);
		}

		private void Portrait(RecipeStep step)
		{
			RgbaImage rgbaImage = SpriteImage(Get(step));
			int width = rgbaImage.Width;
			int height = rgbaImage.Height;
			RgbaImage src = ImageOps.Crop(rgbaImage, (int)((double)width * 0.25), (int)((double)height * 0.12), (int)((double)width * 0.75), (int)((double)height * 0.62));
			src = ImageOps.Resize(src, 236, 236);
			RgbaImage rgbaImage2 = Layer(step.Str("under"));
			float[] array = step.Color("glow");
			ImageOps.AlphaComposite(rgbaImage2, ImageOps.Tinted(ImageOps.GaussianBlur(Mask.AlphaOf(src), 8.0), array[0] / 255f, array[1] / 255f, array[2] / 255f, 160), 10, 14);
			ImageOps.AlphaComposite(rgbaImage2, src, 10, 14);
			RgbaImage rgbaImage3 = Layer(step.Str("over"));
			if (rgbaImage3 != null)
			{
				ImageOps.AlphaComposite(rgbaImage2, rgbaImage3);
			}
			TextureCodec.Write(Target(step.Target), rgbaImage2);
		}

		private void Portrait3D(RecipeStep step)
		{
			SceneReader sceneReader = new SceneReader(_manager, _template, _overrides);
			long num = sceneReader.FindRoot(step.Str("prefab"));
			if (num == 0L)
			{
				throw new SetupException("setup.error.template", "Prefab " + step.Str("prefab") + " missing from the template");
			}
			RgbaImage image = new PortraitRenderer
			{
				TargetY = step.Num("targetY", 1.4),
				Distance = step.Num("distance", 1.45),
				Yaw = step.Num("yaw", 32.0),
				Pitch = step.Num("pitch", -8.0),
				Fov = step.Num("fov", 28.0)
			}.Render(sceneReader, num, Layer(step.Str("under")), Layer(step.Str("over")));
			TextureCodec.Write(Target(step.Target), image);
		}

		private void Bake(RecipeStep step)
		{
			AssetTypeValueField assetTypeValueField = Target(step.Id("from"));
			AssetTypeValueField assetTypeValueField2 = Target(step.Target);
			List<Mat4> list = new List<Mat4>();
			foreach (object item in MiniJson.Arr(step.Args, "bones"))
			{
				list.Add(Mat4.FromColumnMajor(((List<object>)item).Select((object v) => (double)v).ToList()));
			}
			MeshVertexData meshVertexData = new MeshVertexData(assetTypeValueField["m_VertexData"]);
			MeshVertexData meshVertexData2 = new MeshVertexData(assetTypeValueField2["m_VertexData"]);
			if (meshVertexData.VertexCount != meshVertexData2.VertexCount)
			{
				throw new SetupException("setup.error.version", $"Mesh {step.Label}: {meshVertexData.VertexCount} vertices, expected {meshVertexData2.VertexCount}");
			}
			meshVertexData2.Data = new byte[meshVertexData2.RequiredSize];
			int num = meshVertexData.Dimension(13);
			int num2 = meshVertexData.Dimension(12);
			double val = double.MaxValue;
			double val2 = double.MaxValue;
			double val3 = double.MaxValue;
			double val4 = double.MinValue;
			double val5 = double.MinValue;
			double val6 = double.MinValue;
			(double, double, double)[] array = new(double, double, double)[meshVertexData.VertexCount];
			for (int num3 = 0; num3 < meshVertexData.VertexCount; num3++)
			{
				double[] array2 = new double[16];
				double num4 = 0.0;
				for (int num5 = 0; num5 < Math.Max(num, 1); num5++)
				{
					int num6 = ((num > 0) ? ((int)meshVertexData.Get(13, num3, num5)) : 0);
					double num7 = ((num2 > num5) ? meshVertexData.Get(12, num3, num5) : ((float)((num5 == 0 && num2 == 0) ? 1 : 0)));
					if (num5 == num - 1 && num2 > 0 && num2 < num)
					{
						num7 = 1.0 - num4;
					}
					if (num7 != 0.0 && num6 < list.Count)
					{
						num4 += num7;
						for (int num8 = 0; num8 < 16; num8++)
						{
							array2[num8] += list[num6].M[num8] * num7;
						}
					}
				}
				Mat4 mat = new Mat4
				{
					M = array2
				};
				for (int num9 = 0; num9 < meshVertexData2.Channels.Length; num9++)
				{
					if (!meshVertexData2.Has(num9) || !meshVertexData.Has(num9))
					{
						continue;
					}
					int num10 = Math.Min(meshVertexData2.Dimension(num9), meshVertexData.Dimension(num9));
					switch (num9)
					{
					case 0:
					{
						(double, double, double) tuple = (array[num3] = mat.Point(meshVertexData.Get(0, num3, 0), meshVertexData.Get(0, num3, 1), meshVertexData.Get(0, num3, 2)));
						meshVertexData2.Set(0, num3, 0, (float)tuple.Item1);
						meshVertexData2.Set(0, num3, 1, (float)tuple.Item2);
						meshVertexData2.Set(0, num3, 2, (float)tuple.Item3);
						val = Math.Min(val, tuple.Item1);
						val2 = Math.Min(val2, tuple.Item2);
						val3 = Math.Min(val3, tuple.Item3);
						val4 = Math.Max(val4, tuple.Item1);
						val5 = Math.Max(val5, tuple.Item2);
						val6 = Math.Max(val6, tuple.Item3);
						break;
					}
					case 1:
					case 2:
					{
						(double, double, double) tuple2 = mat.Vector(meshVertexData.Get(num9, num3, 0), meshVertexData.Get(num9, num3, 1), meshVertexData.Get(num9, num3, 2));
						double num12 = Math.Sqrt(tuple2.Item1 * tuple2.Item1 + tuple2.Item2 * tuple2.Item2 + tuple2.Item3 * tuple2.Item3);
						if (num12 > 1E-12)
						{
							tuple2 = (tuple2.Item1 / num12, tuple2.Item2 / num12, tuple2.Item3 / num12);
						}
						meshVertexData2.Set(num9, num3, 0, (float)tuple2.Item1);
						meshVertexData2.Set(num9, num3, 1, (float)tuple2.Item2);
						meshVertexData2.Set(num9, num3, 2, (float)tuple2.Item3);
						if (num10 > 3)
						{
							meshVertexData2.Set(num9, num3, 3, meshVertexData.Get(num9, num3, 3));
						}
						break;
					}
					default:
					{
						for (int num11 = 0; num11 < num10; num11++)
						{
							meshVertexData2.Set(num9, num3, num11, meshVertexData.Get(num9, num3, num11));
						}
						break;
					}
					}
				}
			}
			FieldCopier.WriteBytes(assetTypeValueField2["m_VertexData"]["m_DataSize"], meshVertexData2.Data);
			FieldCopier.WriteBytes(assetTypeValueField2["m_IndexBuffer"], FieldCopier.ReadBytes(assetTypeValueField["m_IndexBuffer"]));
			assetTypeValueField2["m_IndexFormat"].AsInt = assetTypeValueField["m_IndexFormat"].AsInt;
			new FieldCopier().Copy(assetTypeValueField2["m_SubMeshes"], assetTypeValueField["m_SubMeshes"]);
			foreach (AssetTypeValueField child in assetTypeValueField2["m_SubMeshes"]["Array"].Children)
			{
				SetBounds(first: (int)child["firstVertex"].AsUInt, count: (int)child["vertexCount"].AsUInt, aabb: child["localAABB"], p: array);
			}
			SetBounds(assetTypeValueField2["m_LocalAABB"], array, 0, array.Length);
			CopyRules.ClearStream(assetTypeValueField2);
		}

		private static void SetBounds(AssetTypeValueField aabb, (double x, double y, double z)[] p, int first, int count)
		{
			double num = double.MaxValue;
			double num2 = double.MaxValue;
			double num3 = double.MaxValue;
			double num4 = double.MinValue;
			double num5 = double.MinValue;
			double num6 = double.MinValue;
			for (int i = first; i < first + count && i < p.Length; i++)
			{
				num = Math.Min(num, p[i].x);
				num2 = Math.Min(num2, p[i].y);
				num3 = Math.Min(num3, p[i].z);
				num4 = Math.Max(num4, p[i].x);
				num5 = Math.Max(num5, p[i].y);
				num6 = Math.Max(num6, p[i].z);
			}
			if (count <= 0 || num > num4)
			{
				num = (num2 = (num3 = (num4 = (num5 = (num6 = 0.0)))));
			}
			aabb["m_Center"]["x"].AsFloat = (float)((num + num4) / 2.0);
			aabb["m_Center"]["y"].AsFloat = (float)((num2 + num5) / 2.0);
			aabb["m_Center"]["z"].AsFloat = (float)((num3 + num6) / 2.0);
			aabb["m_Extent"]["x"].AsFloat = (float)((num4 - num) / 2.0);
			aabb["m_Extent"]["y"].AsFloat = (float)((num5 - num2) / 2.0);
			aabb["m_Extent"]["z"].AsFloat = (float)((num6 - num3) / 2.0);
		}

		private void PickupIcon(RecipeStep step)
		{
			SceneReader sceneReader = new SceneReader(_manager, _template, _overrides);
			long num = sceneReader.FindRoot(step.Str("prefab"));
			if (num == 0L)
			{
				throw new SetupException("setup.error.template", "Pickup prefab " + step.Str("prefab") + " missing from the template");
			}
			float[] array = step.Color("color");
			RgbaImage image = new PickupIconRenderer(sceneReader).Render(num, array[0], array[1], array[2]);
			TextureCodec.Write(Target(step.Target), image);
		}
	}
	public sealed class AssetState
	{
		public const string FileName = "assets.json";

		public string AssetVersion;

		public string RecipeSha256;

		public string BundleFile;

		public string BundleSha256;

		public long BundleSize;

		public string ModVersion;

		public string CreatedUtc;

		public string GameUnityVersion;

		public string GameBuildId;

		public int ChangedSources;

		public int SkippedOptional;

		public List<string> Warnings = new List<string>();

		public static AssetState Load(string folder)
		{
			string path = Path.Combine(folder, "assets.json");
			if (!File.Exists(path))
			{
				return null;
			}
			try
			{
				object o = MiniJson.Parse(File.ReadAllText(path));
				AssetState assetState = new AssetState
				{
					AssetVersion = MiniJson.Str(o, "assetVersion"),
					RecipeSha256 = MiniJson.Str(o, "recipeSha256"),
					BundleFile = MiniJson.Str(o, "bundleFile"),
					BundleSha256 = MiniJson.Str(o, "bundleSha256"),
					BundleSize = MiniJson.Long(o, "bundleSize"),
					ModVersion = MiniJson.Str(o, "modVersion"),
					CreatedUtc = MiniJson.Str(o, "createdUtc"),
					GameUnityVersion = MiniJson.Str(o, "gameUnityVersion"),
					GameBuildId = MiniJson.Str(o, "gameBuildId"),
					ChangedSources = (int)MiniJson.Num(o, "changedSources"),
					SkippedOptional = (int)MiniJson.Num(o, "skippedOptional")
				};
				foreach (object item in MiniJson.Arr(o, "warnings") ?? new List<object>())
				{
					assetState.Warnings.Add(Convert.ToString(item, CultureInfo.InvariantCulture));
				}
				return assetState;
			}
			catch (Exception)
			{
				return null;
			}
		}

		public void Save(string folder)
		{
			Dictionary<string, object> value = new Dictionary<string, object>
			{
				["assetVersion"] = AssetVersion,
				["recipeSha256"] = RecipeSha256,
				["bundleFile"] = BundleFile,
				["bundleSha256"] = BundleSha256,
				["bundleSize"] = BundleSize,
				["modVersion"] = ModVersion,
				["createdUtc"] = CreatedUtc,
				["gameUnityVersion"] = GameUnityVersion,
				["gameBuildId"] = GameBuildId,
				["changedSources"] = ChangedSources,
				["skippedOptional"] = SkippedOptional,
				["warnings"] = Warnings
			};
			AtomicFile.WriteAllText(Path.Combine(folder, "assets.json"), MiniJson.Write(value));
		}
	}
	public enum AssetStatus
	{
		Ready,
		Missing,
		Outdated,
		Damaged,
		SetupFilesMissing
	}
	public sealed class AssetCheck
	{
		public AssetStatus Status;

		public string BundlePath;

		public AssetState State;

		public string Detail;
	}
	public static class AssetDetector
	{
		public static AssetCheck Check(string recipeFolder, string assetFolder, bool fullHash = true)
		{
			AssetCheck assetCheck = new AssetCheck();
			string path = Path.Combine(recipeFolder ?? "", "recipe.json");
			if (recipeFolder == null || !File.Exists(path))
			{
				assetCheck.Status = AssetStatus.SetupFilesMissing;
				assetCheck.Detail = "recipe.json not found in " + recipeFolder;
				return assetCheck;
			}
			Recipe recipe;
			try
			{
				recipe = Recipe.Load(recipeFolder);
			}
			catch (Exception ex)
			{
				assetCheck.Status = AssetStatus.SetupFilesMissing;
				assetCheck.Detail = "recipe.json unreadable: " + ex.Message;
				return assetCheck;
			}
			assetCheck.BundlePath = Path.Combine(assetFolder, recipe.OutputFile);
			assetCheck.State = AssetState.Load(assetFolder);
			if (assetCheck.State == null)
			{
				assetCheck.Status = ((!File.Exists(assetCheck.BundlePath)) ? AssetStatus.Missing : AssetStatus.Damaged);
				assetCheck.Detail = "no assets.json";
				return assetCheck;
			}
			if (assetCheck.State.AssetVersion != recipe.AssetVersion || assetCheck.State.RecipeSha256 != RecipeSha(recipeFolder))
			{
				assetCheck.Status = AssetStatus.Outdated;
				assetCheck.Detail = "assets " + assetCheck.State.AssetVersion + ", mod needs " + recipe.AssetVersion;
				return assetCheck;
			}
			FileInfo fileInfo = new FileInfo(assetCheck.BundlePath);
			if (!fileInfo.Exists || fileInfo.Length != assetCheck.State.BundleSize)
			{
				assetCheck.Status = AssetStatus.Damaged;
				assetCheck.Detail = (fileInfo.Exists ? "bundle size changed" : "bundle missing");
				return assetCheck;
			}
			if (fullHash && SourceBundles.Sha256(File.ReadAllBytes(assetCheck.BundlePath)) != assetCheck.State.BundleSha256)
			{
				assetCheck.Status = AssetStatus.Damaged;
				assetCheck.Detail = "bundle checksum changed";
				return assetCheck;
			}
			assetCheck.Status = AssetStatus.Ready;
			return assetCheck;
		}

		public static string RecipeSha(string recipeFolder)
		{
			return SourceBundles.Sha256(File.ReadAllBytes(Path.Combine(recipeFolder, "recipe.json")));
		}
	}
	public static class AssetInstaller
	{
		public static void Install(string builtFile, string assetFolder, AssetState state, Action<string> log)
		{
			string text = Path.Combine(assetFolder, state.BundleFile);
			string text2 = text + ".bak";
			string text3 = Path.Combine(assetFolder, "assets.json");
			string text4 = text3 + ".bak";
			byte[] array = new byte[7];
			using (FileStream fileStream = File.OpenRead(builtFile))
			{
				if (fileStream.Length < 1024 || fileStream.Read(array, 0, 7) != 7 || Encoding.ASCII.GetString(array) != "UnityFS")
				{
					throw new SetupException("setup.error.write", "The generated bundle is not valid");
				}
			}
			state.BundleSize = new FileInfo(builtFile).Length;
			state.BundleSha256 = SourceBundles.Sha256(File.ReadAllBytes(builtFile));
			bool flag = File.Exists(text);
			bool flag2 = File.Exists(text3);
			try
			{
				if (flag)
				{
					Replace(text, text2);
				}
				if (flag2)
				{
					Replace(text3, text4);
				}
				File.Move(builtFile, text);
				state.Save(assetFolder);
				TryDelete(text2);
				TryDelete(text4);
				log?.Invoke("Installed " + text);
			}
			catch (Exception ex)
			{
				log?.Invoke("Install failed, restoring the previous assets: " + ex.Message);
				TryDelete(text);
				if (flag && File.Exists(text2))
				{
					File.Move(text2, text);
				}
				TryDelete(text3);
				if (flag2 && File.Exists(text4))
				{
					File.Move(text4, text3);
				}
				throw new SetupException("setup.error.write", "Cannot install the generated files: " + ex.Message, ex);
			}
		}

		public static void Recover(string assetFolder, string bundleFile, Action<string> log)
		{
			if (!Directory.Exists(assetFolder))
			{
				return;
			}
			string text = Path.Combine(assetFolder, bundleFile);
			string text2 = Path.Combine(assetFolder, "assets.json");
			if (!File.Exists(text) && File.Exists(text + ".bak"))
			{
				File.Move(text + ".bak", text);
				log?.Invoke("Restored backup bundle");
			}
			if (!File.Exists(text2) && File.Exists(text2 + ".bak"))
			{
				File.Move(text2 + ".bak", text2);
				log?.Invoke("Restored backup state");
			}
			string[] array = new string[4] { "*.building", "*.raw", "*.bak", "*.tmp" };
			foreach (string searchPattern in array)
			{
				string[] files = Directory.GetFiles(assetFolder, searchPattern);
				for (int j = 0; j < files.Length; j++)
				{
					TryDelete(files[j]);
				}
			}
		}

		private static void Replace(string from, string to)
		{
			TryDelete(to);
			File.Move(from, to);
		}

		private static void TryDelete(string path)
		{
			try
			{
				if (File.Exists(path))
				{
					File.Delete(path);
				}
			}
			catch (IOException)
			{
			}
			catch (UnauthorizedAccessException)
			{
			}
		}
	}
	public static class AtomicFile
	{
		public static void WriteAllText(string path, string text)
		{
			string text2 = path + ".tmp";
			File.WriteAllText(text2, text);
			if (File.Exists(path))
			{
				File.Delete(path);
			}
			File.Move(text2, path);
		}
	}
	public static class GameLocator
	{
		public const string SteamAppId = "1229490";

		public const string FolderName = "ULTRAKILL";

		public static bool IsGameFolder(string folder)
		{
			if (string.IsNullOrEmpty(folder))
			{
				return false;
			}
			try
			{
				string text = SourceBundles.AddressablesFolder(folder);
				return Directory.Exists(text) && File.Exists(Path.Combine(text, "assets_assets_assets", "models.bundle"));
			}
			catch (Exception)
			{
				return false;
			}
		}

		public static string Normalize(string chosen)
		{
			if (string.IsNullOrWhiteSpace(chosen))
			{
				return null;
			}
			try
			{
				string text = Path.GetFullPath(chosen.Trim().Trim(new char[1] { '"' }));
				if (File.Exists(text))
				{
					text = Path.GetDirectoryName(text);
				}
				for (int i = 0; i < 6; i++)
				{
					if (string.IsNullOrEmpty(text))
					{
						break;
					}
					if (IsGameFolder(text))
					{
						return text;
					}
					string text2 = Path.Combine(text, "ULTRAKILL");
					if (IsGameFolder(text2))
					{
						return text2;
					}
					text = Path.GetDirectoryName(text);
				}
			}
			catch (Exception)
			{
			}
			return null;
		}

		public static string Find(string preferred, Action<string> log = null)
		{
			string text = Normalize(preferred);
			if (text != null)
			{
				return text;
			}
			foreach (string item in SteamLibraries(log))
			{
				string path = Path.Combine(item, "steamapps", "appmanifest_1229490.acf");
				string path2 = "ULTRAKILL";
				try
				{
					if (File.Exists(path))
					{
						Match match = Regex.Match(File.ReadAllText(path), "\"installdir\"\\s+\"([^\"]+)\"");
						if (match.Success)
						{
							path2 = match.Groups[1].Value;
						}
					}
				}
				catch (Exception)
				{
				}
				string text2 = Path.Combine(item, "steamapps", "common", path2);
				if (IsGameFolder(text2))
				{
					return text2;
				}
			}
			foreach (string item2 in OtherLocations())
			{
				if (IsGameFolder(item2))
				{
					return item2;
				}
			}
			return null;
		}

		public static string BuildId(string gameFolder)
		{
			try
			{
				string path = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(gameFolder)), "appmanifest_1229490.acf");
				if (!File.Exists(path))
				{
					return "";
				}
				Match match = Regex.Match(File.ReadAllText(path), "\"buildid\"\\s+\"(\\d+)\"");
				return match.Success ? match.Groups[1].Value : "";
			}
			catch (Exception)
			{
				return "";
			}
		}

		public static List<string> SteamLibraries(Action<string> log = null)
		{
			List<string> roots = new List<string>();
			AddRoot(RegistryString("HKEY_CURRENT_USER\\Software\\Valve\\Steam", "SteamPath"));
			AddRoot(RegistryString("HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Valve\\Steam", "InstallPath"));
			AddRoot(RegistryString("HKEY_LOCAL_MACHINE\\SOFTWARE\\Valve\\Steam", "InstallPath"));
			AddRoot("C:\\Program Files (x86)\\Steam");
			AddRoot("C:\\Program Files\\Steam");
			foreach (string item in LinuxHomes())
			{
				AddRoot(Path.Combine(item, ".steam", "steam"));
				AddRoot(Path.Combine(item, ".local", "share", "Steam"));
				AddRoot(Path.Combine(item, ".var", "app", "com.valvesoftware.Steam", ".local", "share", "Steam"));
			}
			List<string> list = new List<string>(roots);
			foreach (string item2 in roots)
			{
				string text = Path.Combine(item2, "steamapps", "libraryfolders.vdf");
				try
				{
					if (!File.Exists(text))
					{
						continue;
					}
					foreach (Match item3 in Regex.Matches(File.ReadAllText(text), "\"path\"\\s+\"([^\"]+)\""))
					{
						string text2 = item3.Groups[1].Value.Replace("\\\\", "\\");
						if (text2.StartsWith("/"))
						{
							text2 = "Z:" + text2;
						}
						AddLibrary(list, text2);
					}
				}
				catch (Exception ex)
				{
					log?.Invoke("Cannot read " + text + ": " + ex.Message);
				}
			}
			foreach (DriveInfo item4 in SafeDrives())
			{
				AddLibrary(list, Path.Combine(item4.RootDirectory.FullName, "SteamLibrary"));
				AddLibrary(list, Path.Combine(item4.RootDirectory.FullName, "Steam"));
			}
			return list;
			void AddRoot(string path)
			{
				if (string.IsNullOrEmpty(path))
				{
					return;
				}
				try
				{
					path = Path.GetFullPath(path.Replace('/', Path.DirectorySeparatorChar));
					if (Directory.Exists(path) && !roots.Exists((string r) => string.Equals(r, path, StringComparison.OrdinalIgnoreCase)))
					{
						roots.Add(path);
					}
				}
				catch (Exception)
				{
				}
			}
		}

		private static void AddLibrary(List<string> libraries, string path)
		{
			try
			{
				path = Path.GetFullPath(path);
				if (Directory.Exists(Path.Combine(path, "steamapps")) && !libraries.Exists((string r) => string.Equals(r, path, StringComparison.OrdinalIgnoreCase)))
				{
					libraries.Add(path);
				}
			}
			catch (Exception)
			{
			}
		}

		private static IEnumerable<string> OtherLocations()
		{
			foreach (DriveInfo item in SafeDrives())
			{
				string root = item.RootDirectory.FullName;
				yield return Path.Combine(root, "GOG Games", "ULTRAKILL");
				yield return Path.Combine(root, "Games", "ULTRAKILL");
				yield return Path.Combine(root, "ULTRAKILL");
			}
		}

		private static IEnumerable<string> LinuxHomes()
		{
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string path = Path.Combine("Z:" + directorySeparatorChar, "home");
			try
			{
				return Directory.Exists(path) ? ((IEnumerable<string>)Directory.GetDirectories(path)) : ((IEnumerable<string>)new string[0]);
			}
			catch (Exception)
			{
				return new string[0];
			}
		}

		private static IEnumerable<DriveInfo> SafeDrives()
		{
			List<DriveInfo> list = new List<DriveInfo>();
			try
			{
				DriveInfo[] drives = DriveInfo.GetDrives();
				foreach (DriveInfo driveInfo in drives)
				{
					try
					{
						if (driveInfo.IsReady && (driveInfo.DriveType == DriveType.Fixed || driveInfo.DriveType == DriveType.Removable))
						{
							list.Add(driveInfo);
						}
					}
					catch (Exception)
					{
					}
				}
			}
			catch (Exception)
			{
			}
			return list;
		}

		private static string RegistryString(string key, string name)
		{
			try
			{
				return (Type.GetType("Microsoft.Win32.Registry, mscorlib") ?? Type.GetType("Microsoft.Win32.Registry, Microsoft.Win32.Registry"))?.GetMethod("GetValue", new Type[3]
				{
					typeof(string),
					typeof(string),
					typeof(object)
				})?.Invoke(null, new object[3] { key, name, null }) as string;
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
	public sealed class SourceRef
	{
		public string Bundle;

		public long PathId;

		public string Type;

		public string Name;

		public string Signature;

		public string Sha256;

		public static SourceRef From(Dictionary<string, object> o)
		{
			if (o == null)
			{
				return null;
			}
			return new SourceRef
			{