Decompiled source of hololive English Justice v1.0.1

JusticeSuit.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using GameNetcodeStuff;
using HarmonyLib;
using ModelReplacement;
using ModelReplacement.AvatarBodyUpdater;
using ModelReplacement.Scripts.Player;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace JusticeSuit;

[Serializable]
public struct JusticeLightingContext
{
	public bool InsideFactory;

	public bool InsideShip;

	public bool Indoors
	{
		get
		{
			if (!InsideFactory)
			{
				return InsideShip;
			}
			return true;
		}
	}

	public float Floor
	{
		get
		{
			if (!Indoors)
			{
				return 0.075f;
			}
			return 0f;
		}
	}

	public JusticeLightingContext(bool factory, bool ship)
	{
		InsideFactory = factory;
		InsideShip = ship;
	}
}
public sealed class JusticeCorpseLightingContext
{
	private JusticeLightingContext context;

	private bool trackedItem;

	public JusticeCorpseLightingContext(JusticeLightingContext death)
	{
		context = death;
	}

	public JusticeLightingContext Observe(bool bodyInShip, bool hasHolder, JusticeLightingContext holder, bool hasItem, JusticeLightingContext item)
	{
		if (hasHolder)
		{
			context = holder;
			trackedItem = true;
		}
		else if (hasItem && trackedItem)
		{
			context = item;
		}
		if (!bodyInShip)
		{
			return context;
		}
		return new JusticeLightingContext(factory: false, ship: true);
	}
}
[DefaultExecutionOrder(600)]
public sealed class JusticeAdaptiveLighting : MonoBehaviour
{
	private struct Draw
	{
		public Renderer Renderer;

		public int Slot;

		public bool Floor;

		public bool Ink;

		public Color InkColor;
	}

	public Renderer[] receivers;

	private readonly List<Draw> draws = new List<Draw>();

	private MaterialPropertyBlock block;

	private Func<JusticeLightingContext> contextReader;

	private bool initialized;

	private static readonly int FloorId = Shader.PropertyToID("_GflAmbientFloor");

	private static readonly int InkId = Shader.PropertyToID("_InkColor");

	public JusticeLightingContext Context { get; private set; }

	public float CurrentFloor => Context.Floor;

	public int FloorSlots { get; private set; }

	public int InkSlots { get; private set; }

	private void Awake()
	{
		Rebind();
		Refresh();
	}

	private void OnEnable()
	{
		if (initialized)
		{
			Refresh();
		}
	}

	public void Rebind()
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Expected O, but got Unknown
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		if (block == null)
		{
			block = new MaterialPropertyBlock();
		}
		draws.Clear();
		int floorSlots = (InkSlots = 0);
		FloorSlots = floorSlots;
		receivers = ((Component)this).GetComponentsInChildren<Renderer>(true);
		Renderer[] array = receivers;
		foreach (Renderer val in array)
		{
			Material[] sharedMaterials = val.sharedMaterials;
			for (int i = 0; i < sharedMaterials.Length; i++)
			{
				Material val2 = sharedMaterials[i];
				if (!Object.op_Implicit((Object)(object)val2))
				{
					continue;
				}
				bool flag = val2.HasProperty(FloorId);
				bool flag2 = val2.HasProperty(InkId);
				if (flag || flag2)
				{
					draws.Add(new Draw
					{
						Renderer = val,
						Slot = i,
						Floor = flag,
						Ink = flag2,
						InkColor = (flag2 ? val2.GetColor(InkId) : Color.black)
					});
					if (flag)
					{
						FloorSlots++;
					}
					if (flag2)
					{
						InkSlots++;
					}
				}
			}
		}
		initialized = true;
		Apply(Context);
	}

	public void BindContext(Func<JusticeLightingContext> reader)
	{
		contextReader = reader;
		Refresh();
	}

	public JusticeLightingContext ReadContext()
	{
		if (contextReader == null)
		{
			return Context;
		}
		return contextReader();
	}

	public void InheritContext(JusticeAdaptiveLighting source)
	{
		if (Object.op_Implicit((Object)(object)source))
		{
			BindContext(source.ReadContext);
		}
	}

	public void Refresh()
	{
		Apply(ReadContext());
	}

	public void Apply(JusticeLightingContext context)
	{
		//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_00be: 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)
		if (!initialized)
		{
			Rebind();
		}
		Context = context;
		foreach (Draw draw in draws)
		{
			if (!Object.op_Implicit((Object)(object)draw.Renderer))
			{
				continue;
			}
			block.Clear();
			draw.Renderer.GetPropertyBlock(block, draw.Slot);
			if (draw.Floor)
			{
				block.SetFloat(FloorId, context.Floor);
			}
			if (draw.Ink)
			{
				Color inkColor = draw.InkColor;
				if (context.Indoors)
				{
					((Color)(ref inkColor))..ctor(0f, 0f, 0f, inkColor.a);
				}
				block.SetColor(InkId, inkColor);
			}
			draw.Renderer.SetPropertyBlock(block, draw.Slot);
		}
	}

	private void LateUpdate()
	{
		Refresh();
	}
}
internal static class JusticeLightingControl
{
	private sealed class Death
	{
		internal ulong Owner;

		internal JusticeLightingContext Context;
	}

	private static readonly Dictionary<PlayerControllerB, Death> deaths = new Dictionary<PlayerControllerB, Death>();

	private static readonly FieldInfo sourceField = AccessTools.Field(typeof(BodyReplacementBase), "replacementModel");

	private static readonly FieldInfo shadowField = AccessTools.Field(typeof(BodyReplacementBase), "replacementModelShadow");

	private static readonly FieldInfo viewField = AccessTools.Field(typeof(BodyReplacementBase), "replacementViewModel");

	private static JusticeLightingContext Native(PlayerControllerB player)
	{
		if (!Object.op_Implicit((Object)(object)player))
		{
			return default(JusticeLightingContext);
		}
		return new JusticeLightingContext(player.isInsideFactory, player.isInHangarShipRoom);
	}

	internal static void Install(Harmony harmony)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Expected O, but got Unknown
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Expected O, but got Unknown
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Expected O, but got Unknown
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		harmony.Patch((MethodBase)AccessTools.Method(typeof(BodyReplacementBase), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(JusticeLightingControl), "Created", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		MethodInfo methodInfo = AccessTools.Method(typeof(BodyReplacementBase), "LoadRagdollReplacement", (Type[])null, (Type[])null);
		if (methodInfo != null)
		{
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(JusticeLightingControl), "Ragdoll", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerControllerB), "KillPlayer", (Type[])null, (Type[])null), new HarmonyMethod(typeof(JusticeLightingControl), "CaptureDeath", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerControllerB), "SpawnDeadBody", (Type[])null, (Type[])null), new HarmonyMethod(typeof(JusticeLightingControl), "CaptureRemoteDeath", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(StartOfRound), "ReviveDeadPlayers", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(JusticeLightingControl), "Clear", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static void CaptureDeath(PlayerControllerB __instance)
	{
		if (Object.op_Implicit((Object)(object)__instance) && !__instance.isPlayerDead)
		{
			deaths[__instance] = new Death
			{
				Owner = ((NetworkBehaviour)__instance).OwnerClientId,
				Context = Native(__instance)
			};
		}
	}

	private static void CaptureRemoteDeath(PlayerControllerB deadPlayerController)
	{
		if (Object.op_Implicit((Object)(object)deadPlayerController) && !((NetworkBehaviour)deadPlayerController).IsOwner)
		{
			deaths[deadPlayerController] = new Death
			{
				Owner = ((NetworkBehaviour)deadPlayerController).OwnerClientId,
				Context = Native(deadPlayerController)
			};
		}
	}

	private static void Created(BodyReplacementBase __instance)
	{
		if (__instance is JusticeBody justiceBody && Object.op_Implicit((Object)(object)((BodyReplacementBase)justiceBody).controller))
		{
			FieldInfo[] array = new FieldInfo[3] { sourceField, shadowField, viewField };
			for (int i = 0; i < array.Length; i++)
			{
				object? obj = array[i]?.GetValue(justiceBody);
				Bind((GameObject)((obj is GameObject) ? obj : null), ((BodyReplacementBase)justiceBody).controller);
			}
		}
	}

	internal static void AttachView(GameObject playerObject, GameObject view)
	{
		if (Object.op_Implicit((Object)(object)playerObject) && Object.op_Implicit((Object)(object)view) && Object.op_Implicit((Object)(object)view.GetComponent<JusticeAdaptiveLighting>()))
		{
			Bind(view, playerObject.GetComponent<PlayerControllerB>());
		}
	}

	private static void Ragdoll(BodyReplacementBase __instance, GameObject __result)
	{
		if (__instance is JusticeBody justiceBody && Object.op_Implicit((Object)(object)((BodyReplacementBase)justiceBody).controller))
		{
			Bind(__result, ((BodyReplacementBase)justiceBody).controller, corpse: true);
		}
	}

	private static void Bind(GameObject model, PlayerControllerB player, bool corpse = false)
	{
		if (!Object.op_Implicit((Object)(object)model) || !Object.op_Implicit((Object)(object)player))
		{
			return;
		}
		JusticeAdaptiveLighting justiceAdaptiveLighting = model.GetComponent<JusticeAdaptiveLighting>() ?? model.AddComponent<JusticeAdaptiveLighting>();
		justiceAdaptiveLighting.Rebind();
		ulong owner = ((NetworkBehaviour)player).OwnerClientId;
		if (!corpse)
		{
			justiceAdaptiveLighting.BindContext(() => (!Object.op_Implicit((Object)(object)player) || ((NetworkBehaviour)player).OwnerClientId != owner) ? default(JusticeLightingContext) : Native(player));
			return;
		}
		Death value;
		JusticeLightingContext death = ((deaths.TryGetValue(player, out value) && value.Owner == owner) ? value.Context : Native(player));
		JusticeCorpseLightingContext corpseContext = new JusticeCorpseLightingContext(death);
		DeadBodyInfo nativeBody = player.deadBody;
		justiceAdaptiveLighting.BindContext(delegate
		{
			if (!Object.op_Implicit((Object)(object)nativeBody))
			{
				return corpseContext.Observe(bodyInShip: false, hasHolder: false, default(JusticeLightingContext), hasItem: false, default(JusticeLightingContext));
			}
			GrabbableObject grabBodyObject = nativeBody.grabBodyObject;
			PlayerControllerB val = ((Object.op_Implicit((Object)(object)grabBodyObject) && grabBodyObject.isHeld) ? grabBodyObject.playerHeldBy : null);
			return corpseContext.Observe(nativeBody.isInShip || nativeBody.parentedToShip, Object.op_Implicit((Object)(object)val), Native(val), Object.op_Implicit((Object)(object)grabBodyObject), Object.op_Implicit((Object)(object)grabBodyObject) ? new JusticeLightingContext(grabBodyObject.isInFactory, grabBodyObject.isInShipRoom) : default(JusticeLightingContext));
		});
	}

	internal static void Clear()
	{
		deaths.Clear();
	}
}
public enum AttentionKind
{
	Player,
	Enemy,
	Item
}
public struct AttentionCandidate
{
	public int Key;

	public AttentionKind Kind;

	public float Distance;

	public bool Speaking;

	public bool Eligible;

	public AttentionCandidate(int key, AttentionKind kind, float distance, bool speaking = true, bool eligible = true)
	{
		Key = key;
		Kind = kind;
		Distance = distance;
		Speaking = speaking;
		Eligible = eligible;
	}
}
public sealed class JusticeAttentionSelection
{
	private float lastSpeech;

	private float selectedAt;

	public int CurrentKey { get; private set; }

