Decompiled source of MikuShowcase v0.2.5

plugins/com.github.Thanks.MikuShowcase.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using MikuDanceProject.Core;
using MikuDanceProject.Mmd;
using MikuDanceProject.Runtime;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace MikuDanceProject.Runtime
{
	internal sealed class DanceController : MonoBehaviour
	{
		private readonly struct PlacementPose
		{
			public Vector3 Position { get; }

			public Vector3 Forward { get; }

			public string Source { get; }

			private PlacementPose(Vector3 position, Vector3 forward, string source)
			{
				//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_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				Position = position;
				Forward = forward;
				Source = source;
			}

			public static PlacementPose Create(Vector3 position, Vector3 forward, string source)
			{
				//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)
				return new PlacementPose(position, forward, source);
			}
		}

		[CompilerGenerated]
		private sealed class <LoadAssetsRoutine>d__60 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public DanceController <>4__this;

			private string <resolvedUnityBundlePath>5__2;

			object? IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object? IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadAssetsRoutine>d__60(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<resolvedUnityBundlePath>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				DanceController danceController = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (danceController._config == null || danceController._logger == null || danceController._isLoading)
					{
						return false;
					}
					danceController._isLoading = true;
					<resolvedUnityBundlePath>5__2 = danceController._config.ResolveUnityBundlePath();
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					try
					{
						if (!File.Exists(<resolvedUnityBundlePath>5__2))
						{
							danceController._logger.LogError((object)("Required Unity asset bundle file was not found: '" + <resolvedUnityBundlePath>5__2 + "'."));
							return false;
						}
						danceController._loadedPrefab = danceController._unityBundleLoader.Load(<resolvedUnityBundlePath>5__2, danceController._logger);
						Object.DontDestroyOnLoad((Object)(object)danceController._loadedPrefab.Template);
						danceController._logger.LogInfo((object)("Using Unity asset bundle dancer source '" + <resolvedUnityBundlePath>5__2 + "'."));
					}
					catch (Exception arg)
					{
						danceController._logger.LogError((object)$"Failed to load Unity asset bundle dancer source '{<resolvedUnityBundlePath>5__2}': {arg}");
					}
					finally
					{
						danceController._isLoading = false;
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const float GroundProbeStartHeight = 80f;

		private const float GroundProbeDistance = 200f;

		private const float PlayerGroundProbeStartHeight = 1.25f;

		private const float PlayerGroundProbeMaxRise = 0.6f;

		private const float PlayerGroundProbePreferredMaxDrop = 0.9f;

		private const float PlayerGroundProbeFallbackMaxDrop = 1.25f;

		private const float PlayerGroundProbeSearchRadius = 3f;

		private const float PlayerColliderFootPadding = 0.05f;

		private const float RuntimeRefreshInterval = 0.25f;

		private const float OfflinePauseTimeScaleThreshold = 0.001f;

		private const float AudioMinDistanceMeters = 1f;

		private const float MotionTrimStartFrame = 435f;

		private const float MotionFrameRate = 30f;

		private const float AudioFadeDurationSeconds = 0.35f;

		private const float AudioRestartLeadTimeSeconds = 0.05f;

		private const BindingFlags InstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags StaticBindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const string DancerObjectName = "MikuDanceDisplay";

		private static readonly Vector3 AirportDisplayPosition = new Vector3(-16.78f, 2.55f, 64.85f);

		private static readonly Vector3 AirportDisplayForward = Vector3.forward;

		private static readonly Vector3[] PlayerGroundProbeSampleOffsets = BuildPlayerGroundSampleOffsets();

		private static readonly Type? CharacterType = FindGameType("Character");

		private static readonly Type? PlayerType = FindGameType("Player");

		private static readonly Type? MenuWindowType = FindGameType("MenuWindow");

		private static readonly FieldInfo? LocalCharacterField = CharacterType?.GetField("localCharacter", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo? LocalPlayerField = PlayerType?.GetField("localPlayer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo? AllActiveWindowsField = MenuWindowType?.GetField("AllActiveWindows", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly PropertyInfo? CharacterCenterProperty = CharacterType?.GetProperty("Center", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly PropertyInfo? CharacterVirtualCenterProperty = CharacterType?.GetProperty("VirtualCenter", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly PropertyInfo? PlayerCharacterProperty = PlayerType?.GetProperty("character", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo? PlayerCharacterField = PlayerType?.GetField("character", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly PropertyInfo? MenuWindowIsOpenProperty = MenuWindowType?.GetProperty("isOpen", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private readonly UnityAssetBundleLoader _unityBundleLoader = new UnityAssetBundleLoader();

		private DancePluginConfig? _config;

		private ManualLogSource? _logger;

		private LoadedDancePrefab? _loadedPrefab;

		private GameObject? _activeDancer;

		private Animator? _activeAnimator;

		private Animation? _activeAnimation;

		private AudioSource? _activeAudioSource;

		private AnimationClip? _activePrimaryAnimatorClip;

		private bool _activeUsesMmdMorphBridge;

		private PlacementPose _activePlacement;

		private bool _hasActivePlacement;

		private bool _isLoading;

		private float _nextRefreshTime;

		private string? _lastSceneName;

		private bool _loggedSceneHint;

		private bool _lastAudioEnabledState;

		private bool _audioRetrySuppressed;

		private bool _isPausedForOfflineMenu;

		private bool _audioPausedForOfflineMenu;

		private AudioSource? _fadingAudioSource;

		private float _audioFadeStartTime;

		private float _audioFadeDuration;

		private float _audioFadeTargetVolume;

		public void Initialize(DancePluginConfig config, ManualLogSource logger)
		{
			_config = config;
			_logger = logger;
			_lastAudioEnabledState = config.EnableAudio.Value;
		}

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(LoadAssetsRoutine());
		}

		private void OnDestroy()
		{
			_unityBundleLoader.UnloadRetainedBundle();
		}

		private void Update()
		{
			if (_config == null || _logger == null)
			{
				return;
			}
			TrackSceneTransitions();
			if (!_config.ModEnabled.Value)
			{
				if ((Object)(object)_activeDancer != (Object)null)
				{
					DestroyActiveDancer("Model hidden because ModEnabled=False.");
				}
				_hasActivePlacement = false;
				return;
			}
			EnsureAirportLobbyDisplay();
			ProcessSpawnHotkey();
			MaintainSynchronizedLoopPlayback();
			UpdateActiveAudioFade();
			if (Time.unscaledTime < _nextRefreshTime)
			{
				return;
			}
			_nextRefreshTime = Time.unscaledTime + 0.25f;
			if (!((Object)(object)_activeDancer == (Object)null))
			{
				if (_hasActivePlacement)
				{
					ApplyPlacement(_activeDancer.transform, _activePlacement, _config, _loadedPrefab);
				}
				RefreshLivePlayback(_activeDancer);
			}
		}

		[IteratorStateMachine(typeof(<LoadAssetsRoutine>d__60))]
		private IEnumerator LoadAssetsRoutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAssetsRoutine>d__60(0)
			{
				<>4__this = this
			};
		}

		private void TrackSceneTransitions()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			if (!string.Equals(name, _lastSceneName, StringComparison.Ordinal))
			{
				_lastSceneName = name;
				_loggedSceneHint = false;
				_nextRefreshTime = 0f;
				if ((Object)(object)_activeDancer != (Object)null)
				{
					DestroyActiveDancer("Scene changed to '" + name + "'. The model must be placed again in the new scene.");
				}
				_hasActivePlacement = false;
				_isPausedForOfflineMenu = false;
				_audioPausedForOfflineMenu = false;
			}
		}

		private void EnsureAirportLobbyDisplay()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			if (_loadedPrefab == null || (Object)(object)_activeDancer != (Object)null || _hasActivePlacement)
			{
				return;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			if (!string.Equals(((Scene)(ref activeScene)).name, "Airport", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			_activePlacement = CreateGroundLockedPlacement(AirportDisplayPosition, AirportDisplayForward, "AirportLobbyDisplay");
			_hasActivePlacement = true;
			if (EnsureDancerInstance() && !((Object)(object)_activeDancer == (Object)null))
			{
				ApplyPlacement(_activeDancer.transform, _activePlacement, _config, _loadedPrefab);
				ConfigurePlayback(_activeDancer);
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					string text = $"Spawned default Airport display model at {_activeDancer.transform.position}. ";
					Quaternion rotation = _activeDancer.transform.rotation;
					logger.LogInfo((object)(text + $"rotation={((Quaternion)(ref rotation)).eulerAngles}, scale={_activeDancer.transform.localScale}."));
				}
			}
		}

		private void ProcessSpawnHotkey()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0030: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			if (_config != null && _logger != null)
			{
				if (!_loggedSceneHint)
				{
					_loggedSceneHint = true;
					ManualLogSource? logger = _logger;
					Scene activeScene = SceneManager.GetActiveScene();
					logger.LogInfo((object)$"Placement hotkey ready in scene '{((Scene)(ref activeScene)).name}'. Press {_config.SpawnModelKey.Value} to spawn the model or move it to the local player's current ground position.");
				}
				KeyCode value = _config.SpawnModelKey.Value;
				if ((int)value != 0 && Input.GetKeyDown(value))
				{
					SpawnOrMoveToCurrentPlayer();
				}
			}
		}

		private void SpawnOrMoveToCurrentPlayer()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			if (_config == null || _logger == null)
			{
				return;
			}
			if (_loadedPrefab == null)
			{
				_logger.LogWarning((object)(_isLoading ? "The Unity asset bundle is still loading. Try the placement hotkey again in a moment." : "The Unity asset bundle has not been loaded successfully, so the model cannot be spawned."));
				return;
			}
			if (!TryResolveCurrentLocalPlayerPose(out Vector3 position, out Vector3 forward, out Transform ignoredRoot, out string source))
			{
				_logger.LogWarning((object)"The local player transform is not available yet, so the model cannot be moved right now.");
				return;
			}
			Vector3 forward2 = ResolveFacingDirection(-forward);
			_activePlacement = CreatePlayerGroundLockedPlacement(position, forward2, source, ignoredRoot);
			_hasActivePlacement = true;
			bool flag = EnsureDancerInstance();
			if (!((Object)(object)_activeDancer == (Object)null))
			{
				ApplyPlacement(_activeDancer.transform, _activePlacement, _config, _loadedPrefab);
				if (flag)
				{
					ConfigurePlayback(_activeDancer);
				}
				else
				{
					RefreshLivePlayback(_activeDancer);
				}
				ManualLogSource? logger = _logger;
				string[] obj = new string[7]
				{
					flag ? "Spawned" : "Moved",
					" display model in scene '",
					null,
					null,
					null,
					null,
					null
				};
				Scene activeScene = SceneManager.GetActiveScene();
				obj[2] = ((Scene)(ref activeScene)).name;
				obj[3] = "'. ";
				obj[4] = $"source={source}, playerPosition={position}, groundedPosition={_activePlacement.Position}, ";
				object arg = _activeDancer.transform.position;
				Quaternion rotation = _activeDancer.transform.rotation;
				obj[5] = $"modelPosition={arg}, modelRotation={((Quaternion)(ref rotation)).eulerAngles}, ";
				obj[6] = $"modelScale={_activeDancer.transform.localScale}.";
				logger.LogInfo((object)string.Concat(obj));
			}
		}

		private bool EnsureDancerInstance()
		{
			if ((Object)(object)_activeDancer != (Object)null || _loadedPrefab == null)
			{
				return false;
			}
			_activeDancer = Object.Instantiate<GameObject>(_loadedPrefab.Template);
			((Object)_activeDancer).name = "MikuDanceDisplay";
			RemoveAllColliders(_activeDancer);
			ResetAudioPlaybackState();
			CacheActiveRuntimeComponents(_activeDancer);
			_activeUsesMmdMorphBridge = false;
			if (_loadedPrefab.Source == LoadedPrefabSource.UnityAssetBundle)
			{
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)("Using embedded Animator playback for '" + ((Object)_activeDancer).name + "'. Runtime MMD4Mecanim morph bridge is disabled for Unity AssetBundle models to avoid CreateMMDModel errors and blendshape overrides."));
				}
			}
			if (0 == 0 && _loadedPrefab.Source == LoadedPrefabSource.RuntimePmx)
			{
				DancePhysicsConfigurator.Apply(_activeDancer);
			}
			if (_loadedPrefab.Source == LoadedPrefabSource.RuntimePmx)
			{
				ConfigureMotionSolvers(_activeDancer);
			}
			NormalizeRendererMaterials(_activeDancer);
			ConfigureFacialExpressions(_activeDancer);
			_activeDancer.SetActive(true);
			return true;
		}

		private void DestroyActiveDancer(string reason)
		{
			if (!((Object)(object)_activeDancer == (Object)null))
			{
				AudioSource activeAudioSource = _activeAudioSource;
				if ((Object)(object)activeAudioSource != (Object)null && activeAudioSource.isPlaying)
				{
					activeAudioSource.Stop();
				}
				ClearActiveAudioFade(activeAudioSource);
				Object.Destroy((Object)(object)_activeDancer);
				_activeDancer = null;
				_activeUsesMmdMorphBridge = false;
				ClearActiveRuntimeComponents();
				ResetAudioPlaybackState();
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)reason);
				}
			}
		}

		private static void ApplyPlacement(Transform dancerTransform, PlacementPose placement, DancePluginConfig config, LoadedDancePrefab? prefab)
		{
			//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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			float resolvedModelScale = config.ResolvedModelScale;
			float num = ((prefab == null) ? 0f : ((0f - prefab.LocalMinY) * resolvedModelScale));
			Vector3 position = placement.Position;
			position.y += num;
			dancerTransform.localScale = Vector3.one * resolvedModelScale;
			dancerTransform.position = position;
			dancerTransform.rotation = Quaternion.LookRotation(ResolveFacingDirection(placement.Forward), Vector3.up) * Quaternion.Euler(0f, config.ModelYawCorrection.Value, 0f);
		}

		private static PlacementPose CreateGroundLockedPlacement(Vector3 desiredPosition, Vector3 forward, string source)
		{
			//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_0004: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = desiredPosition;
			position.y = ResolveGroundYExact(desiredPosition, desiredPosition.y + 80f, 200f, float.PositiveInfinity);
			return PlacementPose.Create(position, forward, source);
		}

		private static PlacementPose CreatePlayerGroundLockedPlacement(Vector3 desiredPosition, Vector3 forward, string source, Transform? ignoredRoot)
		{
			//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_0004: 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_0016: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = desiredPosition;
			position.y = ResolveGroundYNearPlayer(desiredPosition, desiredPosition.y + 1.25f, 200f, desiredPosition.y + 0.6f, ignoredRoot);
			return PlacementPose.Create(position, forward, source);
		}

		private static Vector3 ResolveFacingDirection(Vector3 forward)
		{
			//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_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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)
			Vector3 val = Vector3.ProjectOnPlane(forward, Vector3.up);
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f))
			{
				return Vector3.forward;
			}
			return ((Vector3)(ref val)).normalized;
		}

		private static bool TryResolveCurrentLocalPlayerPose(out Vector3 position, out Vector3 forward, out Transform? ignoredRoot, out string source)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetLocalCharacterObject(out object source2) && TryResolveCharacterPose(source2, "Character.localCharacter", out position, out forward, out ignoredRoot, out source))
			{
				return true;
			}
			if (TryGetLocalPlayerCharacterObject(out object source3) && TryResolveCharacterPose(source3, "Player.localPlayer.character", out position, out forward, out ignoredRoot, out source))
			{
				return true;
			}
			position = default(Vector3);
			forward = Vector3.forward;
			ignoredRoot = null;
			source = string.Empty;
			return false;
		}

		private static float ResolveGroundYExact(Vector3 desiredPosition, float startY, float maxDistance, float maxAcceptedY, Transform? ignoredRoot = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			Transform ignoredRoot2 = ignoredRoot;
			RaycastHit[] array = Physics.RaycastAll(new Vector3(desiredPosition.x, startY, desiredPosition.z), Vector3.down, maxDistance, -1, (QueryTriggerInteraction)1);
			if (array.Length == 0)
			{
				return desiredPosition.y;
			}
			RaycastHit[] array2 = (from hit in array
				where (Object)(object)((RaycastHit)(ref hit)).collider != (Object)null
				where ((RaycastHit)(ref hit)).normal.y > 0.35f
				where !ShouldIgnoreGroundHit(hit, ignoredRoot2)
				select hit).ToArray();
			if (array2.Length == 0)
			{
				return desiredPosition.y;
			}
			if (!float.IsPositiveInfinity(maxAcceptedY))
			{
				RaycastHit val = (from hit in array2
					where ((RaycastHit)(ref hit)).point.y <= maxAcceptedY
					orderby ((RaycastHit)(ref hit)).point.y descending, ((RaycastHit)(ref hit)).distance
					select hit).FirstOrDefault();
				if ((Object)(object)((RaycastHit)(ref val)).collider != (Object)null)
				{
					return ((RaycastHit)(ref val)).point.y;
				}
				return desiredPosition.y;
			}
			RaycastHit val2 = (from hit in array2
				orderby ((RaycastHit)(ref hit)).point.y descending, ((RaycastHit)(ref hit)).distance
				select hit).FirstOrDefault();
			if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null))
			{
				return ((RaycastHit)(ref val2)).point.y;
			}
			return desiredPosition.y;
		}

		private static float ResolveGroundYNearPlayer(Vector3 desiredPosition, float startY, float maxDistance, float maxAcceptedY, Transform? ignoredRoot)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			GroundSampleCandidate? groundSampleCandidate = null;
			GroundSampleCandidate? groundSampleCandidate2 = null;
			for (int i = 0; i < PlayerGroundProbeSampleOffsets.Length; i++)
			{
				GroundSampleCandidate? groundSampleCandidate3 = TryResolveGroundCandidate(desiredPosition + PlayerGroundProbeSampleOffsets[i], startY, maxDistance, maxAcceptedY, ignoredRoot);
				if (groundSampleCandidate3.HasValue)
				{
					if (!groundSampleCandidate2.HasValue || groundSampleCandidate3.Value.IsBetterThan(groundSampleCandidate2.Value))
					{
						groundSampleCandidate2 = groundSampleCandidate3;
					}
					if (!(desiredPosition.y - groundSampleCandidate3.Value.Y > 0.9f) && (!groundSampleCandidate.HasValue || groundSampleCandidate3.Value.IsBetterThan(groundSampleCandidate.Value)))
					{
						groundSampleCandidate = groundSampleCandidate3;
					}
				}
			}
			if (groundSampleCandidate.HasValue)
			{
				return groundSampleCandidate.Value.Y;
			}
			if (groundSampleCandidate2.HasValue && desiredPosition.y - groundSampleCandidate2.Value.Y <= 1.25f)
			{
				return groundSampleCandidate2.Value.Y;
			}
			return desiredPosition.y;
		}

		private static GroundSampleCandidate? TryResolveGroundCandidate(Vector3 desiredPosition, float startY, float maxDistance, float maxAcceptedY, Transform? ignoredRoot)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Transform ignoredRoot2 = ignoredRoot;
			RaycastHit[] array = Physics.RaycastAll(new Vector3(desiredPosition.x, startY, desiredPosition.z), Vector3.down, maxDistance, -1, (QueryTriggerInteraction)1);
			if (array.Length == 0)
			{
				return null;
			}
			GroundSampleCandidate[] array2 = (from hit in array
				where (Object)(object)((RaycastHit)(ref hit)).collider != (Object)null
				where ((RaycastHit)(ref hit)).normal.y > 0.35f
				where !ShouldIgnoreGroundHit(hit, ignoredRoot2)
				where ((RaycastHit)(ref hit)).point.y <= maxAcceptedY
				select new GroundSampleCandidate(((RaycastHit)(ref hit)).point.y, Mathf.Abs(desiredPosition.y - ((RaycastHit)(ref hit)).point.y), Vector2.Distance(new Vector2(desiredPosition.x, desiredPosition.z), new Vector2(((RaycastHit)(ref hit)).point.x, ((RaycastHit)(ref hit)).point.z)), ((RaycastHit)(ref hit)).distance) into hit
				orderby hit.VerticalDelta, hit.HorizontalDelta, hit.RaycastDistance
				select hit).ToArray();
			if (array2.Length != 0)
			{
				return array2[0];
			}
			return null;
		}

		private static bool TryGetLocalCharacterObject(out object source)
		{
			source = LocalCharacterField?.GetValue(null);
			return source != null;
		}

		private static bool TryGetLocalPlayerCharacterObject(out object source)
		{
			object obj = LocalPlayerField?.GetValue(null);
			if (obj == null)
			{
				source = null;
				return false;
			}
			source = PlayerCharacterProperty?.GetValue(obj, null) ?? PlayerCharacterField?.GetValue(obj);
			return source != null;
		}

		private static bool TryResolveCharacterPose(object source, string sourceName, out Vector3 position, out Vector3 forward, out Transform? ignoredRoot, out string resolvedSource)
		{
			//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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			resolvedSource = sourceName;
			if (!TryExtractTransform(source, out Transform transform))
			{
				position = default(Vector3);
				forward = Vector3.forward;
				ignoredRoot = null;
				return false;
			}
			ignoredRoot = transform;
			position = transform.position;
			Vector3 vector2;
			if (TryExtractVector3(CharacterCenterProperty?.GetValue(source, null), out var vector))
			{
				position = new Vector3(vector.x, position.y, vector.z);
				resolvedSource = sourceName + ".CenterXZ";
			}
			else if (TryExtractVector3(CharacterVirtualCenterProperty?.GetValue(source, null), out vector2))
			{
				position = new Vector3(vector2.x, position.y, vector2.z);
				resolvedSource = sourceName + ".VirtualCenterXZ";
			}
			position = new Vector3(position.x, ResolveCharacterFootY(transform, position.y), position.z);
			resolvedSource += ".FootY";
			forward = ResolvePlanarForward(transform);
			return true;
		}

		private static float ResolveCharacterFootY(Transform root, float fallbackY)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			float num = float.PositiveInfinity;
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger)
				{
					Bounds bounds = val.bounds;
					float y = ((Bounds)(ref bounds)).min.y;
					if (!float.IsNaN(y) && !float.IsInfinity(y))
					{
						num = Mathf.Min(num, y);
						flag = true;
					}
				}
			}
			if (!flag)
			{
				return fallbackY;
			}
			return num + 0.05f;
		}

		private static bool ShouldIgnoreGroundHit(RaycastHit hit, Transform? ignoredRoot)
		{
			if ((Object)(object)ignoredRoot == (Object)null || (Object)(object)((RaycastHit)(ref hit)).collider == (Object)null)
			{
				return false;
			}
			if (IsSameOrChildTransform(((Component)((RaycastHit)(ref hit)).collider).transform, ignoredRoot))
			{
				return true;
			}
			Rigidbody attachedRigidbody = ((RaycastHit)(ref hit)).collider.attachedRigidbody;
			if ((Object)(object)attachedRigidbody != (Object)null)
			{
				return IsSameOrChildTransform(((Component)attachedRigidbody).transform, ignoredRoot);
			}
			return false;
		}

		private static bool IsSameOrChildTransform(Transform? candidate, Transform root)
		{
			if ((Object)(object)candidate != (Object)null)
			{
				if (!((Object)(object)candidate == (Object)(object)root))
				{
					return candidate.IsChildOf(root);
				}
				return true;
			}
			return false;
		}

		private static Vector3[] BuildPlayerGroundSampleOffsets()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			Vector2[] obj = new Vector2[8]
			{
				new Vector2(1f, 0f),
				new Vector2(-1f, 0f),
				new Vector2(0f, 1f),
				new Vector2(0f, -1f),
				default(Vector2),
				default(Vector2),
				default(Vector2),
				default(Vector2)
			};
			Vector2 val = new Vector2(1f, 1f);
			obj[4] = ((Vector2)(ref val)).normalized;
			val = new Vector2(1f, -1f);
			obj[5] = ((Vector2)(ref val)).normalized;
			val = new Vector2(-1f, 1f);
			obj[6] = ((Vector2)(ref val)).normalized;
			val = new Vector2(-1f, -1f);
			obj[7] = ((Vector2)(ref val)).normalized;
			Vector2[] array = (Vector2[])(object)obj;
			float[] array2 = new float[6] { 0.35f, 0.7f, 1.1f, 1.6f, 2.2f, 3f };
			List<Vector3> list = new List<Vector3>(1 + array.Length * array2.Length) { Vector3.zero };
			float[] array3 = array2;
			foreach (float num in array3)
			{
				foreach (Vector2 val2 in array)
				{
					list.Add(new Vector3(val2.x * num, 0f, val2.y * num));
				}
			}
			return list.ToArray();
		}

		private void ConfigureMotionSolvers(GameObject dancer)
		{
			if (_logger != null && _loadedPrefab != null)
			{
				(dancer.GetComponent<MmdLegIkSolver>() ?? dancer.AddComponent<MmdLegIkSolver>()).Initialize(_loadedPrefab, _logger);
			}
		}

		private static bool TryExtractTransform(object? source, out Transform transform)
		{
			Transform val = (Transform)((source is Transform) ? source : null);
			if (val == null)
			{
				Component val2 = (Component)((source is Component) ? source : null);
				if (val2 == null)
				{
					GameObject val3 = (GameObject)((source is GameObject) ? source : null);
					if (val3 != null)
					{
						transform = val3.transform;
						return true;
					}
					transform = null;
					return false;
				}
				transform = val2.transform;
				return (Object)(object)transform != (Object)null;
			}
			transform = val;
			return true;
		}

		private static bool TryExtractVector3(object? value, out Vector3 vector)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (value is Vector3 val)
			{
				vector = val;
				return true;
			}
			vector = default(Vector3);
			return false;
		}

		private static Vector3 ResolvePlanarForward(Transform transform)
		{
			//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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f))
			{
				return Vector3.forward;
			}
			return ((Vector3)(ref val)).normalized;
		}

		private static Type? FindGameType(string typeName)
		{
			return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly assembly) => string.Equals(assembly.GetName().Name, "Assembly-CSharp", StringComparison.Ordinal))?.GetType(typeName, throwOnError: false, ignoreCase: false);
		}

		private static void RemoveAllColliders(GameObject root)
		{
			Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
		}

		private void NormalizeRendererMaterials(GameObject root)
		{
			if (_logger == null)
			{
				return;
			}
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				val.enabled = true;
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null);
				if (val2 == null)
				{
					continue;
				}
				val2.updateWhenOffscreen = true;
				Mesh sharedMesh = val2.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null)
				{
					continue;
				}
				int num = Mathf.Max(1, sharedMesh.subMeshCount);
				if (val.sharedMaterials.Length == num)
				{
					continue;
				}
				Material[] array = val.sharedMaterials.Where((Material material) => (Object)(object)material != (Object)null).Take(num).ToArray();
				if (array.Length == 0)
				{
					continue;
				}
				if (array.Length < num)
				{
					Array.Resize(ref array, num);
					for (int j = 0; j < num; j++)
					{
						Material[] array2 = array;
						int num2 = j;
						if (array2[num2] == null)
						{
							array2[num2] = array[Mathf.Max(0, j - 1)];
						}
					}
				}
				val.sharedMaterials = array;
				_logger.LogInfo((object)$"Normalized runtime materials for '{((Object)val).name}'. subMeshes={num}, materials={val.sharedMaterials.Length}.");
			}
		}

		private void ConfigurePlayback(GameObject dancer)
		{
			CacheActiveRuntimeComponents(dancer);
			AudioSource activeAudioSource = _activeAudioSource;
			AudioClip val = ResolveAudioClip(activeAudioSource);
			Animator activeAnimator = _activeAnimator;
			if ((Object)(object)activeAnimator != (Object)null && (Object)(object)activeAnimator.runtimeAnimatorController != (Object)null)
			{
				ConfigureAudioSource(activeAudioSource, val);
				AnimationClip activePrimaryAnimatorClip = _activePrimaryAnimatorClip;
				float num = ResolveSynchronizedAnimatorSpeed(activePrimaryAnimatorClip, val);
				activeAnimator.cullingMode = (AnimatorCullingMode)0;
				activeAnimator.applyRootMotion = false;
				activeAnimator.updateMode = (AnimatorUpdateMode)0;
				activeAnimator.speed = num;
				activeAnimator.Rebind();
				activeAnimator.Update(0f);
				StartAnimatorAtBeginning(activeAnimator, activePrimaryAnimatorClip);
				StartMorphPlayback(dancer);
				bool flag = StartAudioIfEnabled(activeAudioSource, val, activePrimaryAnimatorClip, suppressFurtherRetries: true);
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					string[] obj = new string[11]
					{
						"Animator configured for '",
						((Object)dancer).name,
						"', controller='",
						((Object)activeAnimator.runtimeAnimatorController).name,
						"', avatar='",
						null,
						null,
						null,
						null,
						null,
						null
					};
					Avatar avatar = activeAnimator.avatar;
					obj[5] = ((avatar != null) ? ((Object)avatar).name : null) ?? "(none)";
					obj[6] = "', ";
					obj[7] = string.Format("clip='{0}', clipLength={1:0.###}, ", ((activePrimaryAnimatorClip != null) ? ((Object)activePrimaryAnimatorClip).name : null) ?? "(none)", (activePrimaryAnimatorClip != null) ? activePrimaryAnimatorClip.length : 0f);
					obj[8] = string.Format("audioEnabled={0}, audioClip='{1}', audioLength={2:0.###}, ", _config?.EnableAudio.Value ?? false, ((val != null) ? ((Object)val).name : null) ?? "(none)", (val != null) ? val.length : 0f);
					obj[9] = $"audioSegmentStart={ResolveAudioSegmentStartSeconds(activePrimaryAnimatorClip, val):0.###}, audioSegmentLength={ResolveAudioSegmentDuration(activePrimaryAnimatorClip, val):0.###}, ";
					obj[10] = $"animatorSpeed={num:0.###}, audioVolume={_config?.ResolvedAudioVolume ?? 0f:0.###}, audioRange={_config?.ResolvedAudioRangeMeters ?? 0f:0.###}, audioStarted={flag}, audioIsPlaying={activeAudioSource != null && activeAudioSource.isPlaying}.";
					logger.LogInfo((object)string.Concat(obj));
				}
				return;
			}
			Animation activeAnimation = _activeAnimation;
			if ((Object)(object)activeAnimation != (Object)null && (Object)(object)_loadedPrefab?.Clip != (Object)null)
			{
				activeAnimation.cullingType = (AnimationCullingType)0;
				if ((Object)(object)activeAnimation.GetClip(((Object)_loadedPrefab.Clip).name) == (Object)null)
				{
					activeAnimation.AddClip(_loadedPrefab.Clip, ((Object)_loadedPrefab.Clip).name);
				}
				activeAnimation.clip = _loadedPrefab.Clip;
				activeAnimation.wrapMode = (WrapMode)2;
				activeAnimation.Stop();
				activeAnimation.Rewind();
				activeAnimation.Play(((Object)_loadedPrefab.Clip).name);
				ConfigureAudioSource(activeAudioSource, val);
				StartAudioIfEnabled(activeAudioSource, val, _loadedPrefab.Clip, suppressFurtherRetries: true);
				ManualLogSource? logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)$"Animation configured for '{((Object)dancer).name}', clip='{((Object)_loadedPrefab.Clip).name}', isPlaying={activeAnimation.isPlaying}.");
				}
			}
			else
			{
				StartMorphPlayback(dancer);
			}
		}

		private void ConfigureFacialExpressions(GameObject dancer)
		{
			CacheActiveRuntimeComponents(dancer);
			if ((Object)(object)_loadedPrefab?.MorphClip != (Object)null)
			{
				MikuFacialExpressionController component = dancer.GetComponent<MikuFacialExpressionController>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = false;
				}
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)("Skipping fallback facial expression controller for '" + ((Object)dancer).name + "' because a VMD morph clip is available."));
				}
				return;
			}
			if (_activeUsesMmdMorphBridge)
			{
				MikuFacialExpressionController component2 = dancer.GetComponent<MikuFacialExpressionController>();
				if ((Object)(object)component2 != (Object)null)
				{
					((Behaviour)component2).enabled = false;
				}
				ManualLogSource? logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)("Skipping fallback facial expression controller for '" + ((Object)dancer).name + "' because the runtime MMD4Mecanim morph bridge is active."));
				}
				return;
			}
			LoadedDancePrefab? loadedPrefab = _loadedPrefab;
			if (loadedPrefab != null && loadedPrefab.Source == LoadedPrefabSource.UnityAssetBundle && (Object)(object)_activeAnimator != (Object)null && (Object)(object)_activeAnimator.runtimeAnimatorController != (Object)null && (Object)(object)_activePrimaryAnimatorClip != (Object)null)
			{
				ManualLogSource? logger3 = _logger;
				if (logger3 != null)
				{
					logger3.LogInfo((object)("Unity AssetBundle Animator clip '" + ((Object)_activePrimaryAnimatorClip).name + "' is active on '" + ((Object)dancer).name + "', but no morph bridge is available. Falling back to simplified facial controller."));
				}
			}
			(dancer.GetComponent<MikuFacialExpressionController>() ?? dancer.AddComponent<MikuFacialExpressionController>()).Initialize(_activeAudioSource, _activeAnimator, _logger);
		}

		private void RefreshLivePlayback(GameObject dancer)
		{
			CacheActiveRuntimeComponents(dancer);
			Animator activeAnimator = _activeAnimator;
			AudioSource activeAudioSource = _activeAudioSource;
			AudioClip val = ResolveAudioClip(activeAudioSource);
			ConfigureAudioSource(activeAudioSource, val);
			HandleAudioToggleState();
			if (HandleOfflineMenuPause(activeAnimator, activeAudioSource, val))
			{
				return;
			}
			if ((Object)(object)activeAnimator != (Object)null && (Object)(object)activeAnimator.runtimeAnimatorController != (Object)null)
			{
				AnimationClip val2 = ResolvePrimaryAnimatorClip(activeAnimator);
				activeAnimator.speed = ResolveSynchronizedAnimatorSpeed(val2, val);
				DancePluginConfig? config = _config;
				if (config == null || !config.EnableAudio.Value || !((Object)(object)activeAudioSource != (Object)null) || !((Object)(object)val != (Object)null) || activeAudioSource.isPlaying || _audioRetrySuppressed)
				{
					return;
				}
				StartAnimatorAtBeginning(activeAnimator, val2);
				StartMorphPlayback(dancer);
				if (StartAudioIfEnabled(activeAudioSource, val, val2, suppressFurtherRetries: true))
				{
					ManualLogSource? logger = _logger;
					if (logger != null)
					{
						logger.LogInfo((object)("Audio was enabled while the model was already active. Restarted synchronized playback with clip '" + ((Object)val).name + "'."));
					}
				}
			}
			else
			{
				DancePluginConfig? config2 = _config;
				if (config2 != null && config2.EnableAudio.Value && (Object)(object)activeAudioSource != (Object)null && (Object)(object)val != (Object)null && !activeAudioSource.isPlaying && !_audioRetrySuppressed)
				{
					StartAudioIfEnabled(activeAudioSource, val, _loadedPrefab?.Clip, suppressFurtherRetries: true);
				}
			}
		}

		private void HandleAudioToggleState()
		{
			bool flag = _config?.EnableAudio.Value ?? false;
			if (flag != _lastAudioEnabledState)
			{
				_audioRetrySuppressed = false;
				_lastAudioEnabledState = flag;
			}
		}

		private void ResetAudioPlaybackState()
		{
			_audioRetrySuppressed = false;
			_lastAudioEnabledState = _config?.EnableAudio.Value ?? false;
			ClearActiveAudioFade();
		}

		private void ConfigureAudioSource(AudioSource? audioSource, AudioClip? audioClip)
		{
			if (!((Object)(object)audioSource == (Object)null))
			{
				if ((Object)(object)audioClip != (Object)null && (Object)(object)audioSource.clip == (Object)null)
				{
					audioSource.clip = audioClip;
				}
				audioSource.playOnAwake = false;
				audioSource.loop = false;
				DancePluginConfig? config = _config;
				audioSource.mute = config == null || !config.EnableAudio.Value;
				if (!IsActiveAudioFade(audioSource))
				{
					audioSource.volume = _config?.ResolvedAudioVolume ?? 1f;
				}
				float maxDistance = Mathf.Max(1.01f, _config?.ResolvedAudioRangeMeters ?? 5f);
				audioSource.spatialBlend = 1f;
				audioSource.dopplerLevel = 0f;
				audioSource.rolloffMode = (AudioRolloffMode)1;
				audioSource.minDistance = 1f;
				audioSource.maxDistance = maxDistance;
				audioSource.spread = 0f;
				DancePluginConfig? config2 = _config;
				if ((config2 == null || !config2.EnableAudio.Value) && audioSource.isPlaying)
				{
					ClearActiveAudioFade(audioSource);
					audioSource.Stop();
					audioSource.time = 0f;
				}
			}
		}

		private bool StartAudioIfEnabled(AudioSource? audioSource, AudioClip? audioClip, AnimationClip? animationClip, bool suppressFurtherRetries)
		{
			DancePluginConfig? config = _config;
			if (config == null || !config.EnableAudio.Value || (Object)(object)audioSource == (Object)null || (Object)(object)audioClip == (Object)null)
			{
				if ((Object)(object)audioSource != (Object)null)
				{
					ClearActiveAudioFade(audioSource);
					audioSource.Stop();
					audioSource.time = 0f;
				}
				_audioRetrySuppressed = false;
				return false;
			}
			float num = ResolveAudioSegmentStartSeconds(animationClip, audioClip);
			float num2 = ResolveAudioSegmentDuration(animationClip, audioClip);
			if (num2 <= 0.01f)
			{
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogWarning((object)("Audio segment duration is invalid for clip '" + ((Object)audioClip).name + "'."));
				}
				return false;
			}
			try
			{
				audioClip.LoadAudioData();
				audioSource.clip = audioClip;
				audioSource.loop = false;
				audioSource.time = Mathf.Clamp(num, 0f, Mathf.Max(0f, audioClip.length - 0.01f));
				audioSource.volume = 0f;
				audioSource.Play();
				BeginAudioFade(audioSource, Mathf.Min(0.35f, num2 * 0.5f));
			}
			catch (Exception ex)
			{
				if (suppressFurtherRetries)
				{
					_audioRetrySuppressed = true;
				}
				ManualLogSource? logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("Audio playback failed for clip '" + ((Object)audioClip).name + "': " + ex.Message));
				}
				return false;
			}
			bool isPlaying = audioSource.isPlaying;
			if (!isPlaying && suppressFurtherRetries)
			{
				_audioRetrySuppressed = true;
				ManualLogSource? logger3 = _logger;
				if (logger3 == null)
				{
					return isPlaying;
				}
				logger3.LogWarning((object)("Audio playback could not start for clip '" + ((Object)audioClip).name + "'. Automatic retries are suppressed until audio is toggled again or the model is respawned."));
			}
			return isPlaying;
		}

		private void MaintainSynchronizedLoopPlayback()
		{
			if ((Object)(object)_activeDancer == (Object)null)
			{
				return;
			}
			DancePluginConfig? config = _config;
			if (config == null || !config.EnableAudio.Value || _isPausedForOfflineMenu)
			{
				return;
			}
			if ((Object)(object)_activeAnimator == (Object)null || (Object)(object)_activeAudioSource == (Object)null)
			{
				CacheActiveRuntimeComponents(_activeDancer);
			}
			Animator activeAnimator = _activeAnimator;
			AudioSource activeAudioSource = _activeAudioSource;
			AudioClip val = ResolveAudioClip(activeAudioSource);
			if ((Object)(object)activeAnimator == (Object)null || (Object)(object)activeAnimator.runtimeAnimatorController == (Object)null || (Object)(object)activeAudioSource == (Object)null || (Object)(object)val == (Object)null || !activeAudioSource.isPlaying)
			{
				return;
			}
			AnimationClip activePrimaryAnimatorClip = _activePrimaryAnimatorClip;
			if (!((Object)(object)activePrimaryAnimatorClip == (Object)null))
			{
				float num = ResolveAudioSegmentEndSeconds(activePrimaryAnimatorClip, val);
				if (!(activeAudioSource.time < num - 0.05f))
				{
					StartAnimatorAtBeginning(activeAnimator, activePrimaryAnimatorClip);
					StartMorphPlayback(_activeDancer);
					StartAudioIfEnabled(activeAudioSource, val, activePrimaryAnimatorClip, suppressFurtherRetries: true);
				}
			}
		}

		private void StartMorphPlayback(GameObject? dancer)
		{
			if (!((Object)(object)dancer == (Object)null) && !((Object)(object)_loadedPrefab?.MorphClip == (Object)null))
			{
				Animation val = (_activeAnimation = dancer.GetComponent<Animation>() ?? dancer.AddComponent<Animation>());
				val.cullingType = (AnimationCullingType)0;
				if ((Object)(object)val.GetClip(((Object)_loadedPrefab.MorphClip).name) == (Object)null)
				{
					val.AddClip(_loadedPrefab.MorphClip, ((Object)_loadedPrefab.MorphClip).name);
				}
				val.clip = _loadedPrefab.MorphClip;
				val.wrapMode = (WrapMode)2;
				val.Stop(((Object)_loadedPrefab.MorphClip).name);
				val.Rewind(((Object)_loadedPrefab.MorphClip).name);
				val.Play(((Object)_loadedPrefab.MorphClip).name);
			}
		}

		private void BeginAudioFade(AudioSource audioSource, float durationSeconds)
		{
			_fadingAudioSource = audioSource;
			_audioFadeStartTime = Time.unscaledTime;
			_audioFadeDuration = Mathf.Max(0.01f, durationSeconds);
			_audioFadeTargetVolume = _config?.ResolvedAudioVolume ?? 1f;
			audioSource.volume = 0f;
		}

		private void UpdateActiveAudioFade()
		{
			if ((Object)(object)_fadingAudioSource == (Object)null)
			{
				return;
			}
			DancePluginConfig? config = _config;
			if (config == null || !config.EnableAudio.Value || !_fadingAudioSource.isPlaying)
			{
				ClearActiveAudioFade(_fadingAudioSource);
				return;
			}
			float num = Mathf.Clamp01((Time.unscaledTime - _audioFadeStartTime) / _audioFadeDuration);
			_fadingAudioSource.volume = Mathf.Lerp(0f, _audioFadeTargetVolume, num);
			if (num >= 0.999f)
			{
				ClearActiveAudioFade(_fadingAudioSource);
			}
		}

		private bool IsActiveAudioFade(AudioSource? audioSource)
		{
			if ((Object)(object)audioSource != (Object)null)
			{
				return audioSource == _fadingAudioSource;
			}
			return false;
		}

		private void ClearActiveAudioFade(AudioSource? audioSource = null)
		{
			if (!((Object)(object)_fadingAudioSource == (Object)null) && (!((Object)(object)audioSource != (Object)null) || audioSource == _fadingAudioSource))
			{
				if ((Object)(object)_fadingAudioSource != (Object)null)
				{
					_fadingAudioSource.volume = _config?.ResolvedAudioVolume ?? 1f;
				}
				_fadingAudioSource = null;
				_audioFadeStartTime = 0f;
				_audioFadeDuration = 0f;
				_audioFadeTargetVolume = 0f;
			}
		}

		private bool HandleOfflineMenuPause(Animator? animator, AudioSource? audioSource, AudioClip? audioClip)
		{
			if (ShouldPauseForOfflineMenu())
			{
				if (!_isPausedForOfflineMenu)
				{
					_isPausedForOfflineMenu = true;
					_audioPausedForOfflineMenu = (Object)(object)audioSource != (Object)null && audioSource.isPlaying;
					if (_audioPausedForOfflineMenu)
					{
						audioSource.Pause();
					}
					ManualLogSource? logger = _logger;
					if (logger != null)
					{
						logger.LogInfo((object)"Paused dancer playback because the offline menu is open.");
					}
				}
				if ((Object)(object)animator != (Object)null)
				{
					animator.speed = 0f;
				}
				Animation activeAnimation = _activeAnimation;
				if ((Object)(object)activeAnimation != (Object)null && (Object)(object)activeAnimation.clip != (Object)null && (TrackedReference)(object)activeAnimation[((Object)activeAnimation.clip).name] != (TrackedReference)null)
				{
					activeAnimation[((Object)activeAnimation.clip).name].speed = 0f;
				}
				return true;
			}
			if (!_isPausedForOfflineMenu)
			{
				return false;
			}
			_isPausedForOfflineMenu = false;
			if (_audioPausedForOfflineMenu)
			{
				DancePluginConfig? config = _config;
				if (config != null && config.EnableAudio.Value && (Object)(object)audioSource != (Object)null && (Object)(object)audioClip != (Object)null)
				{
					audioSource.UnPause();
				}
			}
			Animation activeAnimation2 = _activeAnimation;
			if ((Object)(object)activeAnimation2 != (Object)null && (Object)(object)activeAnimation2.clip != (Object)null && (TrackedReference)(object)activeAnimation2[((Object)activeAnimation2.clip).name] != (TrackedReference)null)
			{
				activeAnimation2[((Object)activeAnimation2.clip).name].speed = 1f;
			}
			_audioPausedForOfflineMenu = false;
			ManualLogSource? logger2 = _logger;
			if (logger2 != null)
			{
				logger2.LogInfo((object)"Resumed dancer playback after closing the offline menu.");
			}
			return false;
		}

		private static bool ShouldPauseForOfflineMenu()
		{
			if (!PhotonNetwork.OfflineMode)
			{
				return false;
			}
			if (Time.timeScale <= 0.001f)
			{
				return true;
			}
			if (!(AllActiveWindowsField?.GetValue(null) is IEnumerable enumerable))
			{
				return false;
			}
			bool flag = default(bool);
			foreach (object item in enumerable)
			{
				if (item != null)
				{
					object obj = MenuWindowIsOpenProperty?.GetValue(item, null);
					int num;
					if (obj is bool)
					{
						flag = (bool)obj;
						num = 1;
					}
					else
					{
						num = 0;
					}
					if (((uint)num & (flag ? 1u : 0u)) != 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static AudioClip? ResolveAudioClip(AudioSource? audioSource)
		{
			if ((Object)(object)audioSource == (Object)null)
			{
				return null;
			}
			if ((Object)(object)audioSource.clip != (Object)null)
			{
				return audioSource.clip;
			}
			AudioResource resource = audioSource.resource;
			return (AudioClip?)(object)((resource is AudioClip) ? resource : null);
		}

		private void CacheActiveRuntimeComponents(GameObject? dancer)
		{
			if ((Object)(object)dancer == (Object)null)
			{
				ClearActiveRuntimeComponents();
				return;
			}
			_activeAnimator = dancer.GetComponentInChildren<Animator>(true);
			_activeAnimation = dancer.GetComponentInChildren<Animation>(true);
			_activeAudioSource = dancer.GetComponentInChildren<AudioSource>(true);
			_activePrimaryAnimatorClip = (((Object)(object)_activeAnimator != (Object)null && (Object)(object)_activeAnimator.runtimeAnimatorController != (Object)null) ? ResolvePrimaryAnimatorClip(_activeAnimator) : null);
		}

		private void ClearActiveRuntimeComponents()
		{
			_activeAnimator = null;
			_activeAnimation = null;
			_activeAudioSource = null;
			_activePrimaryAnimatorClip = null;
		}

		private static AnimationClip? ResolvePrimaryAnimatorClip(Animator animator)
		{
			RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController;
			if (runtimeAnimatorController == null)
			{
				return null;
			}
			return (from clip in runtimeAnimatorController.animationClips
				where (Object)(object)clip != (Object)null
				orderby clip.length descending
				select clip).FirstOrDefault();
		}

		private static float ResolveSynchronizedAnimatorSpeed(AnimationClip? animationClip, AudioClip? audioClip)
		{
			if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f)
			{
				return 1f;
			}
			if ((Object)(object)audioClip == (Object)null || audioClip.length <= 0.01f)
			{
				return 1f;
			}
			float num = ResolveAudioSegmentDuration(animationClip, audioClip);
			if (num <= 0.01f)
			{
				return 1f;
			}
			return Mathf.Clamp(animationClip.length / num, 0.25f, 4f);
		}

		private static float ResolveAudioSegmentStartSeconds(AnimationClip? animationClip, AudioClip? audioClip)
		{
			if ((Object)(object)animationClip == (Object)null || (Object)(object)audioClip == (Object)null || audioClip.length <= 0.01f)
			{
				return 0f;
			}
			return Mathf.Clamp(14.5f, 0f, Mathf.Max(0f, audioClip.length - 0.01f));
		}

		private static float ResolveAudioSegmentDuration(AnimationClip? animationClip, AudioClip? audioClip)
		{
			if ((Object)(object)audioClip == (Object)null || audioClip.length <= 0.01f)
			{
				return 0f;
			}
			float num = ResolveAudioSegmentStartSeconds(animationClip, audioClip);
			float num2 = Mathf.Max(0f, audioClip.length - num);
			if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f)
			{
				return num2;
			}
			return Mathf.Min(animationClip.length, num2);
		}

		private static float ResolveAudioSegmentEndSeconds(AnimationClip? animationClip, AudioClip? audioClip)
		{
			return ResolveAudioSegmentStartSeconds(animationClip, audioClip) + ResolveAudioSegmentDuration(animationClip, audioClip);
		}

		private static void StartAnimatorAtBeginning(Animator animator, AnimationClip? primaryClip)
		{
			animator.Play(0, 0, 0f);
			animator.Update(0f);
		}
	}
	internal readonly struct GroundSampleCandidate
	{
		public float Y { get; }

		public float VerticalDelta { get; }

		public float HorizontalDelta { get; }

		public float RaycastDistance { get; }

		public GroundSampleCandidate(float y, float verticalDelta, float horizontalDelta, float raycastDistance)
		{
			Y = y;
			VerticalDelta = verticalDelta;
			HorizontalDelta = horizontalDelta;
			RaycastDistance = raycastDistance;
		}

		public bool IsBetterThan(GroundSampleCandidate other)
		{
			if (VerticalDelta < other.VerticalDelta - 0.001f)
			{
				return true;
			}
			if (Mathf.Abs(VerticalDelta - other.VerticalDelta) > 0.001f)
			{
				return false;
			}
			if (HorizontalDelta < other.HorizontalDelta - 0.001f)
			{
				return true;
			}
			if (Mathf.Abs(HorizontalDelta - other.HorizontalDelta) > 0.001f)
			{
				return false;
			}
			return RaycastDistance < other.RaycastDistance;
		}
	}
	internal static class DancePhysicsConfigurator
	{
		private static readonly string[] HairPatterns = new string[8] { "ツインテ", "テール", "髪", "前髪", "横髪", "後髪", "おさげ", "ahoge" };

		private static readonly string[] SkirtPatterns = new string[6] { "スカート", "skirt", "裾", "ひら", "リボン", "ネクタイ" };

		public static void Apply(GameObject instanceRoot)
		{
			Transform[] componentsInChildren = instanceRoot.GetComponentsInChildren<Transform>(true);
			AttachDynamicBones(componentsInChildren, HairPatterns, ConfigureHair);
			AttachDynamicBones(componentsInChildren, SkirtPatterns, ConfigureSkirt);
		}

		private static void AttachDynamicBones(IEnumerable<Transform> transforms, IReadOnlyList<string> patterns, Action<DynamicBone> configure)
		{
			IReadOnlyList<string> patterns2 = patterns;
			Transform[] array = (from transform in transforms
				where transform.childCount > 0
				where ContainsPattern(((Object)transform).name, patterns2)
				where !AncestorMatches(transform, patterns2)
				select transform).ToArray();
			foreach (Transform val in array)
			{
				DynamicBone val2 = ((Component)val).gameObject.GetComponent<DynamicBone>() ?? ((Component)val).gameObject.AddComponent<DynamicBone>();
				val2.m_Root = val;
				configure(val2);
				val2.SetupParticles();
			}
		}

		private static void ConfigureHair(DynamicBone dynamicBone)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			dynamicBone.m_Damping = 0.12f;
			dynamicBone.m_Elasticity = 0.08f;
			dynamicBone.m_Stiffness = 0.12f;
			dynamicBone.m_Inert = 0.35f;
			dynamicBone.m_Friction = 0.03f;
			dynamicBone.m_Radius = 0.02f;
			dynamicBone.m_EndLength = 0.05f;
			dynamicBone.m_Gravity = new Vector3(0f, -0.12f, 0f);
			dynamicBone.m_Force = new Vector3(0f, 0f, 0.02f);
		}

		private static void ConfigureSkirt(DynamicBone dynamicBone)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			dynamicBone.m_Damping = 0.18f;
			dynamicBone.m_Elasticity = 0.04f;
			dynamicBone.m_Stiffness = 0.2f;
			dynamicBone.m_Inert = 0.22f;
			dynamicBone.m_Friction = 0.04f;
			dynamicBone.m_Radius = 0.03f;
			dynamicBone.m_EndLength = 0.03f;
			dynamicBone.m_Gravity = new Vector3(0f, -0.22f, 0f);
			dynamicBone.m_Force = Vector3.zero;
		}

		private static bool ContainsPattern(string name, IReadOnlyList<string> patterns)
		{
			string name2 = name;
			return patterns.Any((string pattern) => name2.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) >= 0);
		}

		private static bool AncestorMatches(Transform transform, IReadOnlyList<string> patterns)
		{
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				if (ContainsPattern(((Object)parent).name, patterns))
				{
					return true;
				}
				parent = parent.parent;
			}
			return false;
		}
	}
	internal sealed class MikuFacialExpressionController : MonoBehaviour
	{
		private readonly struct BlendShapeBinding
		{
			public SkinnedMeshRenderer Renderer { get; }

			public int Index { get; }

			public string Name { get; }

			public BlendShapeBinding(SkinnedMeshRenderer renderer, int index, string name)
			{
				Renderer = renderer;
				Index = index;
				Name = name;
			}
		}

		private readonly struct FacialShapeGroup
		{
			public string Key { get; }

			public string[] ExactAliases { get; }

			public string[] PartialAliases { get; }

			public FacialShapeGroup(string key, string[] exactAliases, string[] partialAliases)
			{
				Key = key;
				ExactAliases = exactAliases;
				PartialAliases = partialAliases;
			}

			public bool Matches(string rawName, string normalizedName)
			{
				for (int i = 0; i < ExactAliases.Length; i++)
				{
					string text = NormalizeName(ExactAliases[i]);
					if (string.Equals(rawName, ExactAliases[i], StringComparison.OrdinalIgnoreCase) || string.Equals(normalizedName, text, StringComparison.Ordinal) || (!string.IsNullOrWhiteSpace(text) && normalizedName.EndsWith(text, StringComparison.Ordinal)))
					{
						return true;
					}
				}
				for (int j = 0; j < PartialAliases.Length; j++)
				{
					string value = NormalizeName(PartialAliases[j]);
					if (!string.IsNullOrWhiteSpace(value) && normalizedName.IndexOf(value, StringComparison.Ordinal) >= 0)
					{
						return true;
					}
				}
				return false;
			}
		}

		private readonly struct BoneCandidate
		{
			public Transform Transform { get; }

			public int Score { get; }

			public BoneCandidate(Transform transform, int score)
			{
				Transform = transform;
				Score = score;
			}
		}

		private readonly struct BonePoseBinding
		{
			public Transform Transform { get; }

			public Vector3 ClosedLocalPosition { get; }

			public Quaternion ClosedLocalRotation { get; }

			public BonePoseBinding(Transform transform, Vector3 closedLocalPosition, Quaternion closedLocalRotation)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				Transform = transform;
				ClosedLocalPosition = closedLocalPosition;
				ClosedLocalRotation = closedLocalRotation;
			}
		}

		private const string MouthAGroupKey = "MouthA";

		private const string MouthIGroupKey = "MouthI";

		private const string MouthUGroupKey = "MouthU";

		private const string MouthEGroupKey = "MouthE";

		private const string MouthOGroupKey = "MouthO";

		private const string SmileGroupKey = "Smile";

		private static readonly string[] MouthShapePriority = new string[5] { "MouthA", "MouthI", "MouthU", "MouthE", "MouthO" };

		private static readonly FacialShapeGroup[] ManagedShapeGroups = new FacialShapeGroup[6]
		{
			new FacialShapeGroup("MouthA", new string[5] { "あ", "あ2", "a", "aa", "A" }, new string[7] { "moutha", "mouthaa", "phonemea", "visemeaa", "vaa", "jawopen", "mouthopen" }),
			new FacialShapeGroup("MouthI", new string[3] { "い", "i", "I" }, new string[4] { "mouthi", "phonemei", "visemeih", "vih" }),
			new FacialShapeGroup("MouthU", new string[3] { "う", "u", "U" }, new string[4] { "mouthu", "phonemeu", "visemeou", "vou" }),
			new FacialShapeGroup("MouthE", new string[3] { "え", "e", "E" }, new string[4] { "mouthe", "phonemee", "visemee", "ve" }),
			new FacialShapeGroup("MouthO", new string[3] { "お", "o", "O" }, new string[5] { "moutho", "phonemeo", "visemeoh", "voh", "mouthround" }),
			new FacialShapeGroup("Smile", new string[4] { "笑い", "smile", "Smile", "口角上げ" }, new string[4] { "warai", "happy", "grin", "mouthsmile" })
		};

		private static readonly string[] JawBoneTokens = new string[6] { "jaw", "chin", "顎", "あご", "下顎", "下あご" };

		private static readonly string[] LipBoneTokens = new string[5] { "mouth", "lip", "口", "くち", "唇" };

		private static readonly string[] ExcludedBoneTokens = new string[12]
		{
			"eye", "瞳", "眉", "brow", "nose", "鼻", "hair", "髪", "ear", "耳",
			"cheek", "頬"
		};

		private const float SmileWeight = 10f;

		private const float MinimumMouthWeight = 4f;

		private const float MouthWeightSmoothing = 10f;

		private const float AudioAmplitudeScale = 28f;

		private const float JawOpenAngleDegrees = 10f;

		private const float JawOpenOffsetMeters = 0.005f;

		private const float LipOpenOffsetMeters = 0.0035f;

		private const int LoggedBlendShapeNamesPerRenderer = 12;

		private readonly Dictionary<string, List<BlendShapeBinding>> _bindingsByGroupKey = new Dictionary<string, List<BlendShapeBinding>>(StringComparer.OrdinalIgnoreCase);

		private readonly List<BonePoseBinding> _jawBindings = new List<BonePoseBinding>();

		private readonly List<BonePoseBinding> _lipBindings = new List<BonePoseBinding>();

		private readonly float[] _audioSamples = new float[256];

		private AudioSource? _audioSource;

		private Animator? _animator;

		private ManualLogSource? _logger;

		private bool _initialized;

		private float _currentMouthWeight;

		private string? _lastPrimaryShapeGroupKey;

		public void Initialize(AudioSource? audioSource, Animator? animator, ManualLogSource? logger)
		{
			((Behaviour)this).enabled = true;
			_audioSource = audioSource;
			_animator = animator;
			_logger = logger;
			_bindingsByGroupKey.Clear();
			_jawBindings.Clear();
			_lipBindings.Clear();
			List<string> list = new List<string>();
			SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true);
			foreach (SkinnedMeshRenderer val in componentsInChildren)
			{
				Mesh sharedMesh = val.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null)
				{
					continue;
				}
				List<string> list2 = new List<string>(Mathf.Min(sharedMesh.blendShapeCount, 12));
				for (int j = 0; j < sharedMesh.blendShapeCount; j++)
				{
					string blendShapeName = sharedMesh.GetBlendShapeName(j);
					if (list2.Count < 12)
					{
						list2.Add(string.IsNullOrWhiteSpace(blendShapeName) ? $"#{j}" : blendShapeName);
					}
					if (!string.IsNullOrWhiteSpace(blendShapeName) && TryResolveManagedShapeGroup(blendShapeName, out string groupKey))
					{
						if (!_bindingsByGroupKey.TryGetValue(groupKey, out List<BlendShapeBinding> value))
						{
							value = new List<BlendShapeBinding>();
							_bindingsByGroupKey.Add(groupKey, value);
						}
						value.Add(new BlendShapeBinding(val, j, blendShapeName));
					}
				}
				list.Add(string.Format("{0}:{1}[{2}{3}]", ((Object)val).name, sharedMesh.blendShapeCount, string.Join(", ", list2), (sharedMesh.blendShapeCount > list2.Count) ? ", ..." : string.Empty));
			}
			DiscoverBoneBindings();
			_initialized = true;
			if (_bindingsByGroupKey.Count == 0 && _jawBindings.Count == 0 && _lipBindings.Count == 0)
			{
				((Behaviour)this).enabled = false;
				ManualLogSource? logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)("Facial expression controller disabled because no supported blendshapes or mouth bones were found on the loaded model. Skinned renderers: " + ((list.Count == 0) ? "(none)" : string.Join(" | ", list)) + "."));
				}
				return;
			}
			string text = ((_bindingsByGroupKey.Count == 0) ? "(none)" : string.Join(", ", _bindingsByGroupKey.Keys.OrderBy<string, string>((string name) => name, StringComparer.OrdinalIgnoreCase)));
			string text2 = ((_jawBindings.Count == 0) ? "(none)" : string.Join(", ", _jawBindings.Select((BonePoseBinding binding) => ((Object)binding.Transform).name)));
			string text3 = ((_lipBindings.Count == 0) ? "(none)" : string.Join(", ", _lipBindings.Select((BonePoseBinding binding) => ((Object)binding.Transform).name)));
			ManualLogSource? logger3 = _logger;
			if (logger3 != null)
			{
				logger3.LogInfo((object)("Facial expression controller initialized. blendshapeGroups=[" + text + "], jawBones=[" + text2 + "], lipBones=[" + text3 + "], skinnedRenderers=" + ((list.Count == 0) ? "(none)" : string.Join(" | ", list)) + "."));
			}
		}

		private void LateUpdate()
		{
			if (_initialized)
			{
				float num = ResolveMouthWeight();
				string text = ResolvePrimaryMouthShapeGroupKey(num);
				ResetManagedWeights();
				ApplySmileWeight();
				ApplyBoneMouthPose(num);
				if (!string.IsNullOrWhiteSpace(text) && num > 4f)
				{
					ApplyWeight(text, num);
				}
				_lastPrimaryShapeGroupKey = text;
			}
		}

		private float ResolveMouthWeight()
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			if ((Object)(object)_audioSource != (Object)null && (Object)(object)_audioSource.clip != (Object)null && _audioSource.isPlaying)
			{
				try
				{
					_audioSource.GetOutputData(_audioSamples, 0);
					float num2 = 0f;
					for (int i = 0; i < _audioSamples.Length; i++)
					{
						num2 += _audioSamples[i] * _audioSamples[i];
					}
					num = Mathf.Clamp(Mathf.Sqrt(num2 / (float)_audioSamples.Length) * 28f * 100f, 0f, 100f);
				}
				catch (Exception ex)
				{
					ManualLogSource? logger = _logger;
					if (logger != null)
					{
						logger.LogWarning((object)("Facial expression audio sampling failed: " + ex.Message));
					}
				}
			}
			else if ((Object)(object)_animator != (Object)null && (Object)(object)_animator.runtimeAnimatorController != (Object)null)
			{
				AnimatorStateInfo currentAnimatorStateInfo = _animator.GetCurrentAnimatorStateInfo(0);
				num = Mathf.Clamp01(Mathf.Sin(Mathf.Repeat(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime, 1f) * (float)Math.PI * 8f) * 0.5f + 0.5f) * 18f;
			}
			_currentMouthWeight = Mathf.Lerp(_currentMouthWeight, num, Time.deltaTime * 10f);
			return _currentMouthWeight;
		}

		private string? ResolvePrimaryMouthShapeGroupKey(float mouthWeight)
		{
			if (mouthWeight <= 4f)
			{
				return null;
			}
			float num = 0f;
			if ((Object)(object)_audioSource != (Object)null && (Object)(object)_audioSource.clip != (Object)null)
			{
				num = _audioSource.time;
			}
			else if ((Object)(object)_animator != (Object)null)
			{
				num = Time.time;
			}
			string[] array = (Mathf.Abs(Mathf.FloorToInt(num * 7f)) % 5) switch
			{
				0 => new string[2] { "MouthA", "MouthO" }, 
				1 => new string[2] { "MouthI", "MouthE" }, 
				2 => new string[2] { "MouthU", "MouthO" }, 
				3 => new string[2] { "MouthE", "MouthI" }, 
				_ => new string[2] { "MouthO", "MouthA" }, 
			};
			foreach (string text in array)
			{
				if (_bindingsByGroupKey.ContainsKey(text))
				{
					return text;
				}
			}
			array = MouthShapePriority;
			foreach (string text2 in array)
			{
				if (_bindingsByGroupKey.ContainsKey(text2))
				{
					return text2;
				}
			}
			return _lastPrimaryShapeGroupKey;
		}

		private void ResetManagedWeights()
		{
			foreach (List<BlendShapeBinding> value in _bindingsByGroupKey.Values)
			{
				foreach (BlendShapeBinding item in value)
				{
					item.Renderer.SetBlendShapeWeight(item.Index, 0f);
				}
			}
		}

		private void ApplySmileWeight()
		{
			if (_bindingsByGroupKey.ContainsKey("Smile"))
			{
				ApplyWeight("Smile", 10f);
			}
		}

		private void ApplyWeight(string groupKey, float weight)
		{
			if (_bindingsByGroupKey.TryGetValue(groupKey, out List<BlendShapeBinding> value))
			{
				for (int i = 0; i < value.Count; i++)
				{
					value[i].Renderer.SetBlendShapeWeight(value[i].Index, weight);
				}
			}
		}

		private void ApplyBoneMouthPose(float mouthWeight)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01((mouthWeight - 4f) / 96f);
			for (int i = 0; i < _jawBindings.Count; i++)
			{
				BonePoseBinding bonePoseBinding = _jawBindings[i];
				bonePoseBinding.Transform.localRotation = bonePoseBinding.ClosedLocalRotation * Quaternion.Euler(-10f * num, 0f, 0f);
				bonePoseBinding.Transform.localPosition = bonePoseBinding.ClosedLocalPosition + ResolveLocalDownDirection(bonePoseBinding.Transform) * (0.005f * num);
			}
			for (int j = 0; j < _lipBindings.Count; j++)
			{
				BonePoseBinding bonePoseBinding2 = _lipBindings[j];
				bonePoseBinding2.Transform.localRotation = bonePoseBinding2.ClosedLocalRotation;
				bonePoseBinding2.Transform.localPosition = bonePoseBinding2.ClosedLocalPosition + ResolveLocalDownDirection(bonePoseBinding2.Transform) * (0.0035f * num);
			}
		}

		private void DiscoverBoneBindings()
		{
			HashSet<Transform> hashSet = new HashSet<Transform>();
			AddTopBoneBindings(_jawBindings, JawBoneTokens, hashSet, 2);
			foreach (BonePoseBinding jawBinding in _jawBindings)
			{
				hashSet.Add(jawBinding.Transform);
			}
			AddTopBoneBindings(_lipBindings, LipBoneTokens, hashSet, 2);
		}

		private void AddTopBoneBindings(ICollection<BonePoseBinding> destination, IEnumerable<string> tokens, ISet<Transform> excludedTransforms, int maxCount)
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			ISet<Transform> excludedTransforms2 = excludedTransforms;
			IEnumerable<string> tokens2 = tokens;
			BoneCandidate[] array = (from candidate in ((Component)this).GetComponentsInChildren<Transform>(true)
				where (Object)(object)candidate != (Object)(object)((Component)this).transform
				where !excludedTransforms2.Contains(candidate)
				select new BoneCandidate(candidate, ScoreBoneCandidate(((Object)candidate).name, tokens2)) into candidate
				where candidate.Score > 0
				orderby candidate.Score descending, ((Object)candidate.Transform).name.Length
				select candidate).ThenBy<BoneCandidate, string>((BoneCandidate candidate) => ((Object)candidate.Transform).name, StringComparer.OrdinalIgnoreCase).Take(maxCount).ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				destination.Add(new BonePoseBinding(array[i].Transform, array[i].Transform.localPosition, array[i].Transform.localRotation));
			}
		}

		private static int ScoreBoneCandidate(string candidateName, IEnumerable<string> tokens)
		{
			string normalizedName = NormalizeName(candidateName);
			if (string.IsNullOrWhiteSpace(normalizedName))
			{
				return 0;
			}
			if (ExcludedBoneTokens.Any((string token) => normalizedName.IndexOf(NormalizeName(token), StringComparison.Ordinal) >= 0))
			{
				return 0;
			}
			int num = 0;
			foreach (string token in tokens)
			{
				string text = NormalizeName(token);
				if (normalizedName == text)
				{
					num = Mathf.Max(num, 300);
				}
				else if (normalizedName.EndsWith(text, StringComparison.Ordinal))
				{
					num = Mathf.Max(num, 220);
				}
				else if (normalizedName.IndexOf(text, StringComparison.Ordinal) >= 0)
				{
					num = Mathf.Max(num, 160);
				}
			}
			return num;
		}

		private static bool TryResolveManagedShapeGroup(string blendShapeName, out string groupKey)
		{
			string normalizedName = NormalizeName(blendShapeName);
			for (int i = 0; i < ManagedShapeGroups.Length; i++)
			{
				if (ManagedShapeGroups[i].Matches(blendShapeName, normalizedName))
				{
					groupKey = ManagedShapeGroups[i].Key;
					return true;
				}
			}
			groupKey = string.Empty;
			return false;
		}

		private static string NormalizeName(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return string.Empty;
			}
			char[] array = new char[value.Length];
			int num = 0;
			for (int i = 0; i < value.Length; i++)
			{
				char c = char.ToLowerInvariant(value[i]);
				if (!char.IsWhiteSpace(c) && c != '_' && c != '-' && c != '.' && c != '/' && c != '\\' && c != '(' && c != ')' && c != '[' && c != ']' && c != '・')
				{
					array[num++] = c;
				}
			}
			if (num == 0)
			{
				return string.Empty;
			}
			string text = new string(array, 0, num);
			int j;
			for (j = 0; j < text.Length && char.IsDigit(text[j]); j++)
			{
			}
			if (j <= 0 || j >= text.Length)
			{
				return text;
			}
			return text.Substring(j);
		}

		private static Vector3 ResolveLocalDownDirection(Transform transform)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)transform.parent == (Object)null)
			{
				return Vector3.down;
			}
			Vector3 val = transform.parent.InverseTransformDirection(Vector3.down);
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.0001f))
			{
				return Vector3.down;
			}
			return ((Vector3)(ref val)).normalized;
		}
	}
	internal sealed class MmdLegIkSolver : MonoBehaviour
	{
		private sealed class IkChain
		{
			public string Name { get; }

			public Transform Target { get; }

			public Transform EndEffector { get; }

			public IkLink[] Links { get; }

			public int IterationCount { get; }

			public float StepDegrees { get; }

			public Quaternion EndEffectorRotationOffset { get; }

			public IkChain(string name, Transform target, Transform endEffector, IkLink[] links, int iterationCount, float stepDegrees, Quaternion endEffectorRotationOffset)
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				Name = name;
				Target = target;
				EndEffector = endEffector;
				Links = links;
				IterationCount = iterationCount;
				StepDegrees = stepDegrees;
				EndEffectorRotationOffset = endEffectorRotationOffset;
			}
		}

		private sealed class IkLink
		{
			public Transform Transform { get; }

			public bool HasAngleLimit { get; }

			public Vector3 MinimumAngleDegrees { get; }

			public Vector3 MaximumAngleDegrees { get; }

			public IkLink(Transform transform, bool hasAngleLimit, Vector3 minimumAngleDegrees, Vector3 maximumAngleDegrees)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				Transform = transform;
				HasAngleLimit = hasAngleLimit;
				MinimumAngleDegrees = minimumAngleDegrees;
				MaximumAngleDegrees = maximumAngleDegrees;
			}
		}

		private const float TargetReachToleranceSqr = 1E-06f;

		private readonly List<IkChain> _chains = new List<IkChain>();

		private bool _isInitialized;

		public void Initialize(LoadedDancePrefab prefab, ManualLogSource logger)
		{
			if (_isInitialized)
			{
				return;
			}
			_isInitialized = true;
			_chains.Clear();
			if (prefab.Bones.Count == 0 || prefab.BonePaths.Count != prefab.Bones.Count)
			{
				logger.LogInfo((object)"PMX IK metadata is unavailable; leg solver skipped.");
				return;
			}
			Transform[] boneTransforms = ResolveBoneTransforms(prefab.BonePaths);
			for (int i = 0; i < prefab.Bones.Count; i++)
			{
				PmxBone pmxBone = prefab.Bones[i];
				if (IsLegIkBone(pmxBone.DisplayName) && pmxBone.IkDefinition != null)
				{
					TryAddIkChain(i, pmxBone, boneTransforms, logger);
				}
			}
			logger.LogInfo((object)((_chains.Count > 0) ? ("Enabled PMX leg IK solver for " + string.Join(", ", _chains.Select((IkChain chain) => chain.Name)) + ".") : "No compatible PMX leg IK chains found; leg solver skipped."));
		}

		private void LateUpdate()
		{
			if (_chains.Count == 0)
			{
				return;
			}
			foreach (IkChain chain in _chains)
			{
				SolveChain(chain);
			}
		}

		private Transform?[] ResolveBoneTransforms(IReadOnlyList<string> bonePaths)
		{
			Transform[] array = (Transform[])(object)new Transform[bonePaths.Count];
			for (int i = 0; i < bonePaths.Count; i++)
			{
				string text = bonePaths[i];
				array[i] = (string.IsNullOrWhiteSpace(text) ? ((Component)this).transform : ((Component)this).transform.Find(text));
			}
			return array;
		}

		private void TryAddIkChain(int boneIndex, PmxBone bone, Transform?[] boneTransforms, ManualLogSource logger)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			PmxIkDefinition ikDefinition = bone.IkDefinition;
			if (ikDefinition == null)
			{
				return;
			}
			if (!TryGetBoneTransform(boneTransforms, boneIndex, out Transform transform) || !TryGetBoneTransform(boneTransforms, ikDefinition.TargetBoneIndex, out Transform transform2))
			{
				logger.LogInfo((object)("Skipping leg IK chain '" + bone.DisplayName + "' because required target bones are missing."));
				return;
			}
			List<IkLink> list = new List<IkLink>(ikDefinition.Links.Count);
			foreach (PmxIkLink link in ikDefinition.Links)
			{
				if (TryGetBoneTransform(boneTransforms, link.BoneIndex, out Transform transform3))
				{
					list.Add(new IkLink(transform3, link.HasAngleLimit, ToDegrees(link.MinimumAngle), ToDegrees(link.MaximumAngle)));
				}
			}
			if (list.Count == 0)
			{
				logger.LogInfo((object)("Skipping leg IK chain '" + bone.DisplayName + "' because its link list is empty."));
				return;
			}
			float stepDegrees = ((ikDefinition.LimitRadian <= 0f) ? 180f : Mathf.Clamp(ikDefinition.LimitRadian * 57.29578f, 1f, 180f));
			_chains.Add(new IkChain(bone.DisplayName, transform, transform2, list.ToArray(), Mathf.Clamp(ikDefinition.LoopCount, 1, 32), stepDegrees, Quaternion.Inverse(transform.rotation) * transform2.rotation));
		}

		private static bool TryGetBoneTransform(Transform?[] transforms, int boneIndex, out Transform transform)
		{
			if (boneIndex >= 0 && boneIndex < transforms.Length && (Object)(object)transforms[boneIndex] != (Object)null)
			{
				transform = transforms[boneIndex];
				return true;
			}
			transform = null;
			return false;
		}

		private static bool IsLegIkBone(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			bool num = name.IndexOf("左足", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("右足", StringComparison.OrdinalIgnoreCase) >= 0;
			bool flag = name.IndexOf("IK", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("IK", StringComparison.Ordinal) >= 0;
			bool flag2 = name.IndexOf("つま先", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("toe", StringComparison.OrdinalIgnoreCase) >= 0;
			if (num && flag)
			{
				return !flag2;
			}
			return false;
		}

		private static Vector3 ToDegrees(Vector3 radians)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return radians * 57.29578f;
		}

		private static void SolveChain(IkChain chain)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < chain.IterationCount; i++)
			{
				Vector3 val = chain.Target.position - chain.EndEffector.position;
				if (((Vector3)(ref val)).sqrMagnitude <= 1E-06f)
				{
					break;
				}
				IkLink[] links = chain.Links;
				foreach (IkLink link in links)
				{
					RotateLinkTowardTarget(chain, link);
					ApplyAngleLimitIfNeeded(link);
					val = chain.Target.position - chain.EndEffector.position;
					if (((Vector3)(ref val)).sqrMagnitude <= 1E-06f)
					{
						break;
					}
				}
			}
			chain.EndEffector.rotation = chain.Target.rotation * chain.EndEffectorRotationOffset;
		}

		private static void RotateLinkTowardTarget(IkChain chain, IkLink link)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = link.Transform.position;
			Vector3 val = chain.EndEffector.position - position;
			Vector3 val2 = chain.Target.position - position;
			if (!(((Vector3)(ref val)).sqrMagnitude <= 1E-06f) && !(((Vector3)(ref val2)).sqrMagnitude <= 1E-06f))
			{
				Quaternion val3 = Quaternion.FromToRotation(val, val2);
				if (chain.StepDegrees < 179.9f)
				{
					val3 = Quaternion.RotateTowards(Quaternion.identity, val3, chain.StepDegrees);
				}
				link.Transform.rotation = val3 * link.Transform.rotation;
			}
		}

		private static void ApplyAngleLimitIfNeeded(IkLink link)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0044: 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_0056: 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_0073: 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_0098: 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)
			if (link.HasAngleLimit)
			{
				Vector3 val = NormalizeSignedEuler(link.Transform.localEulerAngles);
				val.x = Mathf.Clamp(val.x, link.MinimumAngleDegrees.x, link.MaximumAngleDegrees.x);
				val.y = Mathf.Clamp(val.y, link.MinimumAngleDegrees.y, link.MaximumAngleDegrees.y);
				val.z = Mathf.Clamp(val.z, link.MinimumAngleDegrees.z, link.MaximumAngleDegrees.z);
				link.Transform.localRotation = Quaternion.Euler(val);
			}
		}

		private static Vector3 NormalizeSignedEuler(Vector3 euler)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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)
			return new Vector3(NormalizeSignedAngle(euler.x), NormalizeSignedAngle(euler.y), NormalizeSignedAngle(euler.z));
		}

		private static float NormalizeSignedAngle(float angle)
		{
			angle %= 360f;
			if (angle > 180f)
			{
				angle -= 360f;
			}
			else if (angle < -180f)
			{
				angle += 360f;
			}
			return angle;
		}
	}
	internal static class MmdMorphRuntimeBridge
	{
		private const string AssemblySimpleName = "MMD4Mecanim";

		private const string DefaultAnimatorStateName = "Base Layer.motion_vmd";

		private static readonly string[] ModelTypeCandidates = new string[2] { "MMD4MecanimModelImpl", "MMD4MecanimModel" };

		private static readonly string[] AnimTypeCandidates = new string[2] { "MMD4MecanimModelImpl+Anim", "MMD4MecanimModel+Anim" };

		private static Assembly? _loadedAssembly;

		private static string? _loadedAssemblyPath;

		private static IntPtr _loadedNativePhysicsHandle;

		private static string? _loadedNativePhysicsPath;

		public static void TryPreloadAssembly(string assemblyPath, ManualLogSource logger)
		{
			TryResolveAssembly(assemblyPath, logger, logMissingFileAsWarning: false);
		}

		public static bool TryAttach(GameObject dancer, LoadedDancePrefab prefab, Animator? animator, AudioSource? audioSource, string assemblyPath, ManualLogSource logger)
		{
			if ((Object)(object)prefab.MmdModelFile == (Object)null || (Object)(object)prefab.MmdIndexFile == (Object)null || (Object)(object)prefab.MmdAnimFile == (Object)null)
			{
				logger.LogInfo((object)"Skipped MMD4Mecanim morph bridge because required model/index/anim bytes are unavailable.");
				return false;
			}
			if (!TryEnsureNativePhysicsLibraryLoaded(assemblyPath, logger))
			{
				return false;
			}
			Assembly assembly = TryResolveAssembly(assemblyPath, logger, logMissingFileAsWarning: true);
			if (assembly == null)
			{
				return false;
			}
			Type type2 = ResolveType(assembly, ModelTypeCandidates);
			Type type3 = ResolveType(assembly, AnimTypeCandidates);
			if (type2 == null || type3 == null)
			{
				string text = string.Join(", ", (from type in assembly.GetTypes()
					select type.FullName into name
					whe