	public bool HasTarget { get; private set; }

	public AttentionKind CurrentKind { get; private set; }

	public void Reset()
	{
		HasTarget = false;
		CurrentKey = 0;
		lastSpeech = (selectedAt = 0f);
	}

	public int Choose(IList<AttentionCandidate> candidates, float now, float pauseHold = 1.2f)
	{
		AttentionCandidate attentionCandidate = default(AttentionCandidate);
		AttentionCandidate c = default(AttentionCandidate);
		AttentionCandidate c2 = default(AttentionCandidate);
		bool flag = false;
		bool flag2 = false;
		bool flag3 = false;
		foreach (AttentionCandidate candidate in candidates)
		{
			if (!candidate.Eligible || float.IsNaN(candidate.Distance) || float.IsInfinity(candidate.Distance) || candidate.Distance < 0f)
			{
				continue;
			}
			if (HasTarget && candidate.Key == CurrentKey && candidate.Kind == CurrentKind)
			{
				attentionCandidate = candidate;
				flag = true;
			}
			if (candidate.Kind == AttentionKind.Player)
			{
				if (candidate.Speaking && (!flag2 || candidate.Distance < c.Distance))
				{
					c = candidate;
					flag2 = true;
				}
			}
			else if (!flag3 || candidate.Kind < c2.Kind || (candidate.Kind == c2.Kind && candidate.Distance < c2.Distance))
			{
				c2 = candidate;
				flag3 = true;
			}
		}
		if (flag && attentionCandidate.Kind == AttentionKind.Player && attentionCandidate.Speaking)
		{
			lastSpeech = now;
		}
		if (flag2)
		{
			if (flag && attentionCandidate.Kind == AttentionKind.Player && attentionCandidate.Speaking && (now - selectedAt < 0.65f || c.Distance >= attentionCandidate.Distance * 0.7f))
			{
				return CurrentKey;
			}
			return Select(c, now);
		}
		if (flag && attentionCandidate.Kind == AttentionKind.Player && now - lastSpeech <= Mathf.Clamp(pauseHold, 0f, 5f))
		{
			return CurrentKey;
		}
		if (flag3)
		{
			if (flag && attentionCandidate.Kind == c2.Kind && attentionCandidate.Kind != AttentionKind.Player && (now - selectedAt < 1.5f || c2.Distance >= attentionCandidate.Distance * 0.7f))
			{
				return CurrentKey;
			}
			return Select(c2, now);
		}
		Reset();
		return 0;
	}

	private int Select(AttentionCandidate c, float now)
	{
		if (!HasTarget || c.Key != CurrentKey || c.Kind != CurrentKind)
		{
			selectedAt = now;
		}
		HasTarget = true;
		CurrentKey = c.Key;
		CurrentKind = c.Kind;
		if (c.Kind == AttentionKind.Player && c.Speaking)
		{
			lastSpeech = now;
		}
		return CurrentKey;
	}

	public static bool InView(Vector3 origin, Vector3 forward, Vector3 point, float radius)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = point - origin;
		float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
		if (sqrMagnitude < 0.0225f || sqrMagnitude > radius * radius)
		{
			return false;
		}
		Vector3 val2 = Vector3.ProjectOnPlane(val, Vector3.up);
		Vector3 val3 = Vector3.ProjectOnPlane(forward, Vector3.up);
		if (Vector3.Angle(val2, val3) <= 65f)
		{
			return Mathf.Abs(Mathf.Atan2(val.y, ((Vector3)(ref val2)).magnitude) * 57.29578f) <= 60f;
		}
		return false;
	}

	public static bool ActiveSpeech(bool speaking, float amplitude)
	{
		if (speaking && !float.IsNaN(amplitude) && !float.IsInfinity(amplitude))
		{
			return amplitude >= 0.002f;
		}
		return false;
	}

	public static bool Visible(Vector3 origin, Vector3 point, int mask, Transform observer, Transform model, Transform target, RaycastHit[] hits)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = point - origin;
		float magnitude = ((Vector3)(ref val)).magnitude;
		if (magnitude < 0.05f)
		{
			return true;
		}
		int num = Physics.RaycastNonAlloc(origin, val / magnitude, hits, magnitude, mask, (QueryTriggerInteraction)1);
		if (num == hits.Length)
		{
			return false;
		}
		for (int i = 0; i < num; i++)
		{
			Transform transform = ((RaycastHit)(ref hits[i])).transform;
			if (Object.op_Implicit((Object)(object)transform) && (!Object.op_Implicit((Object)(object)observer) || !transform.IsChildOf(observer)) && (!Object.op_Implicit((Object)(object)model) || !transform.IsChildOf(model)) && (!Object.op_Implicit((Object)(object)target) || !transform.IsChildOf(target)))
			{
				return false;
			}
		}
		return true;
	}
}
public sealed class JusticeAttention
{
	private sealed class ItemRenderer
	{
		public GrabbableObject Item;

		public Renderer Renderer;
	}

	private readonly JusticeAttentionSelection selection = new JusticeAttentionSelection();

	private readonly List<AttentionCandidate> candidates = new List<AttentionCandidate>(64);

	private readonly Dictionary<int, Object> objects = new Dictionary<int, Object>();

	private readonly RaycastHit[] hits = (RaycastHit[])(object)new RaycastHit[24];

	private static EnemyAI[] enemies = (EnemyAI[])(object)new EnemyAI[0];

	private static GrabbableObject[] items = (GrabbableObject[])(object)new GrabbableObject[0];

	private static float nextSceneScan;

	private static StartOfRound scene;

	private static readonly Dictionary<int, ItemRenderer> itemRenderers = new Dictionary<int, ItemRenderer>();

	private static readonly HashSet<int> aliveItems = new HashSet<int>();

	private static readonly List<int> staleItems = new List<int>();

	private Object target;

	private float nextScan;

	public void Reset()
	{
		selection.Reset();
		target = null;
		nextScan = 0f;
	}

	private static void ScanScene(float now)
	{
		if ((Object)(object)scene != (Object)(object)StartOfRound.Instance)
		{
			scene = StartOfRound.Instance;
			nextSceneScan = 0f;
			itemRenderers.Clear();
		}
		if (now < nextSceneScan)
		{
			return;
		}
		nextSceneScan = now + 1f;
		enemies = JusticeSceneCache.Enemies(now);
		items = Object.FindObjectsByType<GrabbableObject>((FindObjectsSortMode)0);
		aliveItems.Clear();
		GrabbableObject[] array = items;
		foreach (GrabbableObject val in array)
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				aliveItems.Add(((Object)val).GetInstanceID());
			}
		}
		staleItems.Clear();
		foreach (KeyValuePair<int, ItemRenderer> itemRenderer in itemRenderers)
		{
			if (!aliveItems.Contains(itemRenderer.Key))
			{
				staleItems.Add(itemRenderer.Key);
			}
		}
		foreach (int staleItem in staleItems)
		{
			itemRenderers.Remove(staleItem);
		}
	}

	internal static void ClearSceneCache()
	{
		scene = null;
		nextSceneScan = 0f;
		enemies = (EnemyAI[])(object)new EnemyAI[0];
		items = (GrabbableObject[])(object)new GrabbableObject[0];
		itemRenderers.Clear();
		aliveItems.Clear();
		staleItems.Clear();
	}

	private static Vector3 Point(Object value)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		PlayerControllerB val = (PlayerControllerB)(object)((value is PlayerControllerB) ? value : null);
		if (val != null)
		{
			if (!Object.op_Implicit((Object)(object)val.playerEye))
			{
				return ((Component)val).transform.position + Vector3.up * 1.6f;
			}
			return val.playerEye.position;
		}
		EnemyAI val2 = (EnemyAI)(object)((value is EnemyAI) ? value : null);
		if (val2 != null)
		{
			if (!Object.op_Implicit((Object)(object)val2.eye))
			{
				return ((Component)val2).transform.position + Vector3.up;
			}
			return val2.eye.position;
		}
		GrabbableObject val3 = (GrabbableObject)(object)((value is GrabbableObject) ? value : null);
		if (val3 != null)
		{
			int instanceID = ((Object)val3).GetInstanceID();
			if (!itemRenderers.TryGetValue(instanceID, out var value2) || (Object)(object)value2.Item != (Object)(object)val3)
			{
				value2 = new ItemRenderer
				{
					Item = val3,
					Renderer = ((Component)val3).GetComponentInChildren<Renderer>()
				};
				itemRenderers[instanceID] = value2;
			}
			if (!Object.op_Implicit((Object)(object)value2.Renderer))
			{
				return ((Component)val3).transform.position;
			}
			Bounds bounds = value2.Renderer.bounds;
			return ((Bounds)(ref bounds)).center;
		}
		return Vector3.zero;
	}

	private void Add(Component value, AttentionKind kind, Vector3 origin, Vector3 forward, float range, bool speaking, PlayerControllerB owner, Transform model)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = Point((Object)(object)value);
		if (JusticeAttentionSelection.InView(origin, forward, val, range))
		{
			int mask = (Object.op_Implicit((Object)(object)StartOfRound.Instance) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-5));
			if (JusticeAttentionSelection.Visible(origin, val, mask, ((Component)owner).transform, model, value.transform, hits))
			{
				int instanceID = ((Object)value).GetInstanceID();
				objects[instanceID] = (Object)(object)value;
				candidates.Add(new AttentionCandidate(instanceID, kind, Vector3.Distance(origin, val), speaking));
			}
		}
	}

	public bool Resolve(PlayerControllerB owner, Transform model, Vector3 origin, Vector3 forward, float now, out Vector3 direction)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bc: 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_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_00fa: 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_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		direction = forward;
		if (!Object.op_Implicit((Object)(object)owner) || owner.isPlayerDead || !owner.isPlayerControlled || !Object.op_Implicit((Object)(object)StartOfRound.Instance))
		{
			Reset();
			return false;
		}
		if (now >= nextScan)
		{
			nextScan = now + 0.1f;
			candidates.Clear();
			objects.Clear();
			ScanScene(now);
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val == (Object)(object)owner) && val.isPlayerControlled && !val.isPlayerDead && ((Component)val).gameObject.activeInHierarchy)
				{
					bool flag = JusticeVoiceActivity.IsSpeaking(val);
					if (flag || (selection.HasTarget && selection.CurrentKind == AttentionKind.Player && selection.CurrentKey == ((Object)val).GetInstanceID()))
					{
						Add((Component)(object)val, AttentionKind.Player, origin, forward, Plugin.TalkingPlayersRange.Value, flag, owner, model);
					}
				}
			}
			EnemyAI[] array = enemies;
			foreach (EnemyAI val2 in array)
			{
				if (Object.op_Implicit((Object)(object)val2) && !val2.isEnemyDead && ((Behaviour)val2).isActiveAndEnabled)
				{
					Add((Component)(object)val2, AttentionKind.Enemy, origin, forward, Plugin.EnemiesRange.Value, speaking: false, owner, model);
				}
			}
			GrabbableObject[] array2 = items;
			foreach (GrabbableObject val3 in array2)
			{
				if (Object.op_Implicit((Object)(object)val3) && !val3.isHeld && !val3.isPocketed && !val3.isHeldByEnemy && ((Behaviour)val3).isActiveAndEnabled)
				{
					Add((Component)(object)val3, AttentionKind.Item, origin, forward, Plugin.ItemsRange.Value, speaking: false, owner, model);
				}
			}
			int key = selection.Choose(candidates, now, Plugin.SpeechPauseHold.Value);
			target = ((selection.HasTarget && objects.TryGetValue(key, out var value)) ? value : null);
		}
		if (!Object.op_Implicit(target))
		{
			return false;
		}
		Object obj = target;
		PlayerControllerB val4 = (PlayerControllerB)(object)((obj is PlayerControllerB) ? obj : null);
		if (val4 == null || (val4.isPlayerControlled && !val4.isPlayerDead))
		{
			Object obj2 = target;
			EnemyAI val5 = (EnemyAI)(object)((obj2 is EnemyAI) ? obj2 : null);
			if (val5 == null || !val5.isEnemyDead)
			{
				Object obj3 = target;
				GrabbableObject val6 = (GrabbableObject)(object)((obj3 is GrabbableObject) ? obj3 : null);
				if (val6 == null || (!val6.isHeld && !val6.isPocketed && !val6.isHeldByEnemy))
				{
					direction = Point(target) - origin;
					return ((Vector3)(ref direction)).sqrMagnitude > 1E-06f;
				}
			}
		}
		target = null;
		selection.Reset();
		nextScan = 0f;
		return false;
	}
}
internal static class JusticeVoiceActivity
{
	private static object comms;

	private static readonly Dictionary<int, float> retry = new Dictionary<int, float>();

	private static readonly Dictionary<int, object> states = new Dictionary<int, object>();

	internal static bool IsSpeaking(PlayerControllerB player)
	{
		object obj = JusticeFace.Read(player, "voicePlayerState") ?? JusticeFace.Read(JusticeFace.Read(player, "currentVoiceChatIngameSettings"), "_playerState");
		int instanceID = ((Object)player).GetInstanceID();
		if (obj == null && states.TryGetValue(instanceID, out var value))
		{
			obj = value;
		}
		if (obj == null && (!retry.TryGetValue(instanceID, out var value2) || Time.unscaledTime >= value2))
		{
			retry[instanceID] = Time.unscaledTime + 1f;
			comms = JusticeFace.Read(StartOfRound.Instance, "voiceChatModule");
			if (comms != null)
			{
				string text = (((NetworkBehaviour)player).IsOwner ? (JusticeFace.Read(comms, "LocalPlayerName") as string) : (JusticeFace.Read(player, "voicePlayerName") as string));
				if (!string.IsNullOrEmpty(text))
				{
					try
					{
						obj = JusticeRuntimeMembers.CallString(comms, "FindPlayer", text);
						if (obj != null)
						{
							states[instanceID] = obj;
						}
					}
					catch
					{
					}
				}
			}
		}
		bool value3;
		bool flag = JusticeRuntimeMembers.TryRead<bool>(obj, "IsSpeaking", out value3) && value3;
		if (JusticeRuntimeMembers.TryRead<bool>(obj, "IsConnected", out var value4) && !value4)
		{
			return false;
		}
		if (!JusticeRuntimeMembers.TryRead<float>(obj, "Amplitude", out var value5))
		{
			return flag;
		}
		return JusticeAttentionSelection.ActiveSpeech(flag, value5);
	}

	internal static void Clear()
	{
		comms = null;
		retry.Clear();
		states.Clear();
	}
}
public sealed class JusticeChestGazeTarget : MonoBehaviour
{
	public Transform chest;

	public Transform[] breasts = (Transform[])(object)new Transform[0];

	public Vector3 Point
	{
		get
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Vector3 val = Vector3.zero;
			int num = 0;
			Transform[] array = breasts;
			foreach (Transform val2 in array)
			{
				if (Object.op_Implicit((Object)(object)val2))
				{
					val += val2.position;
					num++;
				}
			}
			if (num <= 0)
			{
				if (!Object.op_Implicit((Object)(object)chest))
				{
					return ((Component)this).transform.position + Vector3.up * 1.3f;
				}
				return chest.position;
			}
			return val / (float)num;
		}
	}
}
public enum JusticeExpression : byte
{
	Neutral,
	Frightened,
	Hurt,
	Happy,
	Surprised,
	VeryHappy,
	Dead,
	Stars,
	Hearts,
	Curious,
	Relaxed,
	Startled,
	Musical,
	Protective,
	Playful,
	FoodDelight,
	Determined,
	ShipCelebrate
}
public struct JusticeExpressionContext
{
	public bool Dead;

	public bool Critical;

	public bool EnemyNear;

	public bool Fear;

	public bool Chased;

	public bool Dancing;

	public bool StarEyes;

	public bool HeartEyes;

	public bool Unsafe
	{
		get
		{
			if (!EnemyNear && !Fear)
			{
				return Chased;
			}
			return true;
		}
	}
}
public sealed class JusticeExpressionSelection
{
	private double hurtUntil = -1.0;

	private double treasureUntil = -1.0;

	private bool surprised = true;

	private int pickups;

	public void Damage(double now)
	{
		hurtUntil = now + 2.0;
	}

	public void PickedUp(int value, double now)
	{
		if (value > 100)
		{
			treasureUntil = now + 3.5;
			surprised = pickups++ % 2 == 0;
		}
	}

	public void Reset()
	{
		hurtUntil = (treasureUntil = -1.0);
		pickups = 0;
		surprised = true;
	}

	public JusticeExpression Choose(JusticeExpressionContext c, double now)
	{
		if (c.Dead)
		{
			return JusticeExpression.Dead;
		}
		if (c.Critical || now < hurtUntil)
		{
			return JusticeExpression.Hurt;
		}
		if (c.Unsafe)
		{
			return JusticeExpression.Frightened;
		}
		if (c.StarEyes)
		{
			return JusticeExpression.Stars;
		}
		if (c.HeartEyes)
		{
			return JusticeExpression.Hearts;
		}
		if (now < treasureUntil)
		{
			if (!surprised)
			{
				return JusticeExpression.VeryHappy;
			}
			return JusticeExpression.Surprised;
		}
		if (c.Dancing)
		{
			return JusticeExpression.Happy;
		}
		return JusticeExpression.Neutral;
	}
}
public struct JusticeExpressionWeight
{
	public string Shape;

	public float Weight;

	public bool Eyes;

	public bool Mouth;

	public JusticeExpressionWeight(string shape, float weight, bool eyes = false, bool mouth = false)
	{
		Shape = "expr_" + shape;
		Weight = weight;
		Eyes = eyes;
		Mouth = mouth;
	}
}
public static class JusticeExpressionProfiles
{
	private static readonly JusticeExpressionWeight[][] profiles = new JusticeExpressionWeight[9][]
	{
		new JusticeExpressionWeight[0],
		new JusticeExpressionWeight[4]
		{
			B("worry", 0.75f),
			B("brow_up", 0.25f),
			E("surprise", 0.85f),
			M("triangle", 0.6f)
		},
		new JusticeExpressionWeight[4]
		{
			B("worry", 0.85f),
			B("serious", 0.25f),
			E("focus", 0.45f),
			M("clench", 0.8f)
		},
		new JusticeExpressionWeight[3]
		{
			B("happy_brows", 0.45f),
			E("smile_eyes", 0.65f),
			M("smile", 0.85f)
		},
		new JusticeExpressionWeight[3]
		{
			B("brow_up", 0.65f),
			E("surprise", 0.9f),
			M("o", 0.65f)
		},
		new JusticeExpressionWeight[3]
		{
			B("happy_brows", 0.65f),
			E("smile_eyes", 0.85f),
			M("laugh", 0.85f)
		},
		new JusticeExpressionWeight[2]
		{
			B("worry", 0.7f),
			M("clench", 0.55f)
		},
		new JusticeExpressionWeight[3]
		{
			B("brow_up", 0.35f),
			E("stars", 1f),
			M("smile", 0.65f)
		},
		new JusticeExpressionWeight[3]
		{
			B("happy_brows", 0.35f),
			E("hearts", 1f),
			M("smile", 0.75f)
		}
	};

	private static JusticeExpressionWeight B(string n, float w)
	{
		return new JusticeExpressionWeight(n, w);
	}

	private static JusticeExpressionWeight E(string n, float w)
	{
		return new JusticeExpressionWeight(n, w, eyes: true);
	}

	private static JusticeExpressionWeight M(string n, float w)
	{
		return new JusticeExpressionWeight(n, w, eyes: false, mouth: true);
	}

	public static JusticeExpressionWeight[] Weights(JusticeExpression state)
	{
		if ((int)state >= profiles.Length)
		{
			return JusticePersonalityProfiles.Weights("", state);
		}
		return profiles[(uint)state];
	}
}
public sealed class JusticeExpressionMixer
{
	private sealed class Binding
	{
		public SkinnedMeshRenderer Renderer;

		public int[] Indices;

		public int Blink;

		public int Open;

		public int Round;
	}

	private readonly List<string> shapes = new List<string>();

	private readonly Dictionary<string, int> slots = new Dictionary<string, int>();

	private readonly List<Binding> bindings = new List<Binding>();

	private float[] values;

	private float[] target;

	private bool[] eyes;

	private bool[] mouth;

	private readonly string character;

	public JusticeExpressionMixer(GameObject model, string member = null)
	{
		character = member ?? JusticePersonalityProfiles.Character(((Object)model).name);
		foreach (JusticeExpression value in Enum.GetValues(typeof(JusticeExpression)))
		{
			JusticeExpressionWeight[] array = JusticeExpressionProfiles.Weights(value);
			for (int i = 0; i < array.Length; i++)
			{
				JusticeExpressionWeight justiceExpressionWeight = array[i];
				if (!slots.ContainsKey(justiceExpressionWeight.Shape))
				{
					slots[justiceExpressionWeight.Shape] = shapes.Count;
					shapes.Add(justiceExpressionWeight.Shape);
				}
			}
		}
		values = new float[shapes.Count];
		target = new float[shapes.Count];
		eyes = new bool[shapes.Count];
		mouth = new bool[shapes.Count];
		foreach (JusticeExpression value2 in Enum.GetValues(typeof(JusticeExpression)))
		{
			JusticeExpressionWeight[] array = JusticeExpressionProfiles.Weights(value2);
			for (int i = 0; i < array.Length; i++)
			{
				JusticeExpressionWeight justiceExpressionWeight2 = array[i];
				int num = slots[justiceExpressionWeight2.Shape];
				eyes[num] |= justiceExpressionWeight2.Eyes;
				mouth[num] |= justiceExpressionWeight2.Mouth;
			}
		}
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			if (Object.op_Implicit((Object)(object)val.sharedMesh) && !JusticeInkOutline.IsInk(val))
			{
				Binding binding = new Binding
				{
					Renderer = val,
					Indices = new int[shapes.Count],
					Blink = val.sharedMesh.GetBlendShapeIndex("blink"),
					Open = val.sharedMesh.GetBlendShapeIndex("speech_open"),
					Round = val.sharedMesh.GetBlendShapeIndex("speech_round")
				};
				for (int j = 0; j < shapes.Count; j++)
				{
					binding.Indices[j] = val.sharedMesh.GetBlendShapeIndex(shapes[j]);
				}
				bindings.Add(binding);
			}
		}
	}

	public void Step(JusticeExpression state, float delta, bool immediate = false)
	{
		Array.Clear(target, 0, target.Length);
		JusticeExpressionWeight[] array = JusticePersonalityProfiles.Weights(character, state);
		for (int i = 0; i < array.Length; i++)
		{
			JusticeExpressionWeight justiceExpressionWeight = array[i];
			target[slots[justiceExpressionWeight.Shape]] = justiceExpressionWeight.Weight;
		}
		float num = ((immediate || state == JusticeExpression.Dead) ? 1f : (1f - Mathf.Exp((0f - Mathf.Clamp(delta, 0f, 0.1f)) * 13f)));
		for (int j = 0; j < values.Length; j++)
		{
			values[j] = Mathf.Lerp(values[j], target[j], num);
		}
		foreach (Binding binding in bindings)
		{
			if (!Object.op_Implicit((Object)(object)binding.Renderer))
			{
				continue;
			}
			float num2 = ((binding.Blink < 0) ? 0f : Mathf.Clamp01(binding.Renderer.GetBlendShapeWeight(binding.Blink) / 100f));
			float num3 = ((binding.Open < 0) ? 0f : Mathf.Clamp01(binding.Renderer.GetBlendShapeWeight(binding.Open) / 85f));
			if (state == JusticeExpression.Dead)
			{
				num2 = 1f;
				num3 = 0f;
				if (binding.Blink >= 0)
				{
					binding.Renderer.SetBlendShapeWeight(binding.Blink, 100f);
				}
				if (binding.Open >= 0)
				{
					binding.Renderer.SetBlendShapeWeight(binding.Open, 0f);
				}
				if (binding.Round >= 0)
				{
					binding.Renderer.SetBlendShapeWeight(binding.Round, 0f);
				}
			}
			for (int k = 0; k < values.Length; k++)
			{
				if (binding.Indices[k] >= 0)
				{
					float num4 = values[k];
					if (eyes[k])
					{
						num4 *= 1f - num2;
					}
					if (mouth[k])
					{
						num4 *= 1f - num3 * 0.55f;
					}
					binding.Renderer.SetBlendShapeWeight(binding.Indices[k], num4 * 100f);
				}
			}
		}
	}
}
[DefaultExecutionOrder(280)]
public sealed class JusticeDeathFace : MonoBehaviour
{
	private JusticeExpressionMixer mixer;

	public void Initialize()
	{
		mixer = new JusticeExpressionMixer(((Component)this).gameObject);
		mixer.Step(JusticeExpression.Dead, 0f, immediate: true);
	}

	private void LateUpdate()
	{
		if (mixer == null)
		{
			Initialize();
		}
		mixer.Step(JusticeExpression.Dead, 0f, immediate: true);
	}
}
public sealed class JusticeGigiRules
{
	private readonly HashSet<int> discovered = new HashSet<int>();

	private bool seeded;

	private bool inside;

	private bool shipUsed;

	private double entry = -100.0;

	private double starsUntil = -100.0;

	private double nearStarted = -100.0;

	private int nearKey = int.MinValue;

	private float gaze;

	public bool ShipReactionUsed => shipUsed;

	public float GazeWeight => gaze;

	public void SeedShip(bool value)
	{
		if (!seeded)
		{
			seeded = true;
			inside = value;
		}
	}

	public void NewRound(bool isInside)
	{
		discovered.Clear();
		shipUsed = false;
		starsUntil = (entry = -100.0);
		inside = isInside;
		seeded = true;
		nearKey = int.MinValue;
		nearStarted = -100.0;
		gaze = 0f;
	}

	public bool NoticeLoot(int key, int value, int threshold, double now, float seconds)
	{
		if (value <= threshold || !discovered.Add(key))
		{
			return false;
		}
		starsUntil = Math.Max(starsUntil, now + (double)seconds);
		return true;
	}

	public void Ship(bool isInside, bool seesPile, double now, float seconds)
	{
		if (!seeded)
		{
			SeedShip(isInside);
			return;
		}
		if (isInside && !inside)
		{
			entry = now;
		}
		inside = isInside;
		if (isInside && !shipUsed && seesPile && now >= entry && now < entry + (double)seconds)
		{
			shipUsed = true;
			starsUntil = Math.Max(starsUntil, entry + (double)seconds);
		}
	}

	public bool Stars(double now)
	{
		return now < starsUntil;
	}

	public void Near(int targetKey, bool eligible, double now, float delta, float dwell, float ramp)
	{
		if (!eligible)
		{
			nearKey = int.MinValue;
			nearStarted = -100.0;
			gaze = 0f;
			return;
		}
		if (nearKey != targetKey)
		{
			nearKey = targetKey;
			nearStarted = now;
			gaze = 0f;
		}
		float num = ((now - nearStarted >= (double)dwell) ? 1 : 0);
		gaze = Mathf.Lerp(gaze, num, 1f - Mathf.Exp((0f - Mathf.Clamp(delta, 0f, 0.1f)) / Mathf.Max(0.1f, ramp)));
	}

	public void ResetTransient()
	{
		starsUntil = (entry = -100.0);
		nearKey = int.MinValue;
		nearStarted = -100.0;
		gaze = 0f;
	}

	public static bool Ladder(bool wearerClimbing, bool otherClimbing, bool sameLadder, float horizontalDistance, float aboveDistance, float maximumDistance)
	{
		if (wearerClimbing && otherClimbing && sameLadder && horizontalDistance <= 0.75f && aboveDistance > 0.25f)
		{
			return aboveDistance <= maximumDistance;
		}
		return false;
	}

	public static bool Pile(int count, int value, int minimumCount, int minimumValue)
	{
		if (count >= minimumCount)
		{
			return value >= minimumValue;
		}
		return false;
	}

	public static string NormalizeSuit(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder();
		foreach (char c in value)
		{
			if (char.IsLetterOrDigit(c))
			{
				stringBuilder.Append(char.ToLowerInvariant(c));
			}
		}
		return stringBuilder.ToString();
	}

	public static bool SuitMatches(string suit, string[] tokens)
	{
		string text = NormalizeSuit(suit);
		for (int i = 0; i < tokens.Length; i++)
		{
			string text2 = NormalizeSuit(tokens[i].Trim());
			if (text2.Length > 0 && text.Contains(text2))
			{
				return true;
			}
		}
		return false;
	}
}
public struct JusticeExpressionRecord
{
	public ulong PlayerId;

	public ulong Owner;

	public byte Character;

	public JusticeExpression Expression;

	public uint Revision;

	public ulong GazePlayerId;

	public float GazeWeight;
}
public sealed class JusticeExpressionStore
{
	private sealed class Entry
	{
		public JusticeExpressionRecord Record;

		public double At;
	}

	private readonly Dictionary<ulong, Entry> records = new Dictionary<ulong, Entry>();

	public bool Accept(ulong sender, ulong actualOwner, JusticeExpressionRecord value, double now)
	{
		if (sender != actualOwner || value.Owner != actualOwner || value.Character >= 4 || (int)value.Expression > 17 || ((value.Expression == JusticeExpression.Stars || value.Expression == JusticeExpression.Hearts) && value.Character != 1) || (value.Character == 1 && (int)value.Expression > 8) || !JusticeReactionStore.Valid(value.GazeWeight) || (value.GazeWeight > 0f && (value.Expression != JusticeExpression.Hearts || value.GazePlayerId == value.PlayerId)) || double.IsNaN(now) || double.IsInfinity(now))
		{
			return false;
		}
		if (records.TryGetValue(value.PlayerId, out var value2) && value2.Record.Owner == actualOwner && (value.Revision < value2.Record.Revision || (value.Revision == value2.Record.Revision && (value.Character != value2.Record.Character || value.Expression != value2.Record.Expression || value.GazePlayerId != value2.Record.GazePlayerId || value.GazeWeight != value2.Record.GazeWeight))))
		{
			return false;
		}
		records[value.PlayerId] = new Entry
		{
			Record = value,
			At = now
		};
		return true;
	}

	public bool TryGet(ulong id, double now, out JusticeExpressionRecord value)
	{
		value = default(JusticeExpressionRecord);
		if (!records.TryGetValue(id, out var value2) || now - value2.At > 5.0 || now < value2.At)
		{
			return false;
		}
		value = value2.Record;
		return true;
	}

	public uint NextRevision(ulong id, ulong owner)
	{
		if (!records.TryGetValue(id, out var value) || value.Record.Owner != owner)
		{
			return 1u;
		}
		return value.Record.Revision + 1;
	}

	public JusticeExpressionRecord[] Snapshot(double now)
	{
		List<JusticeExpressionRecord> list = new List<JusticeExpressionRecord>();
		foreach (Entry value in records.Values)
		{
			if (now >= value.At && now - value.At <= 5.0)
			{
				list.Add(value.Record);
			}
		}
		list.Sort((JusticeExpressionRecord a, JusticeExpressionRecord b) => a.PlayerId.CompareTo(b.PlayerId));
		return list.ToArray();
	}

	public void RemoveOwner(ulong owner)
	{
		List<ulong> list = new List<ulong>();
		foreach (KeyValuePair<ulong, Entry> record in records)
		{
			if (record.Value.Record.Owner == owner)
			{
				list.Add(record.Key);
			}
		}
		foreach (ulong item in list)
		{
			records.Remove(item);
		}
	}

	public void Clear()
	{
		records.Clear();
	}
}
public static class JusticeFirstPersonMesh
{
	private sealed class Entry
	{
		public Mesh Mesh;

		public int[] BoneIndices;

		public int[] MaterialSlots;
	}

	private static readonly Dictionary<Mesh, Entry> Cache = new Dictionary<Mesh, Entry>();

	public static int CachedMeshes => Cache.Count;

	private static HashSet<Transform> ArmBones(GameObject model)
	{
		//IL_0042: 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)
		Animator componentInChildren = model.GetComponentInChildren<Animator>(true);
		if (!Object.op_Implicit((Object)(object)componentInChildren) || !componentInChildren.isHuman)
		{
			throw new InvalidOperationException("Justice first-person avatar must be humanoid.");
		}
		HashSet<Transform> hashSet = new HashSet<Transform>();
		HumanBodyBones[] array = new HumanBodyBones[6];
		RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
		HumanBodyBones[] array2 = (HumanBodyBones[])(object)array;
		foreach (HumanBodyBones val in array2)
		{
			Transform boneTransform = componentInChildren.GetBoneTransform(val);
			if (Object.op_Implicit((Object)(object)boneTransform))
			{
				Transform[] componentsInChildren = ((Component)boneTransform).GetComponentsInChildren<Transform>(true);
				foreach (Transform item in componentsInChildren)
				{
					hashSet.Add(item);
				}
			}
		}
		return hashSet;
	}

	public static void Prime(GameObject model)
	{
		HashSet<Transform> arms = ArmBones(model);
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Get(componentsInChildren[i], arms);
		}
	}

	public static IEnumerator PrimeIncremental(GameObject model)
	{
		HashSet<Transform> arms = ArmBones(model);
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Get(componentsInChildren[i], arms);
			yield return null;
		}
	}

	private static bool Allowed(BoneWeight weight, bool[] bones)
	{
		if ((((BoneWeight)(ref weight)).weight0 <= 0f || bones[((BoneWeight)(ref weight)).boneIndex0]) && (((BoneWeight)(ref weight)).weight1 <= 0f || bones[((BoneWeight)(ref weight)).boneIndex1]) && (((BoneWeight)(ref weight)).weight2 <= 0f || bones[((BoneWeight)(ref weight)).boneIndex2]))
		{
			if (!(((BoneWeight)(ref weight)).weight3 <= 0f))
			{
				return bones[((BoneWeight)(ref weight)).boneIndex3];
			}
			return true;
		}
		return false;
	}

	private static Entry Get(SkinnedMeshRenderer renderer, HashSet<Transform> arms)
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: 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_0314: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0344: Expected O, but got Unknown
		Mesh sharedMesh = renderer.sharedMesh;
		if (!Object.op_Implicit((Object)(object)sharedMesh))
		{
			return null;
		}
		if (Cache.TryGetValue(sharedMesh, out var value))
		{
			return value;
		}
		if (!sharedMesh.isReadable)
		{
			throw new InvalidOperationException("Justice first-person source mesh is not readable: " + ((Object)sharedMesh).name);
		}
		Transform[] bones = renderer.bones;
		bool[] array = new bool[bones.Length];
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = Object.op_Implicit((Object)(object)bones[i]) && arms.Contains(bones[i]);
		}
		BoneWeight[] boneWeights = sharedMesh.boneWeights;
		if (boneWeights.Length != sharedMesh.vertexCount)
		{
			throw new InvalidOperationException("Justice arms require four-weight source skinning.");
		}
		bool[] array2 = new bool[sharedMesh.vertexCount];
		for (int j = 0; j < boneWeights.Length; j++)
		{
			array2[j] = Allowed(boneWeights[j], array);
		}
		List<int> list = new List<int>();
		Dictionary<int, int> dictionary = new Dictionary<int, int>();
		List<int[]> list2 = new List<int[]>();
		List<int> list3 = new List<int>();
		for (int k = 0; k < sharedMesh.subMeshCount; k++)
		{
			int[] triangles = sharedMesh.GetTriangles(k);
			List<int> list4 = new List<int>();
			for (int l = 0; l < triangles.Length; l += 3)
			{
				if (!array2[triangles[l]] || !array2[triangles[l + 1]] || !array2[triangles[l + 2]])
				{
					continue;
				}
				for (int m = 0; m < 3; m++)
				{
					int num = triangles[l + m];
					if (!dictionary.TryGetValue(num, out var value2))
					{
						value2 = list.Count;
						dictionary.Add(num, value2);
						list.Add(num);
					}
					list4.Add(value2);
				}
			}
			if (list4.Count > 0)
			{
				list3.Add(k);
				list2.Add(list4.ToArray());
			}
		}
		if (list.Count == 0)
		{
			Cache.Add(sharedMesh, null);
			return null;
		}
		List<int> list5 = new List<int>();
		Dictionary<int, int> dictionary2 = new Dictionary<int, int>();
		BoneWeight[] array3 = (BoneWeight[])(object)new BoneWeight[list.Count];
		for (int n = 0; n < array3.Length; n++)
		{
			BoneWeight val = boneWeights[list[n]];
			int[] array4 = new int[4]
			{
				((BoneWeight)(ref val)).boneIndex0,
				((BoneWeight)(ref val)).boneIndex1,
				((BoneWeight)(ref val)).boneIndex2,
				((BoneWeight)(ref val)).boneIndex3
			};
			float[] array5 = new float[4]
			{
				((BoneWeight)(ref val)).weight0,
				((BoneWeight)(ref val)).weight1,
				((BoneWeight)(ref val)).weight2,
				((BoneWeight)(ref val)).weight3
			};
			for (int num2 = 0; num2 < 4; num2++)
			{
				if (array5[num2] <= 0f)
				{
					array4[num2] = 0;
					continue;
				}
				if (!dictionary2.TryGetValue(array4[num2], out var value3))
				{
					value3 = list5.Count;
					dictionary2.Add(array4[num2], value3);
					list5.Add(array4[num2]);
				}
				array4[num2] = value3;
			}
			((BoneWeight)(ref val)).boneIndex0 = array4[0];
			((BoneWeight)(ref val)).boneIndex1 = array4[1];
			((BoneWeight)(ref val)).boneIndex2 = array4[2];
			((BoneWeight)(ref val)).boneIndex3 = array4[3];
			array3[n] = val;
		}
		Mesh val2 = new Mesh
		{
			name = ((Object)sharedMesh).name + "_JusticeFirstPerson",
			indexFormat = (IndexFormat)(list.Count > 65535)
		};
		val2.vertices = Subset(sharedMesh.vertices, list);
		if (sharedMesh.normals.Length == sharedMesh.vertexCount)
		{
			val2.normals = Subset(sharedMesh.normals, list);
		}
		if (sharedMesh.tangents.Length == sharedMesh.vertexCount)
		{
			val2.tangents = Subset(sharedMesh.tangents, list);
		}
		if (sharedMesh.colors32.Length == sharedMesh.vertexCount)
		{
			val2.colors32 = Subset(sharedMesh.colors32, list);
		}
		for (int num3 = 0; num3 < 8; num3++)
		{
			List<Vector4> list6 = new List<Vector4>();
			sharedMesh.GetUVs(num3, list6);
			if (list6.Count == sharedMesh.vertexCount)
			{
				val2.SetUVs(num3, Subset(list6.ToArray(), list));
			}
		}
		val2.boneWeights = array3;
		val2.bindposes = Subset(sharedMesh.bindposes, list5);
		val2.subMeshCount = list2.Count;
		for (int num4 = 0; num4 < list2.Count; num4++)
		{
			val2.SetTriangles(list2[num4], num4, false);
		}
		val2.RecalculateBounds();
		value = new Entry
		{
			Mesh = val2,
			BoneIndices = list5.ToArray(),
			MaterialSlots = list3.ToArray()
		};
		Cache.Add(sharedMesh, value);
		return value;
	}

	private static T[] Subset<T>(T[] source, List<int> indices)
	{
		T[] array = new T[indices.Count];
		for (int i = 0; i < indices.Count; i++)
		{
			array[i] = source[indices[i]];
		}
		return array;
	}

	public static GameObject Convert(GameObject model)
	{
		JusticeSourceRotationGrant component = model.GetComponent<JusticeSourceRotationGrant>();
		JusticeSourceRotationGrant.Grant[] sourceGrants = (Object.op_Implicit((Object)(object)component) ? component.grants : null);
		HashSet<Transform> arms = ArmBones(model);
		SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			Entry entry = Get(val, arms);
			if (entry == null)
			{
				((Renderer)val).enabled = false;
				Remove((Object)(object)val);
				continue;
			}
			Transform[] bones = val.bones;
			Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
			Transform[] array = (Transform[])(object)new Transform[entry.BoneIndices.Length];
			Material[] array2 = (Material[])(object)new Material[entry.MaterialSlots.Length];
			for (int j = 0; j < array.Length; j++)
			{
				array[j] = bones[entry.BoneIndices[j]];
			}
			for (int k = 0; k < array2.Length; k++)
			{
				array2[k] = sharedMaterials[entry.MaterialSlots[k]];
			}
			val.sharedMesh = entry.Mesh;
			val.bones = array;
			((Renderer)val).sharedMaterials = array2;
			val.quality = (SkinQuality)4;
			val.updateWhenOffscreen = true;
			((Renderer)val).shadowCastingMode = (ShadowCastingMode)0;
		}
		StripSimulation(model);
		JusticeSourceBillboard[] componentsInChildren2 = model.GetComponentsInChildren<JusticeSourceBillboard>(true);
		foreach (JusticeSourceBillboard justiceSourceBillboard in componentsInChildren2)
		{
			if (Object.op_Implicit((Object)(object)justiceSourceBillboard.sphericalTarget))
			{
				((Renderer)justiceSourceBillboard.sphericalTarget).enabled = false;
				Remove((Object)(object)((Component)justiceSourceBillboard.sphericalTarget).gameObject);
			}
			((Behaviour)justiceSourceBillboard).enabled = false;
			Remove((Object)(object)justiceSourceBillboard);
		}
		JusticeSourceFlipbook[] componentsInChildren3 = model.GetComponentsInChildren<JusticeSourceFlipbook>(true);
		foreach (JusticeSourceFlipbook obj in componentsInChildren3)
		{
			((Behaviour)obj).enabled = false;
			Remove((Object)(object)obj);
		}
		JusticeViewModelPose obj2 = model.GetComponent<JusticeViewModelPose>() ?? model.AddComponent<JusticeViewModelPose>();
		obj2.SourceGrants = sourceGrants;
		obj2.Initialize();
		model.GetComponent<JusticeOutfitState>()?.Rebind();
		model.GetComponent<JusticeAdaptiveLighting>()?.Rebind();
		return model;
	}

	public static void StripSimulation(GameObject model)
	{
		JusticeFlameLight[] componentsInChildren = model.GetComponentsInChildren<JusticeFlameLight>(true);
		foreach (JusticeFlameLight obj in componentsInChildren)
		{
			Light target = obj.target;
			((Behaviour)obj).enabled = false;
			Remove((Object)(object)obj);
			if (Object.op_Implicit((Object)(object)target))
			{
				Remove((Object)(object)((Component)target).gameObject);
			}
		}
		Collider[] componentsInChildren2 = model.GetComponentsInChildren<Collider>(true);
		foreach (Collider obj2 in componentsInChildren2)
		{
			obj2.enabled = false;
			Remove((Object)(object)obj2);
		}
		MonoBehaviour[] componentsInChildren3 = model.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren3)
		{
			switch (((object)val).GetType().FullName)
			{
			case "JusticeSuit.JusticeSecondaryMotion":
			case "JusticeSuit.JusticeHeadTracking":
			case "JusticeSuit.JusticeFace":
			case "JusticeSuit.JusticeToonFrame":
			case "JusticeSuit.JusticeSourceGearRotation":
			case "JusticeSuit.JusticeGigiPropellers":
			case "JusticeSuit.JusticeSourceRotationGrant":
			case "JusticeSuit.JusticePlayerReaction":
			case "JigglePhysics.JiggleRigBuilder":
				((Behaviour)val).enabled = false;
				Remove((Object)(object)val);
				break;
			}
		}
	}

	private static void Remove(Object component)
	{
		if (Application.isPlaying)
		{
			Object.Destroy(component);
		}
		else
		{
			Object.DestroyImmediate(component);
		}
	}

	public static void Clear()
	{
		foreach (Entry value in Cache.Values)
		{
			if (value != null && Object.op_Implicit((Object)(object)value.Mesh))
			{
				Remove((Object)(object)value.Mesh);
			}
		}
		Cache.Clear();
	}
}
public static class JusticeFirstPersonPatch
{
	public static void Install(Harmony harmony)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected O, but got Unknown
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Expected O, but got Unknown
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Expected O, but got Unknown
		Type type = typeof(BodyReplacementBase).Assembly.GetType("ModelReplacement.Scripts.MeshHelper", throwOnError: true);
		MethodInfo methodInfo = AccessTools.Method(type, "ConvertModelToViewModel", new Type[1] { typeof(GameObject) }, (Type[])null);
		if (methodInfo == null)
		{
			throw new MissingMethodException(type.FullName, "ConvertModelToViewModel");
		}
		harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(JusticeFirstPersonPatch), "BeforeConvert", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(BodyReplacementBase), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(JusticeFirstPersonPatch), "AfterBodyCreated", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		Type type2 = typeof(BodyReplacementBase).Assembly.GetType("ModelReplacement.Scripts.Player.ViewModelUpdater", throwOnError: true);
		MethodInfo methodInfo2 = AccessTools.Method(type2, "UpdateViewModel", Type.EmptyTypes, (Type[])null);
		if (methodInfo2 == null)
		{
			throw new MissingMethodException(type2.FullName, "UpdateViewModel");
		}
		harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(JusticeFirstPersonPatch), "BeforeViewPose", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(type2, "AssignViewModelReplacement", new Type[2]
		{
			typeof(GameObject),
			typeof(GameObject)
		}, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(JusticeFirstPersonPatch), "AfterViewAssigned", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static bool BeforeConvert(GameObject __0, ref GameObject __result)
	{
		if (!Object.op_Implicit((Object)(object)__0) || !((Object)__0).name.StartsWith("Justice_", StringComparison.Ordinal))
		{
			return true;
		}
		__result = JusticeFirstPersonMesh.Convert(__0);
		return false;
	}

	private static void AfterBodyCreated(BodyReplacementBase __instance)
	{
		if (!(__instance is JusticeBody))
		{
			return;
		}
		object? value = AccessTools.Field(typeof(BodyReplacementBase), "replacementModel").GetValue(__instance);
		GameObject val = (GameObject)((value is GameObject) ? value : null);
		object? value2 = AccessTools.Field(typeof(BodyReplacementBase), "replacementModelShadow").GetValue(__instance);
		GameObject val2 = (GameObject)((value2 is GameObject) ? value2 : null);
		if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2))
		{
			JusticeFirstPersonMesh.StripSimulation(val2);
			val2.AddComponent<JusticeShadowPose>().Initialize(val);
		}
		object? value3 = AccessTools.Field(typeof(BodyReplacementBase), "replacementViewModel").GetValue(__instance);
		GameObject val3 = (GameObject)((value3 is GameObject) ? value3 : null);
		if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)__instance.controller))
		{
			JusticeViewModelPose component = val3.GetComponent<JusticeViewModelPose>();
			SkinnedMeshRenderer thisPlayerModelArms = __instance.controller.thisPlayerModelArms;
			if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)thisPlayerModelArms))
			{
				component.Bind(thisPlayerModelArms, __instance.controller.playerModelArmsMetarig);
			}
		}
	}

	private static bool BeforeViewPose(ViewModelUpdater __instance)
	{
		GameObject replacementViewModel = __instance.replacementViewModel;
		if (!Object.op_Implicit((Object)(object)replacementViewModel))
		{
			return true;
		}
		JusticeViewModelPose component = replacementViewModel.GetComponent<JusticeViewModelPose>();
		if (Object.op_Implicit((Object)(object)component))
		{
			return !component.Step();
		}
		return true;
	}

	private static void AfterViewAssigned(GameObject __0, GameObject __1)
	{
		if (!Object.op_Implicit((Object)(object)__0) || !Object.op_Implicit((Object)(object)__1))
		{
			return;
		}
		JusticeOutfitControl.AttachView(__0, __1);
		JusticeViewModelPose component = __1.GetComponent<JusticeViewModelPose>();
		if (Object.op_Implicit((Object)(object)component))
		{
			PlayerControllerB component2 = __0.GetComponent<PlayerControllerB>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				component.Bind(component2.thisPlayerModelArms, component2.playerModelArmsMetarig);
			}
		}
	}
}
[DefaultExecutionOrder(470)]
public sealed class JusticeFlameLight : MonoBehaviour
{
	public struct FlameFrame
	{
		public float LightGain;

		public float EmissionGain;

		public float Opacity;

		public float LifeGain;
	}

	public Light target;

	public Renderer flameRenderer;

	public int materialSlot;

	public Renderer[] receivers = (Renderer[])(object)new Renderer[0];

	public float baseIntensity = 10f;

	public float worldRange = 0.2f;

	public float flickerAmplitude = 0.35f;

	public float deathDuration = 2f;

	private Light boundTarget;

	private Component hdData;

	private Action<float> setHDRPIntensity;

	private float legacyBaseIntensity;

	private bool alive = true;

	private double deathStartedAt = -1.0;

	private MaterialPropertyBlock block;

	private static MaterialPropertyBlock receiverBlock;

	private Renderer[] boundReceivers;

	private int[] receiverSlots;

	private readonly List<Material> receiverMaterials = new List<Material>();

	private static readonly int EmissionGainID = Shader.PropertyToID("_JusticeFlameEmissionGain");

	private static readonly int OpacityID = Shader.PropertyToID("_JusticeFlameOpacity");

	private static readonly int ReceiverID = Shader.PropertyToID("_JusticeChestLightPositionWS");

	public bool IsAlive => alive;

	public double DeathStartedAt => deathStartedAt;

	public float CurrentMultiplier { get; private set; } = 1f;

	public FlameFrame CurrentFrame { get; private set; }

	public bool UsesHDRPIntensity
	{
		get
		{
			if (Object.op_Implicit((Object)(object)hdData))
			{
				return setHDRPIntensity != null;
			}
			return false;
		}
	}

	public Vector4 ReceiverPosition
	{
		get
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			if (!Object.op_Implicit((Object)(object)target))
			{
				return Vector4.zero;
			}
			Vector3 position = ((Component)target).transform.position;
			return new Vector4(position.x, position.y, position.z, Mathf.Clamp(worldRange, 0.01f, 0.2f));
		}
	}

	public static double Clock
	{
		get
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if (Object.op_Implicit((Object)(object)singleton) && singleton.IsListening)
			{
				NetworkTime serverTime = singleton.ServerTime;
				return ((NetworkTime)(ref serverTime)).Time;
			}
			return Time.timeAsDouble;
		}
	}

	private static bool Finite(double value)
	{
		if (!double.IsNaN(value))
		{
			return !double.IsInfinity(value);
		}
		return false;
	}

	private void Bind()
	{
		if ((Object)(object)boundTarget == (Object)(object)target)
		{
			return;
		}
		boundTarget = target;
		hdData = null;
		setHDRPIntensity = null;
		if (!Object.op_Implicit((Object)(object)target))
		{
			return;
		}
		legacyBaseIntensity = target.intensity;
		Component[] components = ((Component)target).GetComponents<Component>();
		foreach (Component val in components)
		{
			if (!Object.op_Implicit((Object)(object)val) || ((object)val).GetType().FullName != "UnityEngine.Rendering.HighDefinition.HDAdditionalLightData")
			{
				continue;
			}
			PropertyInfo property = ((object)val).GetType().GetProperty("intensity", BindingFlags.Instance | BindingFlags.Public);
			if (!(property == null) && !(property.PropertyType != typeof(float)) && !(property.GetSetMethod() == null))
			{
				try
				{
					setHDRPIntensity = (Action<float>)Delegate.CreateDelegate(typeof(Action<float>), val, property.GetSetMethod());
					hdData = val;
					break;
				}
				catch
				{
					setHDRPIntensity = null;
					hdData = null;
					break;
				}
			}
		}
	}

	public static float Flicker(float time, float amplitude)
	{
		return LivingFlicker(time, amplitude);
	}

	private static float LivingFlicker(double time, float amplitude)
	{
		float num = (float)(time % 360.0) * (float)Math.PI * 2f;
		return 1f + Mathf.Clamp(amplitude, 0f, 0.5f) * (0.4f * Mathf.Sin(num * 2.1f) + 0.3f * Mathf.Sin(num * 7.3f + 1.7f) + 0.2f * Mathf.Sin(num * 11.1f + 0.3f) + 0.1f * Mathf.Sin(num * 29.4f + 2.3f));
	}

	public void SetLifeState(bool living, double transitionTime)
	{
		if (Finite(transitionTime) && living != alive)
		{
			alive = living;
			deathStartedAt = (living ? (-1.0) : transitionTime);
		}
	}

	public FlameFrame Evaluate(double time)
	{
		if (!Finite(time))
		{
			return default(FlameFrame);
		}
		float num = LivingFlicker(time, flickerAmplitude);
		if (alive)
		{
			return new FlameFrame
			{
				LightGain = num,
				EmissionGain = num,
				Opacity = 1f,
				LifeGain = 1f
			};
		}
		double num2 = Math.Max(0.0, time - deathStartedAt);
		float num3 = (float)(num2 / Math.Max(0.1, deathDuration));
		if (num3 >= 1f)
		{
			return default(FlameFrame);
		}
		float num4 = (float)(num2 % 360.0) * (float)Math.PI * 2f;
		float num5 = 0.55f * Mathf.Sin(num4 * 7.1f) + 0.3f * Mathf.Sin(num4 * 13.7f + 1.3f) + 0.15f * Mathf.Sin(num4 * 31.4f + 0.7f);
		float num6 = Mathf.SmoothStep(0.025f, 1f, Mathf.Clamp01(0.5f + 0.5f * num5));
		num6 = Mathf.Lerp(1f, num6, Mathf.SmoothStep(0f, 1f, num3 / 0.15f));
		float num7 = Mathf.Pow(Mathf.Max(0f, 1f - num3), 1.65f);
		float num8 = num * num7 * num6;
		return new FlameFrame
		{
			LightGain = num8,
			EmissionGain = num8,
			Opacity = num7 * Mathf.Sqrt(num6),
			LifeGain = num7
		};
	}

	public void ApplyTo(Renderer renderer, int slot, double time)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		if (Object.op_Implicit((Object)(object)renderer) && slot >= 0 && Finite(time))
		{
			if (block == null)
			{
				block = new MaterialPropertyBlock();
			}
			FlameFrame flameFrame = Evaluate(time);
			renderer.GetPropertyBlock(block, slot);
			block.SetFloat(EmissionGainID, flameFrame.EmissionGain);
			block.SetFloat(OpacityID, flameFrame.Opacity);
			renderer.SetPropertyBlock(block, slot);
			((Component)renderer).GetComponent<JusticeSourceBillboard>()?.RefreshSpherical();
		}
	}

	public static void ApplyReceiver(Renderer renderer, int slot, Vector4 positionWSRange)
	{
		//IL_0013: 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_0011: Expected O, but got Unknown
		if (receiverBlock == null)
		{
			receiverBlock = new MaterialPropertyBlock();
		}
		ApplyReceiver(renderer, slot, positionWSRange, receiverBlock);
	}

	public static void ApplyReceiver(Renderer renderer, int slot, Vector4 positionWSRange, MaterialPropertyBlock scratch)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)renderer) && slot >= 0 && scratch != null)
		{
			renderer.GetPropertyBlock(scratch, slot);
			scratch.SetVector(ReceiverID, positionWSRange);
			renderer.SetPropertyBlock(scratch, slot);
		}
	}

	private void ApplySourceReceivers()
	{
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Expected O, but got Unknown
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		if (boundReceivers != receivers || receiverSlots == null)
		{
			boundReceivers = receivers;
			receiverSlots = new int[(receivers != null) ? receivers.Length : 0];
			for (int i = 0; i < receiverSlots.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)receivers[i]))
				{
					receiverMaterials.Clear();
					receivers[i].GetSharedMaterials(receiverMaterials);
					receiverSlots[i] = receiverMaterials.Count;
				}
			}
		}
		if (block == null)
		{
			block = new MaterialPropertyBlock();
		}
		Vector4 receiverPosition = ReceiverPosition;
		for (int j = 0; j < receiverSlots.Length; j++)
		{
			if (Object.op_Implicit((Object)(object)boundReceivers[j]))
			{
				for (int k = 0; k < receiverSlots[j]; k++)
				{
					ApplyReceiver(boundReceivers[j], k, receiverPosition, block);
				}
			}
		}
	}

	public void Step(double time)
	{
		if (!Finite(time))
		{
			return;
		}
		Bind();
		CurrentFrame = Evaluate(time);
		CurrentMultiplier = CurrentFrame.LightGain;
		if (Object.op_Implicit((Object)(object)flameRenderer))
		{
			ApplyTo(flameRenderer, materialSlot, time);
		}
		ApplySourceReceivers();
		if (Object.op_Implicit((Object)(object)target))
		{
			target.range = Mathf.Clamp(worldRange, 0.01f, 0.2f);
			((Behaviour)target).enabled = ((Behaviour)this).enabled && ((Component)this).gameObject.activeInHierarchy && CurrentMultiplier > 0f;
			if (UsesHDRPIntensity)
			{
				setHDRPIntensity(Mathf.Max(0f, baseIntensity) * CurrentMultiplier);
			}
			else
			{
				target.intensity = Mathf.Max(0f, legacyBaseIntensity) * CurrentMultiplier;
			}
		}
	}

	private void OnEnable()
	{
		Step(Clock);
	}

	private void LateUpdate()
	{
		Step(Clock);
	}

	private void OnDisable()
	{
		if (Object.op_Implicit((Object)(object)target))
		{
			((Behaviour)target).enabled = false;
		}
	}
}
public class JusticeFootAlignment : MonoBehaviour
{
	private Transform hip;

	private Transform leftSole;

	private Transform rightSole;

	private Transform playerLeft;

	private Transform playerRight;

	private Vector3 leftReference;

	private Vector3 rightReference;

	private SkinnedMeshRenderer source;

	private bool ready;

	public float LastCorrection { get; private set; }

	public void Align(SkinnedMeshRenderer player)
	{
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		//IL_026a: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)player))
		{
			return;
		}
		if (!ready || (Object)(object)source != (Object)(object)player)
		{
			source = player;
			Animator component = ((Component)this).GetComponent<Animator>();
			if (!Object.op_Implicit((Object)(object)component) || !component.isHuman)
			{
				return;
			}
			hip = component.GetBoneTransform((HumanBodyBones)0);
			Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>(true);
			leftSole = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "JusticeSole.L"));
			rightSole = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "JusticeSole.R"));
			Transform val = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "EmployeeSoleReference.L"));
			Transform val2 = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "EmployeeSoleReference.R"));
			playerLeft = ((IEnumerable<Transform>)player.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "foot.L"));
			playerRight = ((IEnumerable<Transform>)player.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "foot.R"));
			ready = Object.op_Implicit((Object)(object)hip) && Object.op_Implicit((Object)(object)leftSole) && Object.op_Implicit((Object)(object)rightSole) && Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)playerLeft) && Object.op_Implicit((Object)(object)playerRight);
			if (!ready)
			{
				return;
			}
			leftReference = val.localPosition;
			rightReference = val2.localPosition;
		}
		float num = Mathf.Min(playerLeft.TransformPoint(leftReference).y, playerRight.TransformPoint(rightReference).y);
		float num2 = Mathf.Min(leftSole.position.y, rightSole.position.y);
		LastCorrection = num - num2;
		if (!float.IsNaN(LastCorrection) && !float.IsInfinity(LastCorrection))
		{
			Transform obj = hip;
			obj.position += Vector3.up * LastCorrection;
		}
	}
}
internal sealed class JusticeGigiContext
{
	private sealed class Entry
	{
		internal ulong Owner;

		internal PlayerControllerB Player;

		internal JusticeGigiRules Rules = new JusticeGigiRules();
	}

	private sealed class Rig
	{
		internal GameObject Model;

		internal Transform[] Breasts;

		internal Transform Chest;

		internal JusticeChestGazeTarget Authored;

		internal int Suit;
	}

	internal static ConfigEntry<bool> StarsEnabled;

	internal static ConfigEntry<bool> HeartsEnabled;

	internal static ConfigEntry<bool> LadderHearts;

	internal static ConfigEntry<bool> ChestGaze;

	internal static ConfigEntry<string> HeartSuits;

	internal static ConfigEntry<int> LootValue;

	internal static ConfigEntry<int> PileCount;

	internal static ConfigEntry<int> PileValue;

	internal static ConfigEntry<float> Duration;

	internal static ConfigEntry<float> NearRange;

	internal static ConfigEntry<float> GazeDelay;

	internal static ConfigEntry<float> GazeRamp;

	internal static ConfigEntry<float> PileRadius;

	internal static ConfigEntry<float> LadderRange;

	private static readonly Dictionary<ulong, Entry> ledger = new Dictionary<ulong, Entry>();

	private static readonly Dictionary<int, Rig> rigs = new Dictionary<int, Rig>();

	private static readonly FieldInfo sourceField = AccessTools.Field(typeof(BodyReplacementBase), "replacementModel");

	private static StartOfRound scene;

	private static bool phaseSeeded;

	private static bool inShipPhase;

	private static GrabbableObject[] items = (GrabbableObject[])(object)new GrabbableObject[0];

	private static InteractTrigger[] ladders = (InteractTrigger[])(object)new InteractTrigger[0];

	private static float nextObjects;

	private static string suitConfig;

	private static string[] suitTokens = new string[0];

	private readonly PlayerControllerB player;

	private readonly Transform model;

	private JusticeGigiRules rules;

	private readonly RaycastHit[] hits = (RaycastHit[])(object)new RaycastHit[24];

	private float nextScan;

	private PlayerControllerB nearPlayer;

	private bool ladderHeart;

	internal bool Heart
	{
		get
		{
			if (HeartsEnabled.Value)
			{
				if (!Object.op_Implicit((Object)(object)nearPlayer))
				{
					return ladderHeart;
				}
				return true;
			}
			return false;
		}
	}

	internal bool Stars
	{
		get
		{
			if (StarsEnabled.Value)
			{
				return rules.Stars(Time.unscaledTime);
			}
			return false;
		}
	}

	internal ulong GazePlayerId
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)nearPlayer))
			{
				return ulong.MaxValue;
			}
			return nearPlayer.playerClientId;
		}
	}

	internal float GazeWeight
	{
		get
		{
			if (!Plugin.Eyes.Value || !ChestGaze.Value || !Object.op_Implicit((Object)(object)nearPlayer))
			{
				return 0f;
			}
			return rules.GazeWeight;
		}
	}

	internal static void Configure(ConfigFile config)
	{
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Expected O, but got Unknown
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Expected O, but got Unknown
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Expected O, but got Unknown
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Expected O, but got Unknown
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Expected O, but got Unknown
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Expected O, but got Unknown
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Expected O, but got Unknown
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Expected O, but got Unknown
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Expected O, but got Unknown
		StarsEnabled = config.Bind<bool>("Gigi expressions", "StarEyes", true, "Star eyes for newly discovered valuable scrap, first pickup, and a qualifying visible ship pile on entry.");
		HeartsEnabled = config.Bind<bool>("Gigi expressions", "HeartEyes", true, "Heart eyes beside configured suits or below another climber on the same ladder.");
		LadderHearts = config.Bind<bool>("Gigi expressions", "LadderHeartEyes", true, (ConfigDescription)null);
		ChestGaze = config.Bind<bool>("Gigi expressions", "GradualChestGaze", true, "Allow only Gigi's eyes to drift toward the nearby target's authored breast bones, with humanoid chest fallback.");
		HeartSuits = config.Bind<string>("Gigi expressions", "HeartSuitNames", "Elizabeth Rose Bloodflame;Raora Panthera;Fuwawa Abyssgard;Mori Calliope;Shiori Novella;Nerissa Ravencroft;Kronii;Botan", "Semicolon-separated case-insensitive suit-name fragments. Spaces and punctuation are ignored. Empty list disables proximity hearts; ladder hearts remain independent.");
		LootValue = config.Bind<int>("Gigi expressions", "HighValueLootThreshold", 100, new ConfigDescription("Value must be strictly greater than this threshold.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000), Array.Empty<object>()));
		PileCount = config.Bind<int>("Gigi expressions", "ShipPileMinimumItems", 6, new ConfigDescription("Minimum dropped scrap items in a ship pile.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 100), Array.Empty<object>()));
		PileValue = config.Bind<int>("Gigi expressions", "ShipPileMinimumValue", 500, new ConfigDescription("Minimum total value of that pile.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100000), Array.Empty<object>()));
		Duration = config.Bind<float>("Gigi expressions", "StarSeconds", 3.5f, new ConfigDescription("Ship reaction ends this many seconds after entry, at most once per round.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), Array.Empty<object>()));
		NearRange = config.Bind<float>("Gigi expressions", "HeartProximityMeters", 1.25f, new ConfigDescription("Very-close player distance; requires front view and a clear line of sight.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>()));
		GazeDelay = config.Bind<float>("Gigi expressions", "ChestGazeDelaySeconds", 2f, new ConfigDescription("Continuous time beside the same target before gaze starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
		GazeRamp = config.Bind<float>("Gigi expressions", "ChestGazeRampSeconds", 1.5f, new ConfigDescription("Exponential eye-only drift time constant.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
		PileRadius = config.Bind<float>("Gigi expressions", "ShipPileRadiusMeters", 2f, new ConfigDescription("Scrap must cluster within this radius of a pile item.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f), Array.Empty<object>()));
		LadderRange = config.Bind<float>("Gigi expressions", "LadderAboveMeters", 2.5f, new ConfigDescription("Maximum distance above Gigi on the same ladder.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 5f), Array.Empty<object>()));
	}

	internal static void Tick()
	{
		StartOfRound instance = StartOfRound.Instance;
		if ((Object)(object)scene != (Object)(object)instance)
		{
			Clear();
			scene = instance;
		}
		if (!Object.op_Implicit((Object)(object)instance))
		{
			return;
		}
		bool flag = instance.inShipPhase;
		if (phaseSeeded && inShipPhase && !flag)
		{
			foreach (Entry value in ledger.Values)
			{
				value.Rules.NewRound(Object.op_Implicit((Object)(object)value.Player) && value.Player.isInHangarShipRoom);
			}
		}
		inShipPhase = flag;
		phaseSeeded = true;
		foreach (Entry value2 in ledger.Values)
		{
			if (Object.op_Implicit((Object)(object)value2.Player) && ((NetworkBehaviour)value2.Player).OwnerClientId == value2.Owner)
			{
				value2.Rules.Ship(value2.Player.isInHangarShipRoom, seesPile: false, Time.unscaledTime, Duration.Value);
			}
		}
	}

	internal JusticeGigiContext(PlayerControllerB p, Transform avatar)
	{
		Tick();
		player = p;
		model = avatar;
		if (!ledger.TryGetValue(p.playerClientId, out var value) || value.Owner != ((NetworkBehaviour)p).OwnerClientId)
		{
			value = new Entry
			{
				Owner = ((NetworkBehaviour)p).OwnerClientId,
				Player = p
			};
			value.Rules.SeedShip(p.isInHangarShipRoom);
			ledger[p.playerClientId] = value;
		}
		rules = value.Rules;
	}

	private static void ScanObjects(float now)
	{
		if (!(now < nextObjects))
		{
			nextObjects = now + 1f;
			items = Object.FindObjectsByType<GrabbableObject>((FindObjectsSortMode)0);
			ladders = (from t in Object.FindObjectsByType<InteractTrigger>((FindObjectsSortMode)0)
				where Object.op_Implicit((Object)(object)t) && t.isLadder
				select t).ToArray();
		}
	}

	private static bool Scrap(GrabbableObject item)
	{
		if (Object.op_Implicit((Object)(object)item) && ((Behaviour)item).isActiveAndEnabled && Object.op_Implicit((Object)(object)item.itemProperties) && item.itemProperties.isScrap && item.scrapValue > 0 && !item.isHeld && !item.isPocketed)
		{
			return !item.isHeldByEnemy;
		}
		return false;
	}

	internal void Pickup(GrabbableObject item, float now)
	{
		if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.itemProperties) && item.itemProperties.isScrap && StarsEnabled.Value)
		{
			rules.NoticeLoot(((Object)item).GetInstanceID(), item.scrapValue, LootValue.Value, now, Duration.Value);
		}
	}

	private bool Visible(Vector3 point, Transform root, float range)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_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)
		//IL_0063: 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)
		Vector3 origin = (Object.op_Implicit((Object)(object)player.playerEye) ? player.playerEye.position : (((Component)player).transform.position + Vector3.up * 1.6f));
		if (JusticeAttentionSelection.InView(origin, ((Component)player).transform.forward, point, range))
		{
			return JusticeAttentionSelection.Visible(origin, point, Object.op_Implicit((Object)(object)scene) ? scene.collidersAndRoomMaskAndDefault : (-5), ((Component)player).transform, model, root, hits);
		}
		return false;
	}

	private static string Suit(PlayerControllerB p)
	{
		StartOfRound instance = StartOfRound.Instance;
		List<UnlockableItem> list = ((!Object.op_Implicit((Object)(object)instance)) ? null : instance.unlockablesList?.unlockables);
		if (list == null || p.currentSuitID < 0 || p.currentSuitID >= list.Count)
		{
			return "";
		}
		return list[p.currentSuitID].unlockableName;
	}

	private static Rig TargetRig(PlayerControllerB p)
	{
		BodyReplacementBase component = ((Component)p).GetComponent<BodyReplacementBase>();
		GameObject val = (GameObject)(Object.op_Implicit((Object)(object)component) ? /*isinst with value type is only supported in some contexts*/: null);
		int instanceID = ((Object)p).GetInstanceID();
		if (rigs.TryGetValue(instanceID, out var value) && (Object)(object)value.Model == (Object)(object)val && value.Suit == p.currentSuitID && (!Object.op_Implicit((Object)(object)value.Model) || Object.op_Implicit((Object)(object)value.Chest)))
		{
			return value;
		}
		Rig rig = new Rig
		{
			Model = val,
			Suit = p.currentSuitID,
			Breasts = (Transform[])(object)new Transform[0]
		};
		if (Object.op_Implicit((Object)(object)val))
		{
			rig.Authored = val.GetComponent<JusticeChestGazeTarget>();
			if (Object.op_Implicit((Object)(object)rig.Authored))
			{
				rig.Chest = rig.Authored.chest;
				rig.Breasts = rig.Authored.breasts;
			}
			else
			{
				Transform[] source = (from b in val.GetComponentsInChildren<SkinnedMeshRenderer>(true).SelectMany((SkinnedMeshRenderer s) => s.bones)
					where Object.op_Implicit((Object)(object)b)
					select b).Distinct().ToArray();
				rig.Breasts = (from b in source.Where(delegate(Transform b)
					{
						string text = ((Object)b).name.ToLowerInvariant();
						return text.Contains("breast") || text.Contains("bust") || text.Contains("boob") || (text.Contains("胸") && !text.Contains("upper"));
					})
					orderby ((Object)b).name.Length
					select b).Take(2).ToArray();
				Animator componentInChildren = val.GetComponentInChildren<Animator>();
				if (Object.op_Implicit((Object)(object)componentInChildren) && componentInChildren.isHuman)
				{
					rig.Chest = componentInChildren.GetBoneTransform((HumanBodyBones)54) ?? componentInChildren.GetBoneTransform((HumanBodyBones)8);
				}
				if (!Object.op_Implicit((Object)(object)rig.Chest))
				{
					rig.Chest = ((IEnumerable<Transform>)source).FirstOrDefault((Func<Transform, bool>)((Transform b) => ((Object)b).name == "spine_04.x" || ((Object)b).name == "DEF-spine.003"));
				}
			}
		}
		if (!Object.op_Implicit((Object)(object)rig.Chest) && Object.op_Implicit((Object)(object)p.playerBodyAnimator) && p.playerBodyAnimator.isHuman)
		{
			rig.Chest = p.playerBodyAnimator.GetBoneTransform((HumanBodyBones)54) ?? p.playerBodyAnimator.GetBoneTransform((HumanBodyBones)8);
		}
		rigs[instanceID] = rig;
		return rig;
	}

	internal static Vector3 ChestPoint(PlayerControllerB p)
	{
		//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_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		Rig rig = TargetRig(p);
		if (Object.op_Implicit((Object)(object)rig.Authored))
		{
			return rig.Authored.Point;
		}
		Vector3 val = Vector3.zero;
		int num = 0;
		Transform[] breasts = rig.Breasts;
		foreach (Transform val2 in breasts)
		{
			if (Object.op_Implicit((Object)(object)val2))
			{
				val += val2.position;
				num++;
			}
		}
		if (num <= 0)
		{
			if (!Object.op_Implicit((Object)(object)rig.Chest))
			{
				return ((Component)p).transform.position + Vector3.up * 1.3f;
			}
			return rig.Chest.position;
		}
		return val / (float)num;
	}

	private static InteractTrigger LadderOf(PlayerControllerB p)
	{
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: 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_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		if (!p.isClimbingLadder)
		{
			return null;
		}
		InteractTrigger currentTriggerInAnimationWith = p.currentTriggerInAnimationWith;
		if (Object.op_Implicit((Object)(object)currentTriggerInAnimationWith) && currentTriggerInAnimationWith.isLadder)
		{
			return currentTriggerInAnimationWith;
		}
		InteractTrigger result = null;
		float num = 0.5625f;
		InteractTrigger[] array = ladders;
		foreach (InteractTrigger val in array)
		{
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.ladderHorizontalPosition) || !Object.op_Implicit((Object)(object)val.bottomOfLadderPosition) || !Object.op_Implicit((Object)(object)val.topOfLadderPosition))
			{
				continue;
			}
			float y = ((Component)p).transform.position.y;
			if (!(y < Mathf.Min(val.bottomOfLadderPosition.position.y, val.topOfLadderPosition.position.y) - 0.5f) && !(y > Mathf.Max(val.bottomOfLadderPosition.position.y, val.topOfLadderPosition.position.y) + 0.5f))
			{
				Vector3 val2 = Vector3.ProjectOnPlane(((Component)p).transform.position - val.ladderHorizontalPosition.position, Vector3.up);
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					result = val;
					num = sqrMagnitude;
				}
			}
		}
		return result;
	}

	private bool SeesPile()
	{
		//IL_004a: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		if (!player.isInHangarShipRoom || rules.ShipReactionUsed)
		{
			return false;
		}
		GrabbableObject[] array = items;
		foreach (GrabbableObject val in array)
		{
			if (!Scrap(val) || !val.isInShipRoom || !Visible(((Component)val).transform.position, ((Component)val).transform, 8f))
			{
				continue;
			}
			int num = 0;
			int num2 = 0;
			GrabbableObject[] array2 = items;
			foreach (GrabbableObject val2 in array2)
			{
				if (Scrap(val2) && val2.isInShipRoom)
				{
					Vector3 val3 = ((Component)val2).transform.position - ((Component)val).transform.position;
					if (((Vector3)(ref val3)).sqrMagnitude <= PileRadius.Value * PileRadius.Value)
					{
						num++;
						num2 += val2.scrapValue;
					}
				}
			}
			if (JusticeGigiRules.Pile(num, num2, PileCount.Value, PileValue.Value))
			{
				return true;
			}
		}
		return false;
	}

	internal void Evaluate(float now, float delta)
	{
		//IL_0434: Unknown result type (might be due to invalid IL or missing references)
		//IL_0444: Unknown result type (might be due to invalid IL or missing references)
		//IL_0449: Unknown result type (might be due to invalid IL or missing references)
		//IL_044e: 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_0301: Unknown result type (might be due to invalid IL or missing references)
		//IL_0311: Unknown result type (might be due to invalid IL or missing references)
		//IL_0316: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_035f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0361: Unknown result type (might be due to invalid IL or missing references)
		//IL_0366: Unknown result type (might be due to invalid IL or missing references)
		//IL_036b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0374: Unknown result type (might be due to invalid IL or missing references)
		Tick();
		if (Object.op_Implicit((Object)(object)player) && ((NetworkBehaviour)player).IsOwner && (!ledger.TryGetValue(player.playerClientId, out var value) || value.Owner != ((NetworkBehaviour)player).OwnerClientId || value.Rules != rules))
		{
			Entry entry = new Entry
			{
				Owner = ((NetworkBehaviour)player).OwnerClientId,
				Player = player
			};
			entry.Rules.SeedShip(player.isInHangarShipRoom);
			ledger[player.playerClientId] = entry;
			rules = entry.Rules;
		}
		if (!Object.op_Implicit((Object)(object)player) || !((NetworkBehaviour)player).IsOwner || player.isPlayerDead || !player.isPlayerControlled)
		{
			nearPlayer = null;
			ladderHeart = false;
			rules.Near(0, eligible: false, now, delta, GazeDelay.Value, GazeRamp.Value);
			return;
		}
		Vector3 val5;
		if (now >= nextScan)
		{
			nextScan = now + 0.1f;
			ScanObjects(now);
			if (suitConfig != HeartSuits.Value)
			{
				suitConfig = HeartSuits.Value;
				suitTokens = suitConfig.Split(';');
			}
			if (StarsEnabled.Value)
			{
				GrabbableObject[] array = items;
				foreach (GrabbableObject val in array)
				{
					if (Scrap(val) && !val.isInShipRoom && val.scrapValue > LootValue.Value && Visible(((Component)val).transform.position, ((Component)val).transform, 3f))
					{
						rules.NoticeLoot(((Object)val).GetInstanceID(), val.scrapValue, LootValue.Value, now, Duration.Value);
					}
				}
				rules.Ship(player.isInHangarShipRoom, SeesPile(), now, Duration.Value);
			}
			nearPlayer = null;
			ladderHeart = false;
			float num = NearRange.Value * NearRange.Value;
			InteractTrigger val2 = LadderOf(player);
			if (Object.op_Implicit((Object)(object)scene) && scene.allPlayerScripts != null)
			{
				PlayerControllerB[] allPlayerScripts = scene.allPlayerScripts;
				foreach (PlayerControllerB val3 in allPlayerScripts)
				{
					if (!Object.op_Implicit((Object)(object)val3) || (Object)(object)val3 == (Object)(object)player || !val3.isPlayerControlled || val3.isPlayerDead || !((Component)val3).gameObject.activeInHierarchy)
					{
						continue;
					}
					Vector3 val4 = ((Component)val3).transform.position - ((Component)player).transform.position;
					if (HeartsEnabled.Value && LadderHearts.Value)
					{
						bool isClimbingLadder = player.isClimbingLadder;
						bool isClimbingLadder2 = val3.isClimbingLadder;
						bool sameLadder = Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 == (Object)(object)LadderOf(val3);
						val5 = Vector3.ProjectOnPlane(val4, Vector3.up);
						if (JusticeGigiRules.Ladder(isClimbingLadder, isClimbingLadder2, sameLadder, ((Vector3)(ref val5)).magnitude, val4.y, LadderRange.Value))
						{
							ladderHeart = true;
						}
					}
					float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
					if (HeartsEnabled.Value && !(sqrMagnitude > num) && JusticeGigiRules.SuitMatches(Suit(val3), suitTokens) && Visible(ChestPoint(val3), ((Component)val3).transform, NearRange.Value + 1f))
					{
						nearPlayer = val3;
						num = sqrMagnitude;
					}
				}
			}
		}
		if (Object.op_Implicit((Object)(object)nearPlayer))
		{
			if (!nearPlayer.isPlayerDead && nearPlayer.isPlayerControlled)
			{
				val5 = ((Component)nearPlayer).transform.position - ((Component)player).transform.position;
				if (!(((Vector3)(ref val5)).sqrMagnitude > NearRange.Value * NearRange.Value))
				{
					goto IL_0475;
				}
			}
			nearPlayer = null;
		}
		goto IL_0475;
		IL_0475:
		rules.Near(Object.op_Implicit((Object)(object)nearPlayer) ? ((Object)nearPlayer).GetInstanceID() : 0, HeartsEnabled.Value && Plugin.Eyes.Value && ChestGaze.Value && Object.op_Implicit((Object)(object)nearPlayer), now, delta, GazeDelay.Value, GazeRamp.Value);
	}

	internal void SuppressGaze()
	{
		rules.Near(0, eligible: false, Time.unscaledTime, 0f, GazeDelay.Value, GazeRamp.Value);
	}

	internal void Revived()
	{
		nearPlayer = null;
		ladderHeart = false;
		rules.ResetTransient();
		nextScan = 0f;
	}

	internal static bool Gaze(PlayerControllerB wearer, ulong targetId, float weight