using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using MikuDanceProject.Core; using MikuDanceProject.Runtime; using Photon.Pun; using TMPro; 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] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 sealed class RuntimeLightingMaterialSnapshot { private readonly Dictionary _colors = new Dictionary(); private RuntimeLightingMaterialSnapshot() { } public static RuntimeLightingMaterialSnapshot Capture(Material material, IEnumerable propertyNames) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) RuntimeLightingMaterialSnapshot runtimeLightingMaterialSnapshot = new RuntimeLightingMaterialSnapshot(); foreach (string propertyName in propertyNames) { if (material.HasProperty(propertyName)) { runtimeLightingMaterialSnapshot._colors[propertyName] = material.GetColor(propertyName); } } return runtimeLightingMaterialSnapshot; } public bool TryGetColor(string propertyName, out Color color) { return _colors.TryGetValue(propertyName, out color); } } 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); } } 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 DistancePauseThresholdMeters = 100f; private const float AudioMinDistanceMeters = 1f; private const float LegacyMotionTrimStartFrame = 0f; private const float LegacyMotionFrameRate = 30f; private const float AudioFadeDurationSeconds = 0.35f; private const float AudioDriftCorrectionThresholdSeconds = 0.35f; private const float AudioHardResyncThresholdSeconds = 1.25f; private const float LoopIntervalSeconds = 5f; private const float SavePlacementHoldDurationSeconds = 3f; private static readonly string[] NativeFacialClipTokens = new string[20] { "face", "facial", "expression", "morph", "blend", "blendshape", "viseme", "mouth", "lip", "eye", "brow", "smile", "blink", "表情", "脸", "口", "目", "眉", "モーフ", "フェイス" }; private static readonly string[] PreferredPivotBoneTokens = new string[12] { "hips", "pelvis", "hip", "cf_j_hips", "j_bip_c_hips", "j_bip_c_pelvis", "腰", "下半身", "骨盤", "センター", "center", "centre" }; private static readonly string[] LightingSensitiveShaderTokens = new string[6] { "lit", "toon", "mmd", "standard", "outline", "cel" }; private static readonly string[] LightingNeutralShaderTokens = new string[3] { "unlit", "sprites/default", "sprite" }; private static readonly string[] LightingSensitiveMaterialProperties = new string[12] { "_Ambient", "_IndirectLightMinColor", "_CelShadeMidPoint", "_CelShadeSoftness", "_ReceiveShadowMappingAmount", "_ShadowMapColor", "_SpecularHighlights", "_EnvironmentReflections", "_Metallic", "_Smoothness", "_Glossiness", "_SpecColor" }; private static readonly string[] RuntimeLightingExposureColorProperties = new string[5] { "_BaseColor", "_Color", "_TintColor", "_MainColor", "_LitColor" }; 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 const string WrappedModelRootName = "MikuLobbyModel"; private static readonly DancePlaybackMetadata LegacyPlaybackMetadata = DancePlaybackMetadata.CreateDefault(); private static readonly Vector3 AirportDisplayPosition = new Vector3(-16.78f, 2.55f, 64.85f); private static readonly Vector3 AirportDisplayForward = Vector3.right; 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 Animator[] _activeAnimators = Array.Empty(); private Animation? _activeAnimation; private AudioSource? _activeAudioSource; private AnimationClip? _activePrimaryAnimatorClip; private readonly List _runtimeLightingStabilizedMaterials = new List(); private readonly Dictionary _runtimeLightingMaterialSnapshots = new Dictionary(); private readonly Dictionary _originalMaterialColors = new Dictionary(); 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 _isPausedForDistance; private bool _audioPausedForPlaybackPause; private AudioSource? _fadingAudioSource; private float _audioFadeStartTime; private float _audioFadeDuration; private float _audioFadeTargetVolume; private int _animatorSegmentLoopIndex; private int _lastAnimatorLoopIndex = -1; private int _lastMorphLoopIndex = -1; private bool _isInLoopInterval; private float _loopIntervalEndTime = -1f; private GameObject? _activeShadowBlob; private bool _hasAppliedPlacementConfiguration; private float _appliedModelScale; private bool _hasResolvedPlacementPivot; private Vector3 _resolvedPlacementPivotLocalPosition; private bool _hasCachedRuntimeComponents; private GameObject? _cachedRuntimeComponentRoot; private RuntimeAnimatorController? _cachedAnimatorController; private bool _hasNativeFacialAnimationControl; private float _placementHotkeyPressedAt = -1f; private bool _placementHotkeyHoldConsumed; private KeyCode _lastObservedSpawnModelKey; private bool _pendingRuntimeLightingRefresh; private bool _lastAppliedStabilizeModelLighting; private float _lastAppliedLightingExposureCompensation = -1f; public void Initialize(DancePluginConfig config, ManualLogSource logger) { _config = config; _logger = logger; _lastAudioEnabledState = config.EnableAudio.Value; _lastAppliedStabilizeModelLighting = config.StabilizeModelLighting.Value; _lastAppliedLightingExposureCompensation = config.ResolvedLightingExposureCompensation; config.StabilizeModelLighting.SettingChanged += HandleRuntimeLightingConfigChanged; config.LightingExposureCompensation.SettingChanged += HandleRuntimeLightingConfigChanged; config.HairColorEnabled.SettingChanged += HandleColorConfigChanged; config.HairColorR.SettingChanged += HandleColorConfigChanged; config.HairColorG.SettingChanged += HandleColorConfigChanged; config.HairColorB.SettingChanged += HandleColorConfigChanged; config.ClothColorEnabled.SettingChanged += HandleColorConfigChanged; config.ClothColorR.SettingChanged += HandleColorConfigChanged; config.ClothColorG.SettingChanged += HandleColorConfigChanged; config.ClothColorB.SettingChanged += HandleColorConfigChanged; config.RandomizeColors.SettingChanged += HandleColorConfigChanged; } private void Start() { ((MonoBehaviour)this).StartCoroutine(LoadAssetsRoutine()); } private void OnDestroy() { if (_config != null) { _config.StabilizeModelLighting.SettingChanged -= HandleRuntimeLightingConfigChanged; _config.LightingExposureCompensation.SettingChanged -= HandleRuntimeLightingConfigChanged; _config.HairColorEnabled.SettingChanged -= HandleColorConfigChanged; _config.HairColorR.SettingChanged -= HandleColorConfigChanged; _config.HairColorG.SettingChanged -= HandleColorConfigChanged; _config.HairColorB.SettingChanged -= HandleColorConfigChanged; _config.ClothColorEnabled.SettingChanged -= HandleColorConfigChanged; _config.ClothColorR.SettingChanged -= HandleColorConfigChanged; _config.ClothColorG.SettingChanged -= HandleColorConfigChanged; _config.ClothColorB.SettingChanged -= HandleColorConfigChanged; _config.RandomizeColors.SettingChanged -= HandleColorConfigChanged; } DestroyActiveDancer("Dance controller destroyed."); DestroyRuntimeLightingStabilizedMaterials(); _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; ResetPlacementHotkeyState(); return; } EnsureAirportLobbyDisplay(); ProcessSpawnHotkey(); MaintainSynchronizedLoopPlayback(); UpdateActiveAudioFade(); RefreshRuntimeLightingIfConfigChanged(); if (Time.unscaledTime < _nextRefreshTime) { return; } _nextRefreshTime = Time.unscaledTime + 0.25f; if (!((Object)(object)_activeDancer == (Object)null)) { if (_hasActivePlacement && HasPlacementConfigurationChanged()) { ApplyPlacement(_activeDancer.transform, _activePlacement, _config, _loadedPrefab); UpdateShadowPresentation(_activeDancer); RecordAppliedPlacementConfiguration(); } RefreshLivePlayback(_activeDancer); } } private void LateUpdate() { if (_config != null && _logger != null) { MaintainMorphPlaybackAfterAnimator(); } } private void HandleRuntimeLightingConfigChanged(object? sender, EventArgs eventArgs) { _pendingRuntimeLightingRefresh = true; } private void HandleColorConfigChanged(object? sender, EventArgs eventArgs) { if (!((Object)(object)_activeDancer == (Object)null) && _config != null) { if (sender == _config.RandomizeColors) { _config.RefreshRandomColors(); } ReapplyAllMaterialColors(); } } private void ReapplyAllMaterialColors() { if ((Object)(object)_activeDancer == (Object)null || _config == null) { return; } Renderer[] componentsInChildren = _activeDancer.GetComponentsInChildren(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { LogVerbose($"Reapplying material colors. randomize={_config.RandomizeColors.Value} " + $"hairEnabled={_config.HairColorEnabled.Value} " + $"hair=({_config.HairColorR.Value:0.###},{_config.HairColorG.Value:0.###},{_config.HairColorB.Value:0.###}) " + $"clothEnabled={_config.ClothColorEnabled.Value} " + $"cloth=({_config.ClothColorR.Value:0.###},{_config.ClothColorG.Value:0.###},{_config.ClothColorB.Value:0.###}) " + $"renderers={componentsInChildren.Length}."); Renderer[] array = componentsInChildren; foreach (Renderer renderer in array) { ApplyLocalizedMaterialColors(renderer); } } } private IEnumerator LoadAssetsRoutine() { if (_config == null || _logger == null || _isLoading || _loadedPrefab != null) { yield break; } _isLoading = true; string text = _config.ResolveUnityBundlePath(); float realtimeSinceStartup = Time.realtimeSinceStartup; LogVerbose("Starting Unity asset bundle load. bundlePath='" + text + "'."); try { if (!File.Exists(text)) { _logger.LogError((object)("Required Unity asset bundle file was not found: '" + text + "'.")); yield break; } _loadedPrefab = _unityBundleLoader.Load(text, _logger); Object.DontDestroyOnLoad((Object)(object)_loadedPrefab.Template); LogVerbose($"Using Unity asset bundle dancer source '{text}'. loadDuration={Time.realtimeSinceStartup - realtimeSinceStartup:0.###}s."); } catch (Exception arg) { _logger.LogError((object)$"Failed to load Unity asset bundle dancer source '{text}': {arg}"); } finally { _isLoading = false; } } 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; _isPausedForDistance = false; _audioPausedForPlaybackPause = false; ResetPlacementHotkeyState(); } } 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if (_loadedPrefab == null || (Object)(object)_activeDancer != (Object)null || _hasActivePlacement) { return; } Scene activeScene = SceneManager.GetActiveScene(); if (string.Equals(((Scene)(ref activeScene)).name, "Airport", StringComparison.OrdinalIgnoreCase)) { _activePlacement = ResolveAirportLobbyPlacement(); _hasActivePlacement = true; if (EnsureDancerInstance() && !((Object)(object)_activeDancer == (Object)null)) { ApplyPlacement(_activeDancer.transform, _activePlacement, _config, _loadedPrefab); UpdateShadowPresentation(_activeDancer); RecordAppliedPlacementConfiguration(); ConfigurePlayback(_activeDancer); string text = $"Spawned default Airport display model at {_activeDancer.transform.position}. "; Quaternion rotation = _activeDancer.transform.rotation; LogVerbose(text + $"rotation={((Quaternion)(ref rotation)).eulerAngles}, scale={_activeDancer.transform.localScale}."); } } } private void ProcessSpawnHotkey() { //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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) if (_config == null || _logger == null) { return; } if (!_loggedSceneHint) { _loggedSceneHint = true; string[] obj = new string[5] { "Placement hotkey ready in scene '", null, null, null, null }; Scene activeScene = SceneManager.GetActiveScene(); obj[1] = ((Scene)(ref activeScene)).name; obj[2] = "'. "; obj[3] = $"Tap {_config.SpawnModelKey.Value} to spawn or move the model to the local player's ground position. "; obj[4] = $"Hold it for {3f:0.#} seconds in Airport to save the lobby showcase position into the config file for future launches."; LogVerbose(string.Concat(obj)); } KeyCode value = _config.SpawnModelKey.Value; if (value != _lastObservedSpawnModelKey) { ResetPlacementHotkeyState(); _lastObservedSpawnModelKey = value; LogVerbose($"Updated placement hotkey binding to '{value}'. Tap/hold behavior now follows this key."); } if ((int)value == 0) { ResetPlacementHotkeyState(); return; } if (Input.GetKeyDown(value)) { _placementHotkeyPressedAt = Time.unscaledTime; _placementHotkeyHoldConsumed = false; } if (Input.GetKey(value)) { if (!_placementHotkeyHoldConsumed && _placementHotkeyPressedAt >= 0f && Time.unscaledTime - _placementHotkeyPressedAt >= 3f) { _placementHotkeyHoldConsumed = true; SaveCurrentAirportDisplayPlacement(); } } else if (Input.GetKeyUp(value)) { bool num = !_placementHotkeyHoldConsumed; ResetPlacementHotkeyState(); if (num) { SpawnOrMoveToCurrentPlayer(); } } } private void SpawnOrMoveToCurrentPlayer() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) if (_config == null || _logger == null) { return; } if (_loadedPrefab == null) { if (!_isLoading) { ((MonoBehaviour)this).StartCoroutine(LoadAssetsRoutine()); } _logger.LogWarning((object)(_isLoading ? "The Unity asset bundle is still loading. Try the placement hotkey again in a moment." : "The model resources are loading now. Press the placement hotkey again in a moment.")); 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) { return; } ApplyPlacement(_activeDancer.transform, _activePlacement, _config, _loadedPrefab); UpdateShadowPresentation(_activeDancer); RecordAppliedPlacementConfiguration(); if (flag) { ConfigurePlayback(_activeDancer); } else { RefreshLivePlayback(_activeDancer); if (_config != null && _config.RandomizeColors.Value) { _config.RefreshRandomColors(); ReapplyAllMaterialColors(); } } 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}."; LogVerbose(string.Concat(obj)); } private void SaveCurrentAirportDisplayPlacement() { //IL_0011: 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_0042: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if (_config == null || _logger == null) { return; } Scene activeScene = SceneManager.GetActiveScene(); if (!string.Equals(((Scene)(ref activeScene)).name, "Airport", StringComparison.OrdinalIgnoreCase)) { _logger.LogWarning((object)$"Hold {_config.SpawnModelKey.Value} for {3f:0.#} seconds only in the Airport lobby to save the lobby showcase position."); 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 Airport showcase position could not be saved."); return; } Vector3 forward2 = ResolveFacingDirection(forward); PlacementPose activePlacement = CreatePlayerGroundLockedPlacement(position, forward2, source + ".SavedAirportDisplay", ignoredRoot); _config.SaveAirportPlacement(activePlacement.Position, activePlacement.Forward); _activePlacement = activePlacement; _hasActivePlacement = true; bool flag = EnsureDancerInstance(); if ((Object)(object)_activeDancer != (Object)null) { ApplyPlacement(_activeDancer.transform, _activePlacement, _config, _loadedPrefab); UpdateShadowPresentation(_activeDancer); RecordAppliedPlacementConfiguration(); if (flag) { ConfigurePlayback(_activeDancer); } else { RefreshLivePlayback(_activeDancer); } } _logger.LogInfo((object)($"Saved Airport showcase placement to config. source={source}, groundedPosition={activePlacement.Position}, " + $"forward={activePlacement.Forward}, createdNow={flag}.")); } private bool EnsureDancerInstance() { if ((Object)(object)_activeDancer != (Object)null || _loadedPrefab == null) { return false; } _activeDancer = Object.Instantiate(_loadedPrefab.Template); ((Object)_activeDancer).name = "MikuDanceDisplay"; RemoveAllColliders(_activeDancer); ResetAudioPlaybackState(); ClearResolvedPlacementPivot(); CacheActiveRuntimeComponents(_activeDancer); LogVerbose("Using embedded Animator playback for '" + ((Object)_activeDancer).name + "'. " + $"preBakedMorphClipAvailable={(Object)(object)_loadedPrefab.MorphClip != (Object)null}."); 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; _activeShadowBlob = null; DestroyRuntimeLightingStabilizedMaterials(); _originalMaterialColors.Clear(); ClearAppliedPlacementConfiguration(); ClearResolvedPlacementPivot(); ClearActiveRuntimeComponents(); ResetAudioPlaybackState(); LogVerbose(reason); } } private void ApplyPlacement(Transform dancerTransform, PlacementPose placement, DancePluginConfig config, LoadedDancePrefab? prefab) { //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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) float resolvedModelScale = config.ResolvedModelScale; Quaternion val = Quaternion.LookRotation(ResolveFacingDirection(placement.Forward), Vector3.up); Vector3 val2 = ResolvePlacementPivotLocalPosition(dancerTransform, prefab) * resolvedModelScale; dancerTransform.localScale = Vector3.one * resolvedModelScale; dancerTransform.rotation = val; dancerTransform.position = placement.Position - val * val2; } private Vector3 ResolvePlacementPivotLocalPosition(Transform dancerTransform, LoadedDancePrefab? prefab) { //IL_0009: 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) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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) if (_hasResolvedPlacementPivot) { return _resolvedPlacementPivotLocalPosition; } float num = prefab?.LocalMinY ?? 0f; if (TryResolvePlacementPivotFromAnimator(dancerTransform, num, out var pivotLocalPosition)) { _resolvedPlacementPivotLocalPosition = pivotLocalPosition; _hasResolvedPlacementPivot = true; return pivotLocalPosition; } if (TryResolvePlacementPivotFromNamedBone(dancerTransform, num, out var pivotLocalPosition2)) { _resolvedPlacementPivotLocalPosition = pivotLocalPosition2; _hasResolvedPlacementPivot = true; return pivotLocalPosition2; } Vector3 result = (_resolvedPlacementPivotLocalPosition = ((prefab == null) ? new Vector3(0f, num, 0f) : new Vector3(prefab.LocalBoundsCenter.x, num, prefab.LocalBoundsCenter.z))); _hasResolvedPlacementPivot = true; return result; } 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 PlacementPose ResolveAirportLobbyPlacement() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) if (_config != null && _config.TryGetSavedAirportPlacement(out var position, out var forward)) { return CreateGroundLockedPlacement(position, forward, "AirportLobbyDisplay.Saved"); } return CreateGroundLockedPlacement(AirportDisplayPosition, AirportDisplayForward, "AirportLobbyDisplay.Default"); } private bool HasPlacementConfigurationChanged() { if (_config == null) { return false; } if (!_hasAppliedPlacementConfiguration) { return true; } return Mathf.Abs(_appliedModelScale - _config.ResolvedModelScale) > 0.0001f; } private void RecordAppliedPlacementConfiguration() { if (_config == null) { ClearAppliedPlacementConfiguration(); return; } _hasAppliedPlacementConfiguration = true; _appliedModelScale = _config.ResolvedModelScale; } private void ClearAppliedPlacementConfiguration() { _hasAppliedPlacementConfiguration = false; _appliedModelScale = 0f; } private void ClearResolvedPlacementPivot() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) _hasResolvedPlacementPivot = false; _resolvedPlacementPivotLocalPosition = Vector3.zero; } private void ResetPlacementHotkeyState() { _placementHotkeyPressedAt = -1f; _placementHotkeyHoldConsumed = false; } private bool TryResolvePlacementPivotFromAnimator(Transform dancerTransform, float pivotY, out Vector3 pivotLocalPosition) { //IL_006d: 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) Animator componentInChildren = ((Component)dancerTransform).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.isHuman) { try { Transform boneTransform = componentInChildren.GetBoneTransform((HumanBodyBones)0); if (TryBuildPlacementPivotFromBone(dancerTransform, boneTransform, pivotY, out pivotLocalPosition)) { LogVerbose($"Resolved placement pivot from humanoid hips bone '{((Object)boneTransform).name}' at local {pivotLocalPosition}."); return true; } } catch (Exception ex) { LogVerbose("Failed to resolve humanoid hips pivot: " + ex.Message); } } pivotLocalPosition = default(Vector3); return false; } private bool TryResolvePlacementPivotFromNamedBone(Transform dancerTransform, float pivotY, out Vector3 pivotLocalPosition) { //IL_0083: 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) Transform[] componentsInChildren = ((Component)dancerTransform).GetComponentsInChildren(true); Transform val = null; int num = int.MinValue; Transform[] array = componentsInChildren; foreach (Transform val2 in array) { if (!((Object)(object)val2 == (Object)null) && val2 != dancerTransform) { int num2 = ScorePlacementPivotCandidate(((Object)val2).name); if (num2 > num) { num = num2; val = val2; } } } if ((Object)(object)val != (Object)null && TryBuildPlacementPivotFromBone(dancerTransform, val, pivotY, out pivotLocalPosition)) { LogVerbose($"Resolved placement pivot from named bone '{((Object)val).name}' at local {pivotLocalPosition}."); return true; } pivotLocalPosition = default(Vector3); return false; } private static bool TryBuildPlacementPivotFromBone(Transform dancerTransform, Transform? pivotBone, float pivotY, out Vector3 pivotLocalPosition) { //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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pivotBone == (Object)null) { pivotLocalPosition = default(Vector3); return false; } Vector3 val = dancerTransform.InverseTransformPoint(pivotBone.position); pivotLocalPosition = new Vector3(val.x, pivotY, val.z); return true; } private static int ScorePlacementPivotCandidate(string? name) { if (string.IsNullOrWhiteSpace(name)) { return int.MinValue; } string text = (name ?? string.Empty).Trim().ToLowerInvariant(); int num = int.MinValue; for (int i = 0; i < PreferredPivotBoneTokens.Length; i++) { string text2 = PreferredPivotBoneTokens[i]; if (string.Equals(text, text2, StringComparison.Ordinal)) { return 1000 - i; } if (text.IndexOf(text2, StringComparison.Ordinal) >= 0) { num = Mathf.Max(num, 500 - i); } } return num; } 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) 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, ignoredRoot) 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) 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, ignoredRoot) 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_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 = ResolvePreferredPlayerForward(transform, position, out string source2); resolvedSource = resolvedSource + "." + source2; 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(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 list = new List(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 static bool TryExtractTransform(object? source, out Transform transform) { transform = null; Object val = (Object)((source is Object) ? source : null); if (val != null && val == (Object)null) { return false; } try { Transform val2 = (Transform)((source is Transform) ? source : null); if (val2 == null) { Component val3 = (Component)((source is Component) ? source : null); if (val3 == null) { GameObject val4 = (GameObject)((source is GameObject) ? source : null); if (val4 != null) { if ((Object)(object)val4 == (Object)null) { return false; } transform = val4.transform; return (Object)(object)transform != (Object)null; } return false; } if ((Object)(object)val3 == (Object)null) { return false; } transform = val3.transform; return (Object)(object)transform != (Object)null; } transform = val2; return (Object)(object)val2 != (Object)null; } catch (MissingReferenceException) { transform = null; return false; } catch (NullReferenceException) { transform = null; return false; } } 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 Vector3 ResolvePreferredPlayerForward(Transform playerRoot, Vector3 playerPosition, out string source) { //IL_0000: 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_000f: Unknown result type (might be due to invalid IL or missing references) if (TryResolveCameraPlanarForward(playerPosition, out Vector3 forward, out string source2)) { source = source2; return forward; } source = "TransformForward"; return ResolvePlanarForward(playerRoot); } private static bool TryResolveCameraPlanarForward(Vector3 playerPosition, out Vector3 forward, out string source) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) source = string.Empty; forward = Vector3.zero; Camera main = Camera.main; if (IsUsableGameplayCamera(main)) { Vector3 val = Vector3.ProjectOnPlane(((Component)main).transform.forward, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude > 0.01f) { forward = ((Vector3)(ref val)).normalized; source = "Camera:" + ((Object)main).name; return true; } } Camera val2 = null; float num = float.PositiveInfinity; Camera[] allCameras = Camera.allCameras; foreach (Camera val3 in allCameras) { if (!IsUsableGameplayCamera(val3)) { continue; } Vector3 val4 = Vector3.ProjectOnPlane(((Component)val3).transform.forward, Vector3.up); if (!(((Vector3)(ref val4)).sqrMagnitude <= 0.01f)) { float num2 = Vector3.Distance(((Component)val3).transform.position, playerPosition); if (!(num2 >= num)) { num = num2; val2 = val3; } } } if ((Object)(object)val2 == (Object)null) { return false; } Vector3 val5 = Vector3.ProjectOnPlane(((Component)val2).transform.forward, Vector3.up); forward = ((Vector3)(ref val5)).normalized; source = "Camera:" + ((Object)val2).name; return true; } private static bool IsUsableGameplayCamera(Camera? camera) { if ((Object)(object)camera != (Object)null && ((Behaviour)camera).enabled && ((Component)camera).gameObject.activeInHierarchy) { return !camera.orthographic; } return false; } 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(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } } private void NormalizeRendererMaterials(GameObject root) { //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) if (_logger == null) { return; } _config?.RefreshRandomColors(); bool flag = _config?.StabilizeModelLighting.Value ?? true; float num = _config?.ResolvedLightingExposureCompensation ?? 0.82f; Dictionary materialCache = new Dictionary(); int num2 = 0; Renderer[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { val.enabled = true; val.shadowCastingMode = (ShadowCastingMode)1; val.receiveShadows = false; val.allowOcclusionWhenDynamic = true; val.lightProbeUsage = (LightProbeUsage)0; val.reflectionProbeUsage = (ReflectionProbeUsage)0; int expectedMaterialCount = GetExpectedMaterialCount(val); if (expectedMaterialCount > 0) { Material[] array = val.sharedMaterials ?? Array.Empty(); if (array.Length != expectedMaterialCount || array.Any((Material material) => (Object)(object)material == (Object)null)) { val.sharedMaterials = BuildNormalizedRendererMaterialArray(array, expectedMaterialCount); LogVerbose($"Normalized runtime materials for '{((Object)val).name}'. subMeshes={expectedMaterialCount}, materials={val.sharedMaterials.Length}."); } } if (flag && TryBuildLightingStabilizedMaterialArray(val, val.sharedMaterials ?? Array.Empty(), materialCache, _runtimeLightingStabilizedMaterials, _runtimeLightingMaterialSnapshots, num, out Material[] stabilizedMaterials, out int newStabilizedMaterialCount)) { val.sharedMaterials = stabilizedMaterials; num2 += newStabilizedMaterialCount; } EnableShadowSupport(val.sharedMaterials); ApplyLocalizedMaterialColors(val); SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); if (val2 != null) { val2.updateWhenOffscreen = true; if ((Object)(object)val2.sharedMesh != (Object)null) { Bounds bounds = val2.sharedMesh.bounds; ((Bounds)(ref bounds)).Expand(0.5f); ((Renderer)val2).localBounds = bounds; } } } if (num2 > 0) { LogVerbose($"Applied runtime lighting stabilization to {num2} material(s). " + $"exposureCompensation={num:0.###}."); } RecordAppliedRuntimeLightingConfiguration(flag, num); } private void ApplyLocalizedMaterialColors(Renderer renderer) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)renderer == (Object)null) { return; } Color color = Color.white; Color color2 = Color.white; bool flag = _config != null && _config.TryResolveHairColor(out color); bool flag2 = _config != null && _config.TryResolveClothColor(out color2); if (!flag && !flag2 && _originalMaterialColors.Count == 0) { return; } Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return; } bool flag3 = false; Material[] array = sharedMaterials; foreach (Material val in array) { if (!((Object)(object)val == (Object)null)) { string normalizedName = NormalizeMaterialName(((Object)val).name, ((Object)renderer).name); if (IsHairMaterialName(normalizedName) || IsClothMaterialName(normalizedName)) { flag3 = true; break; } } } if (!flag3) { if (!VerboseLogState.Enabled) { return; } ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)$"No material matched on '{((Object)renderer).name}' ({sharedMaterials.Length} materials). Listing all:"); } for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null)) { ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogInfo((object)$" [{j}] '{((Object)sharedMaterials[j]).name}'"); } } } return; } Material[] sharedMaterials2 = renderer.sharedMaterials; Material[] materials = renderer.materials; int num = 0; int num2 = 0; array = materials; foreach (Material val2 in array) { if ((Object)(object)val2 == (Object)null) { continue; } string normalizedName2 = NormalizeMaterialName(((Object)val2).name, ((Object)renderer).name); bool flag4 = IsHairMaterialName(normalizedName2); bool flag5 = IsClothMaterialName(normalizedName2); if (!flag4 && !flag5) { continue; } if (!_originalMaterialColors.ContainsKey(val2)) { _originalMaterialColors[val2] = ReadMaterialColor(val2); } Color color3 = _originalMaterialColors[val2]; if (flag4) { if (flag) { SetMaterialColor(val2, color); num++; } else { SetMaterialColor(val2, color3); num2++; } } else if (flag2) { SetMaterialColor(val2, color2); num++; } else { SetMaterialColor(val2, color3); num2++; } } renderer.sharedMaterials = materials; MigrateStabilizedMaterialReferences(sharedMaterials2, materials); if (num > 0 || num2 > 0) { LogVerbose($"Applied localized material colors on '{((Object)renderer).name}'. applied={num} restored={num2} " + $"hair={(object)(Color)(flag ? color : default(Color))} cloth={(object)(Color)(flag2 ? color2 : default(Color))}."); } if (!VerboseLogState.Enabled) { return; } for (int k = 0; k < materials.Length; k++) { if (!((Object)(object)materials[k] == (Object)null)) { string normalizedName3 = NormalizeMaterialName(((Object)materials[k]).name, ((Object)renderer).name); bool flag6 = IsHairMaterialName(normalizedName3); bool flag7 = IsClothMaterialName(normalizedName3); string arg = (flag6 ? (flag ? "HAIR" : "HAIR(off,restored)") : ((!flag7) ? "SKIP" : (flag2 ? "CLOTH" : "CLOTH(off,restored)"))); ManualLogSource? logger3 = _logger; if (logger3 != null) { logger3.LogInfo((object)$" [{k}] '{((Object)materials[k]).name}' -> {arg}"); } } } } private static Color ReadMaterialColor(Material material) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty("_BaseColor")) { return material.GetColor("_BaseColor"); } if (material.HasProperty("_Color")) { return material.GetColor("_Color"); } return Color.white; } private void MigrateStabilizedMaterialReferences(Material[] beforeMaterials, Material[] afterMaterials) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (beforeMaterials == null || afterMaterials == null || _runtimeLightingStabilizedMaterials.Count == 0) { return; } int num = Mathf.Min(beforeMaterials.Length, afterMaterials.Length); for (int i = 0; i < num; i++) { Material val = beforeMaterials[i]; Material val2 = afterMaterials[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && val != val2) { if (_runtimeLightingMaterialSnapshots.TryGetValue(val, out RuntimeLightingMaterialSnapshot value)) { _runtimeLightingStabilizedMaterials.Remove(val); _runtimeLightingStabilizedMaterials.Add(val2); _runtimeLightingMaterialSnapshots[val2] = value; _runtimeLightingMaterialSnapshots.Remove(val); } if (_originalMaterialColors.TryGetValue(val, out var value2)) { _originalMaterialColors[val2] = value2; _originalMaterialColors.Remove(val); } } } } private static string NormalizeMaterialName(string materialName, string rendererName) { string text = (materialName ?? string.Empty) + "|" + (rendererName ?? string.Empty); int num = text.IndexOf("_Runtime", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num) + text.Substring(num + "_Runtime".Length); } return text; } private static bool IsHairMaterialName(string normalizedName) { if (normalizedName.IndexOf("Hair", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("Tails", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("TailS", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("头发", StringComparison.Ordinal) < 0 && normalizedName.IndexOf("前髪", StringComparison.Ordinal) < 0 && normalizedName.IndexOf("後髪", StringComparison.Ordinal) < 0) { return normalizedName.IndexOf("後ろ髪", StringComparison.Ordinal) >= 0; } return true; } private static bool IsClothMaterialName(string normalizedName) { if (normalizedName.IndexOf("Cloth", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("Dress", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("Shirt", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("服装", StringComparison.Ordinal) < 0 && normalizedName.IndexOf("衣服", StringComparison.Ordinal) < 0 && normalizedName.IndexOf("上着", StringComparison.Ordinal) < 0 && normalizedName.IndexOf("Skirt", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("裙子", StringComparison.Ordinal) < 0 && normalizedName.IndexOf("Sock_", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("Bow_", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("Frill_", StringComparison.OrdinalIgnoreCase) < 0 && normalizedName.IndexOf("Buttons_", StringComparison.OrdinalIgnoreCase) < 0) { return normalizedName.IndexOf("Ribbon", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static void SetMaterialColor(Material material, Color color) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", color); } if (material.HasProperty("_Color")) { material.SetColor("_Color", color); } } private static Material[] BuildNormalizedRendererMaterialArray(Material[] sharedMaterials, int expectedCount) { Material[] array = (Material[])(object)new Material[Mathf.Max(1, expectedCount)]; Material val = ((IEnumerable)sharedMaterials).FirstOrDefault((Func)((Material material) => (Object)(object)material != (Object)null)) ?? CreateFallbackRendererMaterial(); for (int num = 0; num < array.Length; num++) { Material val2 = ((num < sharedMaterials.Length) ? sharedMaterials[num] : null); if ((Object)(object)val2 != (Object)null) { array[num] = val2; val = val2; } else { array[num] = val; } } return array; } private static bool TryBuildLightingStabilizedMaterialArray(Renderer renderer, Material[] sharedMaterials, Dictionary materialCache, List runtimeMaterials, Dictionary runtimeMaterialSnapshots, float exposureCompensation, out Material[] stabilizedMaterials, out int newStabilizedMaterialCount) { stabilizedMaterials = sharedMaterials; newStabilizedMaterialCount = 0; if ((Object)(object)renderer == (Object)null || sharedMaterials == null || sharedMaterials.Length == 0) { return false; } Material[] array = null; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if (!((Object)(object)val == (Object)null) && IsLightingSensitiveMaterial(val)) { if (!materialCache.TryGetValue(val, out Material value)) { value = (materialCache[val] = CreateLightingStabilizedMaterial(val, exposureCompensation, out RuntimeLightingMaterialSnapshot snapshot)); runtimeMaterials.Add(value); runtimeMaterialSnapshots[value] = snapshot; newStabilizedMaterialCount++; } if (array == null) { array = (Material[])sharedMaterials.Clone(); } array[i] = value; } } if (array == null) { return false; } stabilizedMaterials = array; return true; } private static bool IsLightingSensitiveMaterial(Material material) { if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return false; } string text = ((Object)material.shader).name ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { return HasAnyMaterialProperty(material, LightingSensitiveMaterialProperties); } string lowerShaderName = text.ToLowerInvariant(); if (LightingNeutralShaderTokens.Any((string token) => lowerShaderName.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0) && !lowerShaderName.Contains("toon")) { return false; } if (!LightingSensitiveShaderTokens.Any((string token) => lowerShaderName.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0)) { return HasAnyMaterialProperty(material, LightingSensitiveMaterialProperties); } return true; } private static bool IsSkinMaterialName(string materialName) { string text = materialName ?? string.Empty; if (text.IndexOf("Skin", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("皮肤", StringComparison.Ordinal) >= 0; } return true; } private static bool IsExposureAffectedMaterialName(string materialName) { string text = materialName ?? string.Empty; if (text.IndexOf("Skin", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("皮肤", StringComparison.Ordinal) < 0 && text.IndexOf("Face", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("脸", StringComparison.Ordinal) < 0 && text.IndexOf("Neck", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("脖子", StringComparison.Ordinal) < 0 && text.IndexOf("Jaw", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("下巴", StringComparison.Ordinal) >= 0; } return true; } private static Material CreateLightingStabilizedMaterial(Material sourceMaterial, float exposureCompensation, out RuntimeLightingMaterialSnapshot snapshot) { //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_0031: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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) Material val = new Material(sourceMaterial) { name = (string.IsNullOrWhiteSpace(((Object)sourceMaterial).name) ? "MikuLightSafeMaterial" : (((Object)sourceMaterial).name + "_LightSafe")) }; float exposure = Mathf.Clamp(exposureCompensation, 0.4f, 1f); snapshot = RuntimeLightingMaterialSnapshot.Capture(val, RuntimeLightingExposureColorProperties); if (IsExposureAffectedMaterialName(((Object)sourceMaterial).name)) { ApplyLightingExposure(val, snapshot, exposure); } ClampColorPropertyMax(val, "_Ambient", 0.22f); ClampColorPropertyMax(val, "_IndirectLightMinColor", 0.06f); ClampColorPropertyMax(val, "_SpecColor", 0.18f); ClampColorPropertyMax(val, "_EmissionColor", 0.45f); SetFloatIfPresent(val, "_Metallic", 0f); ClampFloatPropertyMax(val, "_Smoothness", 0.18f); ClampFloatPropertyMax(val, "_Glossiness", 0.18f); SetFloatIfPresent(val, "_SpecularHighlights", 0f); SetFloatIfPresent(val, "_EnvironmentReflections", 0f); SetFloatIfPresent(val, "_ReceiveShadowMappingAmount", 0.9f); ClampFloatPropertyMin(val, "_ShadowLum", 1.35f); if (IsSkinMaterialName(((Object)sourceMaterial).name)) { SetFloatIfPresent(val, "_Smoothness", 0f); SetFloatIfPresent(val, "_Glossiness", 0f); SetFloatIfPresent(val, "_OcclusionStrength", 0f); } if (val.HasProperty("_ToonTone")) { Vector4 vector = val.GetVector("_ToonTone"); vector.y = Mathf.Min(vector.y, 0.42f); vector.z = Mathf.Min(vector.z, 0.45f); val.SetVector("_ToonTone", vector); } if (val.HasProperty("_SphereMapMode") && val.GetFloat("_SphereMapMode") > 1.5f) { val.SetFloat("_SphereMapMode", 1f); } val.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)4; return val; } private void RefreshRuntimeLightingIfConfigChanged() { if (_config == null) { return; } bool value = _config.StabilizeModelLighting.Value; float resolvedLightingExposureCompensation = _config.ResolvedLightingExposureCompensation; if (!_pendingRuntimeLightingRefresh && _lastAppliedStabilizeModelLighting == value && Mathf.Approximately(_lastAppliedLightingExposureCompensation, resolvedLightingExposureCompensation)) { return; } _pendingRuntimeLightingRefresh = false; if ((Object)(object)_activeDancer == (Object)null) { RecordAppliedRuntimeLightingConfiguration(value, resolvedLightingExposureCompensation); return; } if (value) { if (_runtimeLightingStabilizedMaterials.Count == 0) { NormalizeRendererMaterials(_activeDancer); LogVerbose("Runtime lighting stabilization enabled from config without respawning model. " + $"exposureCompensation={resolvedLightingExposureCompensation:0.###}."); return; } ApplyRuntimeLightingExposure(resolvedLightingExposureCompensation); ReapplyAllMaterialColors(); } else { ApplyRuntimeLightingExposure(1f); ReapplyAllMaterialColors(); } RecordAppliedRuntimeLightingConfiguration(value, resolvedLightingExposureCompensation); LogVerbose($"Applied live runtime lighting config. stabilizeLighting={value}, " + $"exposureCompensation={resolvedLightingExposureCompensation:0.###}, activeMaterials={_runtimeLightingStabilizedMaterials.Count}."); } private void ApplyRuntimeLightingExposure(float exposureCompensation) { float exposure = Mathf.Clamp(exposureCompensation, 0.4f, 1f); foreach (Material runtimeLightingStabilizedMaterial in _runtimeLightingStabilizedMaterials) { if (!((Object)(object)runtimeLightingStabilizedMaterial == (Object)null) && _runtimeLightingMaterialSnapshots.TryGetValue(runtimeLightingStabilizedMaterial, out RuntimeLightingMaterialSnapshot value) && IsExposureAffectedMaterialName(((Object)runtimeLightingStabilizedMaterial).name)) { ApplyLightingExposure(runtimeLightingStabilizedMaterial, value, exposure); } } } private static void ApplyLightingExposure(Material material, RuntimeLightingMaterialSnapshot snapshot, float exposure) { //IL_0024: 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_003e: 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_0051: Unknown result type (might be due to invalid IL or missing references) string[] runtimeLightingExposureColorProperties = RuntimeLightingExposureColorProperties; foreach (string text in runtimeLightingExposureColorProperties) { if (material.HasProperty(text) && snapshot.TryGetColor(text, out var color)) { material.SetColor(text, new Color(Mathf.Clamp01(color.r * exposure), Mathf.Clamp01(color.g * exposure), Mathf.Clamp01(color.b * exposure), color.a)); } } } private void RecordAppliedRuntimeLightingConfiguration(bool stabilizeLighting, float exposureCompensation) { _lastAppliedStabilizeModelLighting = stabilizeLighting; _lastAppliedLightingExposureCompensation = Mathf.Clamp(exposureCompensation, 0.4f, 1f); } private static bool HasAnyMaterialProperty(Material material, IEnumerable propertyNames) { return propertyNames.Any((Func)material.HasProperty); } private static void ClampColorPropertyMax(Material material, string propertyName, float maxChannel) { //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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_0046: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty(propertyName)) { maxChannel = Mathf.Clamp01(maxChannel); Color color = material.GetColor(propertyName); material.SetColor(propertyName, new Color(Mathf.Min(color.r, maxChannel), Mathf.Min(color.g, maxChannel), Mathf.Min(color.b, maxChannel), color.a)); } } private static void SetFloatIfPresent(Material material, string propertyName, float value) { if (material.HasProperty(propertyName)) { material.SetFloat(propertyName, value); } } private static void ClampFloatPropertyMax(Material material, string propertyName, float maxValue) { if (material.HasProperty(propertyName)) { material.SetFloat(propertyName, Mathf.Min(material.GetFloat(propertyName), maxValue)); } } private static void ClampFloatPropertyMin(Material material, string propertyName, float minValue) { if (material.HasProperty(propertyName)) { material.SetFloat(propertyName, Mathf.Max(material.GetFloat(propertyName), minValue)); } } private static Material CreateFallbackRendererMaterial() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown Shader val = Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Texture") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Legacy Shaders/Diffuse"); if (!((Object)(object)val != (Object)null)) { return null; } return new Material(val); } private void DestroyRuntimeLightingStabilizedMaterials() { if (_runtimeLightingStabilizedMaterials.Count == 0) { _runtimeLightingMaterialSnapshots.Clear(); return; } for (int i = 0; i < _runtimeLightingStabilizedMaterials.Count; i++) { Material val = _runtimeLightingStabilizedMaterials[i]; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } _runtimeLightingStabilizedMaterials.Clear(); _runtimeLightingMaterialSnapshots.Clear(); } private static int GetExpectedMaterialCount(Renderer renderer) { SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (val != null && (Object)(object)val.sharedMesh != (Object)null) { return Mathf.Max(1, val.sharedMesh.subMeshCount); } MeshFilter val2 = default(MeshFilter); if (((Component)renderer).TryGetComponent(ref val2) && (Object)(object)val2.sharedMesh != (Object)null) { return Mathf.Max(1, val2.sharedMesh.subMeshCount); } Material[] sharedMaterials = renderer.sharedMaterials; return Mathf.Max(1, (sharedMaterials != null) ? sharedMaterials.Length : 0); } private void UpdateShadowPresentation(GameObject root) { Renderer[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)_activeShadowBlob != (Object)null) || !((Object)(object)((Component)val).gameObject == (Object)(object)_activeShadowBlob)) { val.enabled = true; val.shadowCastingMode = (ShadowCastingMode)1; val.receiveShadows = false; val.allowOcclusionWhenDynamic = true; val.lightProbeUsage = (LightProbeUsage)0; val.reflectionProbeUsage = (ReflectionProbeUsage)0; EnableShadowSupport(val.sharedMaterials); } } DestroyActiveShadowBlob(); } private void DestroyActiveShadowBlob() { if (!((Object)(object)_activeShadowBlob == (Object)null)) { LogVerbose("Destroying shadow blob '" + ((Object)_activeShadowBlob).name + "' (replaced by Unity standard shadows)."); Object.Destroy((Object)(object)_activeShadowBlob); _activeShadowBlob = null; } } private static void EnableShadowSupport(Material[]? materials) { if (materials != null) { for (int i = 0; i < materials.Length; i++) { EnableShadowSupport(materials[i]); } } } private static void EnableShadowSupport(Material? material) { if (!((Object)(object)material == (Object)null)) { if (material.HasProperty("_ReceiveShadows")) { material.SetFloat("_ReceiveShadows", 1f); } if (material.HasProperty("_CastShadows")) { material.SetFloat("_CastShadows", 1f); } material.SetShaderPassEnabled("ShadowCaster", true); } } 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 val2 = ResolveSynchronizedAnimatorClip(activeAnimator); float num = ResolveSynchronizedAnimatorSpeed(val2, val); bool num2 = HasNativeFacialAnimationControl(dancer); activeAnimator.cullingMode = (AnimatorCullingMode)0; activeAnimator.applyRootMotion = false; activeAnimator.updateMode = (AnimatorUpdateMode)0; activeAnimator.speed = num; activeAnimator.Rebind(); activeAnimator.Update(0f); StartAnimatorAtBeginning(activeAnimator, val2); if (num2) { StopRuntimeMorphPlayback(); } else { StartMorphPlayback(dancer); } ConfigureSecondaryNativeAnimators(val2, num); ApplyActiveAnimationPlaybackSpeed(val); bool flag = (Object)(object)activeAudioSource != (Object)null && (Object)(object)val != (Object)null && SynchronizeAudioWithAnimator(activeAnimator, activeAudioSource, val, val2, startIfNeeded: true, allowFadeOnStart: true, suppressFurtherRetries: true, logCorrections: false); 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.###}, ", ((val2 != null) ? ((Object)val2).name : null) ?? "(none)", (val2 != null) ? val2.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(val2, val):0.###}, audioSegmentLength={ResolveAudioSegmentDuration(val2, val):0.###}, "; obj[10] = $"animatorSpeed={num:0.###}, audioVolume={_config?.ResolvedAudioVolume ?? 0f:0.###}, audioRange={_config?.ResolvedAudioRangeMeters ?? 0f:0.###}, audioStarted={flag}, audioIsPlaying={activeAudioSource != null && activeAudioSource.isPlaying}."; LogVerbose(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); ApplyActiveAnimationPlaybackSpeed(val); if (HasNativeFacialAnimationControl(dancer)) { StopRuntimeMorphPlayback(); } StartAudioIfEnabled(activeAudioSource, val, _loadedPrefab.Clip, suppressFurtherRetries: true); LogVerbose($"Animation configured for '{((Object)dancer).name}', clip='{((Object)_loadedPrefab.Clip).name}', isPlaying={activeAnimation.isPlaying}."); } else if (HasNativeFacialAnimationControl(dancer)) { StopRuntimeMorphPlayback(); } else { StartMorphPlayback(dancer); } } private void ConfigureFacialExpressions(GameObject dancer) { CacheActiveRuntimeComponents(dancer); if (HasNativeFacialAnimationControl(dancer)) { MikuFacialExpressionController component = dancer.GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } StopRuntimeMorphPlayback(); LogVerbose("Skipping runtime facial expression playback for '" + ((Object)dancer).name + "' because Unity-native facial animation control was detected."); return; } if ((Object)(object)_loadedPrefab?.MorphClip != (Object)null) { MikuFacialExpressionController component2 = dancer.GetComponent(); if ((Object)(object)component2 != (Object)null) { ((Behaviour)component2).enabled = false; } LogVerbose("Skipping fallback facial expression controller for '" + ((Object)dancer).name + "' because a bundled morph clip is available."); 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) { LogVerbose("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() ?? dancer.AddComponent()).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 (HandlePlaybackPause(dancer, activeAnimator, activeAudioSource, val) || _isInLoopInterval) { return; } if ((Object)(object)activeAnimator != (Object)null && (Object)(object)activeAnimator.runtimeAnimatorController != (Object)null) { AnimationClip val2 = ResolveSynchronizedAnimatorClip(activeAnimator); activeAnimator.speed = ResolveSynchronizedAnimatorSpeed(val2, val); ForceAnimatorLayerWeights(activeAnimator, 1f); RefreshSecondaryNativeAnimators(activeAnimator, val2); ApplyActiveAnimationPlaybackSpeed(val); DancePluginConfig? config = _config; if (config != null && config.EnableAudio.Value && (Object)(object)activeAudioSource != (Object)null && (Object)(object)val != (Object)null && !_audioRetrySuppressed) { bool isPlaying = activeAudioSource.isPlaying; if (SynchronizeAudioWithAnimator(activeAnimator, activeAudioSource, val, val2, startIfNeeded: true, allowFadeOnStart: true, suppressFurtherRetries: true, logCorrections: false) && !isPlaying) { LogVerbose("Audio was enabled while the model was already active. Aligned 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; _animatorSegmentLoopIndex = 0; _lastAnimatorLoopIndex = -1; _lastMorphLoopIndex = -1; _isInLoopInterval = false; _loopIntervalEndTime = -1f; _isPausedForOfflineMenu = false; _isPausedForDistance = false; _audioPausedForPlaybackPause = 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.priority = 32; audioSource.rolloffMode = (AudioRolloffMode)1; audioSource.minDistance = 1f; audioSource.maxDistance = maxDistance; audioSource.spread = 0f; DancePluginConfig? config2 = _config; if (config2 != null && config2.EnableAudio.Value) { RequestAudioClipLoad(audioClip); } DancePluginConfig? config3 = _config; if ((config3 == null || !config3.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 timeSeconds = ResolveAudioSegmentStartSeconds(animationClip, audioClip); float num = ResolveAudioSegmentDuration(animationClip, audioClip); if (num <= 0.01f) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Audio segment duration is invalid for clip '" + ((Object)audioClip).name + "'.")); } return false; } if (!EnsureAudioClipReadyForPlayback(audioClip, suppressFurtherRetries, "audio start")) { return false; } try { audioSource.clip = audioClip; audioSource.loop = false; SeekAudioToTime(audioSource, audioClip, timeSeconds); audioSource.volume = 0f; audioSource.Play(); BeginAudioFade(audioSource, Mathf.Min(0.35f, num * 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 || _isPausedForOfflineMenu || _isPausedForDistance) { return; } if (!((Object)(object)_activeAnimator == (Object)null)) { DancePluginConfig? config = _config; if (config == null || !config.EnableAudio.Value || !((Object)(object)_activeAudioSource == (Object)null)) { goto IL_0060; } } CacheActiveRuntimeComponents(_activeDancer); goto IL_0060; IL_0060: Animator activeAnimator = _activeAnimator; if ((Object)(object)activeAnimator == (Object)null || (Object)(object)activeAnimator.runtimeAnimatorController == (Object)null) { return; } AnimationClip val = ResolveSynchronizedAnimatorClip(activeAnimator); if ((Object)(object)val == (Object)null) { return; } if (_isInLoopInterval) { if (Time.time < _loopIntervalEndTime) { return; } _isInLoopInterval = false; _loopIntervalEndTime = -1f; StartAnimatorAtBeginning(activeAnimator, val); _lastAnimatorLoopIndex = -1; _lastMorphLoopIndex = -1; LogVerbose("Loop interval elapsed; resuming synchronized playback."); } if (activeAnimator.speed == 0f) { AudioClip audioClip = ResolveAudioClip(_activeAudioSource); float targetLoopDurationSeconds = ResolveTargetLoopDurationSeconds(val, audioClip); activeAnimator.speed = ResolveAnimationPlaybackSpeed(val, targetLoopDurationSeconds); } ResolveAnimatorSegmentProgress(activeAnimator, val, out var loopProgress, out var _); if (loopProgress >= 0.999f) { BeginLoopInterval(activeAnimator, val); return; } int animatorSegmentLoopIndex = _animatorSegmentLoopIndex; MaintainAnimatorSegmentLoop(activeAnimator, val); if (_animatorSegmentLoopIndex > animatorSegmentLoopIndex) { BeginLoopInterval(activeAnimator, val); return; } DancePluginConfig? config2 = _config; if (config2 != null && config2.EnableAudio.Value) { AudioSource activeAudioSource = _activeAudioSource; AudioClip val2 = ResolveAudioClip(activeAudioSource); if (!((Object)(object)activeAudioSource == (Object)null) && !((Object)(object)val2 == (Object)null)) { SynchronizeAudioWithAnimator(activeAnimator, activeAudioSource, val2, val, startIfNeeded: true, allowFadeOnStart: true, suppressFurtherRetries: true, logCorrections: false); } } } private void BeginLoopInterval(Animator animator, AnimationClip primaryClip) { _isInLoopInterval = true; _loopIntervalEndTime = Time.time + 5f; float speed = animator.speed; animator.speed = 0f; AudioSource activeAudioSource = _activeAudioSource; if ((Object)(object)activeAudioSource != (Object)null && activeAudioSource.isPlaying) { activeAudioSource.Stop(); } LogVerbose($"Animation loop completed; pausing for {5f:0.##}s before replay. (animatorSpeed was {speed:0.###})"); } private void MaintainMorphPlaybackAfterAnimator() { if ((Object)(object)_activeDancer == (Object)null || _isPausedForOfflineMenu || _isPausedForDistance || _isInLoopInterval) { return; } if ((Object)(object)_activeAnimator == (Object)null) { CacheActiveRuntimeComponents(_activeDancer); } Animator activeAnimator = _activeAnimator; if ((Object)(object)activeAnimator == (Object)null || (Object)(object)activeAnimator.runtimeAnimatorController == (Object)null) { return; } AnimationClip val = ResolveSynchronizedAnimatorClip(activeAnimator); if (!((Object)(object)val == (Object)null)) { if (_hasNativeFacialAnimationControl) { StopRuntimeMorphPlayback(); SynchronizeNativeFacialAnimatorsWithPrimary(activeAnimator, val); } else { SynchronizeMorphPlaybackWithAnimator(activeAnimator, val); } } } private void StartMorphPlayback(GameObject? dancer) { if ((Object)(object)dancer == (Object)null || (Object)(object)_loadedPrefab?.MorphClip == (Object)null) { return; } if (HasNativeFacialAnimationControl(dancer)) { StopRuntimeMorphPlayback(); return; } if (ShouldUseDirectMorphSampling()) { Animation activeAnimation = _activeAnimation; if ((Object)(object)activeAnimation != (Object)null && (Object)(object)activeAnimation.clip != (Object)null) { activeAnimation.Stop(((Object)activeAnimation.clip).name); } _activeAnimation = null; SampleMorphClip(_loadedPrefab.MorphClip, _activeAnimator, 0f); _lastMorphLoopIndex = -1; return; } GameObject val = ResolveMorphPlaybackHost(dancer); Animation val2 = (_activeAnimation = val.GetComponent() ?? val.AddComponent()); val2.cullingType = (AnimationCullingType)0; if ((Object)(object)val2.GetClip(((Object)_loadedPrefab.MorphClip).name) == (Object)null) { val2.AddClip(_loadedPrefab.MorphClip, ((Object)_loadedPrefab.MorphClip).name); } val2.clip = _loadedPrefab.MorphClip; val2.wrapMode = (WrapMode)2; val2.playAutomatically = false; val2.Stop(((Object)_loadedPrefab.MorphClip).name); val2.Rewind(((Object)_loadedPrefab.MorphClip).name); val2.Play(((Object)_loadedPrefab.MorphClip).name); AnimationState val3 = val2[((Object)_loadedPrefab.MorphClip).name]; if ((TrackedReference)(object)val3 != (TrackedReference)null) { val3.enabled = true; val3.weight = 1f; val3.wrapMode = (WrapMode)2; val3.time = 0f; if ((Object)(object)_activeAnimator != (Object)null && (Object)(object)_activeAnimator.runtimeAnimatorController != (Object)null && (Object)(object)_activePrimaryAnimatorClip != (Object)null) { val3.speed = 0f; val2.Sample(); } else { ApplyActiveAnimationPlaybackSpeed(ResolveAudioClip(_activeAudioSource)); } } _lastMorphLoopIndex = -1; } private void SynchronizeMorphPlaybackWithAnimator(Animator animator, AnimationClip? primaryClip) { AnimationClip val = _loadedPrefab?.MorphClip; GameObject val2 = _activeDancer ?? ((Component)animator).gameObject; if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || val.length <= 0.01f) { return; } ResolveAnimatorSegmentProgress(animator, primaryClip, out var loopProgress, out var loopIndex); float num = Mathf.Clamp(loopProgress * val.length, 0f, Mathf.Max(0f, val.length - 0.0001f)); if (ShouldUseDirectMorphSampling()) { SampleMorphClip(val, animator, num); _lastMorphLoopIndex = loopIndex; return; } Animation activeAnimation = _activeAnimation; if ((Object)(object)activeAnimation == (Object)null || (Object)(object)activeAnimation.clip == (Object)null) { return; } string name = ((Object)activeAnimation.clip).name; AnimationState val3 = activeAnimation[name]; if (!((TrackedReference)(object)val3 == (TrackedReference)null)) { val3.enabled = true; val3.weight = 1f; val3.wrapMode = (WrapMode)2; val3.speed = 0f; if (_lastMorphLoopIndex >= 0 && loopIndex != _lastMorphLoopIndex) { activeAnimation.Stop(name); val3.time = 0f; activeAnimation.Play(name); } if (!activeAnimation.IsPlaying(name)) { activeAnimation.Play(name); } val3.time = num; activeAnimation.Sample(); _lastMorphLoopIndex = loopIndex; } } private void StopRuntimeMorphPlayback() { AnimationClip val = _loadedPrefab?.MorphClip; if ((Object)(object)val == (Object)null) { return; } Animation activeAnimation = _activeAnimation; if ((Object)(object)activeAnimation != (Object)null) { if ((Object)(object)activeAnimation.GetClip(((Object)val).name) != (Object)null) { activeAnimation.Stop(((Object)val).name); } if ((Object)(object)activeAnimation.clip != (Object)null && string.Equals(((Object)activeAnimation.clip).name, ((Object)val).name, StringComparison.Ordinal)) { activeAnimation.clip = null; } } _lastMorphLoopIndex = -1; } private GameObject ResolveMorphPlaybackHost(GameObject dancer) { if ((Object)(object)_activeAnimator != (Object)null) { return ((Component)_activeAnimator).gameObject; } Transform val = dancer.transform.Find("MikuLobbyModel"); if (!((Object)(object)val != (Object)null)) { return dancer; } return ((Component)val).gameObject; } private void SampleMorphClip(AnimationClip morphClip, Animator? animator, float timeSeconds) { GameObject activeDancer = _activeDancer; if (!((Object)(object)activeDancer == (Object)null)) { SampleMorphClipAtRoot(morphClip, activeDancer, timeSeconds); Transform val = activeDancer.transform.Find("MikuLobbyModel"); if ((Object)(object)val != (Object)null) { SampleMorphClipAtRoot(morphClip, ((Component)val).gameObject, timeSeconds); } GameObject val2 = (GameObject)(((Object)(object)animator != (Object)null) ? ((object)((Component)animator).gameObject) : ((object)ResolveMorphPlaybackHost(activeDancer))); if ((Object)(object)val2 != (Object)null) { SampleMorphClipAtRoot(morphClip, val2, timeSeconds); } } } private static void SampleMorphClipAtRoot(AnimationClip morphClip, GameObject root, float timeSeconds) { if (!((Object)(object)root == (Object)null)) { morphClip.SampleAnimation(root, timeSeconds); } } 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 HandlePlaybackPause(GameObject dancer, Animator? animator, AudioSource? audioSource, AudioClip? audioClip) { bool flag = ShouldPauseForOfflineMenu(); float distanceMeters; bool flag2 = ShouldPauseForDistance(dancer, out distanceMeters); bool flag3 = _isPausedForOfflineMenu || _isPausedForDistance; _isPausedForOfflineMenu = flag; _isPausedForDistance = flag2; if (_isPausedForOfflineMenu || _isPausedForDistance) { if (!flag3) { _audioPausedForPlaybackPause = (Object)(object)audioSource != (Object)null && audioSource.isPlaying; if (_audioPausedForPlaybackPause) { ClearActiveAudioFade(audioSource); audioSource.Pause(); } if (flag && flag2) { LogVerbose($"Paused dancer playback because the offline menu is open and the local player is {distanceMeters:0.##}m away."); } else if (flag) { LogVerbose("Paused dancer playback because the offline menu is open."); } else { LogVerbose($"Paused dancer playback because the local player is {distanceMeters:0.##}m away, beyond the {100f:0.##}m optimization range."); } } SetPlaybackPausedState(animator, audioClip, paused: true); return true; } if (!flag3) { return false; } if (_audioPausedForPlaybackPause) { DancePluginConfig? config = _config; if (config != null && config.EnableAudio.Value && (Object)(object)audioSource != (Object)null && (Object)(object)audioClip != (Object)null) { audioSource.UnPause(); } } _audioPausedForPlaybackPause = false; SetPlaybackPausedState(animator, audioClip, paused: false); LogVerbose($"Resumed dancer playback because the local player is within {100f:0.##}m and no offline pause condition is active."); return false; } private void LogVerbose(string message) { if (VerboseLogState.Enabled) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)message); } } } private bool ShouldPauseForDistance(GameObject dancer, out float distanceMeters) { //IL_0033: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) distanceMeters = 0f; if (!TryResolveCurrentLocalPlayerPose(out Vector3 position, out Vector3 _, out Transform _, out string _)) { return false; } Vector3 val = (_hasActivePlacement ? _activePlacement.Position : dancer.transform.position); distanceMeters = Vector3.Distance(position, val); return distanceMeters > 100f; } private void SetPlaybackPausedState(Animator? animator, AudioClip? audioClip, bool paused) { if ((Object)(object)animator != (Object)null) { animator.speed = (paused ? 0f : ResolveSynchronizedAnimatorSpeed(_activePrimaryAnimatorClip, audioClip)); ForceAnimatorLayerWeights(animator, 1f); } foreach (Animator item in EnumerateSecondaryAnimators()) { item.speed = (paused ? 0f : ResolveSynchronizedAnimatorSpeed(ResolveAnimatorPlaybackClip(item), audioClip)); ForceAnimatorLayerWeights(item, 1f); } if (ShouldUseDirectMorphSampling()) { return; } Animation activeAnimation = _activeAnimation; if ((Object)(object)activeAnimation == (Object)null || (Object)(object)activeAnimation.clip == (Object)null) { return; } AnimationState val = activeAnimation[((Object)activeAnimation.clip).name]; if (!((TrackedReference)(object)val == (TrackedReference)null)) { if (ShouldSynchronizeMorphWithAnimator()) { val.speed = 0f; } else { val.speed = (paused ? 0f : ResolveDesiredActiveAnimationSpeed(audioClip)); } } } 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; } if (!_hasCachedRuntimeComponents || _cachedRuntimeComponentRoot != dancer) { _cachedRuntimeComponentRoot = dancer; _hasCachedRuntimeComponents = true; _activeAnimators = (from animator in dancer.GetComponentsInChildren(true) where (Object)(object)animator != (Object)null select animator).ToArray(); _activeAnimator = ResolvePrimaryRuntimeAnimator(_activeAnimators); _activeAnimation = dancer.GetComponentInChildren(true); _activeAudioSource = dancer.GetComponentInChildren(true); _cachedAnimatorController = null; _activePrimaryAnimatorClip = null; } RefreshCachedPrimaryAnimatorClip(); RefreshNativeFacialAnimationDetection(dancer); } private void ClearActiveRuntimeComponents() { _activeAnimator = null; _activeAnimators = Array.Empty(); _activeAnimation = null; _activeAudioSource = null; _activePrimaryAnimatorClip = null; _activeShadowBlob = null; _hasCachedRuntimeComponents = false; _cachedRuntimeComponentRoot = null; _cachedAnimatorController = null; _hasNativeFacialAnimationControl = false; } private void RefreshCachedPrimaryAnimatorClip() { Animator activeAnimator = _activeAnimator; RuntimeAnimatorController val = ((activeAnimator != null) ? activeAnimator.runtimeAnimatorController : null); if (val != _cachedAnimatorController) { _cachedAnimatorController = val; _activePrimaryAnimatorClip = (((Object)(object)activeAnimator != (Object)null && (Object)(object)val != (Object)null) ? ResolvePrimaryAnimatorClip(activeAnimator) : null); } } private static AnimationClip? ResolvePrimaryAnimatorClip(Animator animator) { RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController; AnimationClip[] array = ((runtimeAnimatorController != null) ? runtimeAnimatorController.animationClips : null); if (array == null || array.Length == 0) { return null; } AnimationClip result = null; float num = float.MinValue; foreach (AnimationClip val in array) { if (!((Object)(object)val == (Object)null) && !(val.length <= num)) { result = val; num = val.length; } } return result; } private static Animator? ResolvePrimaryRuntimeAnimator(IEnumerable animators) { return animators?.Where((Animator animator) => (Object)(object)animator != (Object)null).OrderBy(delegate(Animator animator) { RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController; return ((Object)(object)runtimeAnimatorController == (Object)null) ? 2 : (IsLikelyNativeFacialController(runtimeAnimatorController) ? 1 : 0); }).ThenByDescending(delegate(Animator animator) { AnimationClip? obj = ResolvePrimaryAnimatorClip(animator); return (obj == null) ? 0f : obj.length; }) .FirstOrDefault(); } private AnimationClip? ResolveSynchronizedAnimatorClip(Animator animator) { AnimationClip val = TryResolveCurrentAnimatorClip(animator); if ((Object)(object)val != (Object)null) { _activePrimaryAnimatorClip = val; return val; } RefreshCachedPrimaryAnimatorClip(); return _activePrimaryAnimatorClip; } private static AnimationClip? TryResolveCurrentAnimatorClip(Animator animator) { if ((Object)(object)animator == (Object)null) { return null; } try { AnimatorClipInfo[] currentAnimatorClipInfo = animator.GetCurrentAnimatorClipInfo(0); if (currentAnimatorClipInfo != null && currentAnimatorClipInfo.Length != 0) { AnimationClip val = currentAnimatorClipInfo.Select((AnimatorClipInfo info) => ((AnimatorClipInfo)(ref info)).clip).FirstOrDefault((Func)((AnimationClip clip) => (Object)(object)clip != (Object)null && clip.length > 0.01f)); if ((Object)(object)val != (Object)null) { return val; } } } catch (Exception) { } try { AnimatorClipInfo[] nextAnimatorClipInfo = animator.GetNextAnimatorClipInfo(0); if (nextAnimatorClipInfo != null && nextAnimatorClipInfo.Length != 0) { AnimationClip val2 = nextAnimatorClipInfo.Select((AnimatorClipInfo info) => ((AnimatorClipInfo)(ref info)).clip).FirstOrDefault((Func)((AnimationClip clip) => (Object)(object)clip != (Object)null && clip.length > 0.01f)); if ((Object)(object)val2 != (Object)null) { return val2; } } } catch (Exception) { } return null; } private void ApplyActiveAnimationPlaybackSpeed(AudioClip? audioClip) { if (ShouldUseDirectMorphSampling() || ShouldSynchronizeMorphWithAnimator()) { return; } Animation activeAnimation = _activeAnimation; AnimationClip val = ((activeAnimation != null) ? activeAnimation.clip : null); if (!((Object)(object)activeAnimation == (Object)null) && !((Object)(object)val == (Object)null)) { AnimationState val2 = activeAnimation[((Object)val).name]; if (!((TrackedReference)(object)val2 == (TrackedReference)null)) { val2.speed = ResolveDesiredActiveAnimationSpeed(audioClip); } } } private float ResolveDesiredActiveAnimationSpeed(AudioClip? audioClip) { Animation? activeAnimation = _activeAnimation; AnimationClip val = ((activeAnimation != null) ? activeAnimation.clip : null); if ((Object)(object)val == (Object)null || val.length <= 0.01f) { return 1f; } if ((Object)(object)_activeAnimator != (Object)null && (Object)(object)_activeAnimator.runtimeAnimatorController != (Object)null && (Object)(object)_activePrimaryAnimatorClip != (Object)null) { float targetLoopDurationSeconds = ResolveTargetLoopDurationSeconds(_activePrimaryAnimatorClip, audioClip); return ResolveAnimationPlaybackSpeed(val, targetLoopDurationSeconds); } float targetLoopDurationSeconds2 = ResolveTargetLoopDurationSeconds(val, audioClip); return ResolveAnimationPlaybackSpeed(val, targetLoopDurationSeconds2); } private bool SynchronizeAudioWithAnimator(Animator animator, AudioSource audioSource, AudioClip audioClip, AnimationClip? primaryClip, bool startIfNeeded, bool allowFadeOnStart, bool suppressFurtherRetries, bool logCorrections) { if (!TryResolveAnimatorAudioPosition(animator, primaryClip, audioClip, out var expectedAudioTime, out var animatorLoopIndex, out var segmentDuration)) { return false; } bool flag = _lastAnimatorLoopIndex >= 0 && animatorLoopIndex != _lastAnimatorLoopIndex; _lastAnimatorLoopIndex = animatorLoopIndex; if (!audioSource.isPlaying) { if (!startIfNeeded) { return false; } return StartAudioAtTime(audioSource, audioClip, expectedAudioTime, segmentDuration, allowFadeOnStart, suppressFurtherRetries, flag ? "animator loop restart" : "audio start"); } if (flag) { return StartAudioAtTime(audioSource, audioClip, expectedAudioTime, segmentDuration, allowFadeOnStart, suppressFurtherRetries, "animator loop restart"); } float num = Mathf.Clamp(audioSource.time, 0f, Mathf.Max(0f, audioClip.length - 0.01f)); float num2 = Mathf.Abs(num - expectedAudioTime); if (num2 < 1.25f) { if (logCorrections && num2 >= 0.35f) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)("Leaving minor audio drift uncorrected for '" + ((Object)audioClip).name + "' to avoid audible seek stutter. " + $"expected={expectedAudioTime:0.###}, current={num:0.###}, drift={num2:0.###}, loop={animatorLoopIndex}.")); } } return true; } if (logCorrections) { ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogInfo((object)($"Correcting audio drift for '{((Object)audioClip).name}'. expected={expectedAudioTime:0.###}, current={num:0.###}, " + $"drift={num2:0.###}, loop={animatorLoopIndex}.")); } } return StartAudioAtTime(audioSource, audioClip, expectedAudioTime, segmentDuration, fadeIn: false, suppressFurtherRetries, "hard resync"); } private bool TryResolveAnimatorAudioPosition(Animator animator, AnimationClip? primaryClip, AudioClip? audioClip, out float expectedAudioTime, out int animatorLoopIndex, out float segmentDuration) { expectedAudioTime = 0f; animatorLoopIndex = 0; segmentDuration = 0f; if ((Object)(object)audioClip == (Object)null || audioClip.length <= 0.01f) { return false; } float num = ResolveAudioSegmentStartSeconds(primaryClip, audioClip); segmentDuration = ResolveAudioSegmentDuration(primaryClip, audioClip); if (segmentDuration <= 0.01f) { return false; } ResolveAnimatorSegmentProgress(animator, primaryClip, out var loopProgress, out animatorLoopIndex); float num2 = Mathf.Min(audioClip.length, num + segmentDuration); expectedAudioTime = Mathf.Lerp(num, num2, loopProgress); expectedAudioTime = Mathf.Clamp(expectedAudioTime, num, Mathf.Max(num, num2 - 0.01f)); return true; } private bool StartAudioAtTime(AudioSource audioSource, AudioClip audioClip, float startTime, float segmentDuration, bool fadeIn, bool suppressFurtherRetries, string logReason) { if (!EnsureAudioClipReadyForPlayback(audioClip, suppressFurtherRetries, logReason)) { return false; } try { ClearActiveAudioFade(audioSource); audioSource.Stop(); audioSource.clip = audioClip; audioSource.loop = false; SeekAudioToTime(audioSource, audioClip, startTime); audioSource.volume = (fadeIn ? 0f : (_config?.ResolvedAudioVolume ?? 1f)); audioSource.Play(); if (fadeIn) { BeginAudioFade(audioSource, Mathf.Min(0.35f, segmentDuration * 0.5f)); } } catch (Exception ex) { if (suppressFurtherRetries) { _audioRetrySuppressed = true; } ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Audio playback failed for clip '" + ((Object)audioClip).name + "' during " + logReason + ": " + ex.Message)); } return false; } bool isPlaying = audioSource.isPlaying; if (!isPlaying && suppressFurtherRetries) { _audioRetrySuppressed = true; ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("Audio playback could not start for clip '" + ((Object)audioClip).name + "' during " + logReason + ". Automatic retries are suppressed until audio is toggled again or the model is respawned.")); } } return isPlaying; } private void RequestAudioClipLoad(AudioClip? audioClip) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)audioClip == (Object)null) { return; } try { if ((int)audioClip.loadState == 0) { audioClip.LoadAudioData(); } } catch (Exception ex) { LogVerbose("Failed to request audio clip load for '" + ((Object)audioClip).name + "': " + ex.Message); } } private bool EnsureAudioClipReadyForPlayback(AudioClip audioClip, bool suppressFurtherRetries, string logReason) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 if ((Object)(object)audioClip == (Object)null) { return false; } RequestAudioClipLoad(audioClip); AudioDataLoadState loadState = audioClip.loadState; if ((int)loadState == 2) { return true; } if ((int)loadState == 3) { if (suppressFurtherRetries) { _audioRetrySuppressed = true; } ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Audio clip '" + ((Object)audioClip).name + "' failed to load during " + logReason + ".")); } return false; } LogVerbose("Audio clip '" + ((Object)audioClip).name + "' is still loading during " + logReason + ". Playback will retry automatically."); return false; } private static void SeekAudioToTime(AudioSource audioSource, AudioClip audioClip, float timeSeconds) { float num = Mathf.Clamp(timeSeconds, 0f, Mathf.Max(0f, audioClip.length - 0.01f)); int num2 = Mathf.Max(0, audioClip.samples - 1); if (audioClip.frequency > 0 && num2 > 0) { try { int timeSamples = Mathf.Clamp(Mathf.RoundToInt(num * (float)audioClip.frequency), 0, num2); audioSource.timeSamples = timeSamples; return; } catch (Exception) { } } audioSource.time = num; } private float ResolveSynchronizedAnimatorSpeed(AnimationClip? animationClip, AudioClip? audioClip) { if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f) { return 1f; } if (ShouldPreserveOriginalAnimatorTiming(animationClip)) { return 1f; } if ((Object)(object)audioClip == (Object)null || audioClip.length <= 0.01f) { return 1f; } float num = ResolveMotionSegmentDurationSeconds(animationClip); float num2 = ResolveAudioSegmentDuration(animationClip, audioClip); if (num2 <= 0.01f || num <= 0.01f) { return 1f; } return Mathf.Clamp(num / num2, 0.25f, 4f); } private bool ShouldPreserveOriginalAnimatorTiming(AnimationClip? animationClip) { if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f) { return true; } DancePlaybackMetadata dancePlaybackMetadata = ResolvePlaybackMetadata(); float num = dancePlaybackMetadata.ResolveMotionStartSeconds(animationClip.length); float num2 = dancePlaybackMetadata.ResolveMotionEndSeconds(animationClip.length); if (num <= 0.01f) { return num2 >= animationClip.length - 0.01f; } return false; } private float ResolveAudioSegmentStartSeconds(AnimationClip? animationClip, AudioClip? audioClip) { if ((Object)(object)audioClip == (Object)null || audioClip.length <= 0.01f) { return 0f; } return Mathf.Clamp(ResolvePlaybackMetadata().ResolveAudioSegmentStartSeconds(), 0f, Mathf.Max(0f, audioClip.length - 0.01f)); } private float ResolveAudioSegmentDuration(AnimationClip? animationClip, AudioClip? audioClip) { if ((Object)(object)audioClip == (Object)null || audioClip.length <= 0.01f) { return 0f; } return ResolvePlaybackMetadata().ResolveAudioSegmentDurationSeconds(ResolveMotionSegmentDurationSeconds(animationClip), audioClip.length); } private float ResolveTargetLoopDurationSeconds(AnimationClip? animationClip, AudioClip? audioClip) { if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f) { return 0f; } if ((Object)(object)audioClip == (Object)null) { return ResolveMotionSegmentDurationSeconds(animationClip); } float num = ResolveAudioSegmentDuration(animationClip, audioClip); if (!(num > 0.01f)) { return ResolveMotionSegmentDurationSeconds(animationClip); } return num; } private static float ResolveAnimationPlaybackSpeed(AnimationClip animationClip, float targetLoopDurationSeconds) { if (animationClip.length <= 0.01f || targetLoopDurationSeconds <= 0.01f) { return 1f; } return Mathf.Clamp(animationClip.length / targetLoopDurationSeconds, 0.25f, 4f); } private DancePlaybackMetadata ResolvePlaybackMetadata() { DancePlaybackMetadata dancePlaybackMetadata = _loadedPrefab?.PlaybackMetadata; if (dancePlaybackMetadata != null) { return dancePlaybackMetadata; } LegacyPlaybackMetadata.SourceFrameRate = 30f; LegacyPlaybackMetadata.MotionStartFrame = Mathf.RoundToInt(0f); LegacyPlaybackMetadata.HasMotionEndFrame = false; LegacyPlaybackMetadata.MotionEndFrame = 0; LegacyPlaybackMetadata.AudioSegmentStartSeconds = 0f; LegacyPlaybackMetadata.AudioSegmentDurationSeconds = 0f; return LegacyPlaybackMetadata; } private float ResolveMotionSegmentStartSeconds(AnimationClip? animationClip) { if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f) { return 0f; } return ResolvePlaybackMetadata().ResolveMotionStartSeconds(animationClip.length); } private float ResolveMotionSegmentDurationSeconds(AnimationClip? animationClip) { if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f) { return 0f; } return ResolvePlaybackMetadata().ResolveMotionSegmentDurationSeconds(animationClip.length); } private bool TryResolveMotionSegmentNormalizedRange(AnimationClip? animationClip, out float startNormalized, out float durationNormalized, out float durationSeconds) { startNormalized = 0f; durationNormalized = 1f; durationSeconds = 0f; if ((Object)(object)animationClip == (Object)null || animationClip.length <= 0.01f) { return false; } DancePlaybackMetadata dancePlaybackMetadata = ResolvePlaybackMetadata(); float num = dancePlaybackMetadata.ResolveMotionStartSeconds(animationClip.length); float num2 = dancePlaybackMetadata.ResolveMotionEndSeconds(animationClip.length); durationSeconds = Mathf.Max(0f, num2 - num); if (durationSeconds <= 0.01f) { durationSeconds = animationClip.length; return false; } if (num <= 0.01f && num2 >= animationClip.length - 0.01f) { return false; } startNormalized = Mathf.Clamp01(num / animationClip.length); durationNormalized = Mathf.Clamp(durationSeconds / animationClip.length, 0.0001f, 1f); return true; } private void ResolveAnimatorSegmentProgress(Animator animator, AnimationClip? primaryClip, out float loopProgress, out int loopIndex) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) loopProgress = 0f; loopIndex = 0; AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0); float num = Mathf.Max(0f, ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime); if (!TryResolveMotionSegmentNormalizedRange(primaryClip, out var startNormalized, out var durationNormalized, out var _)) { loopIndex = Mathf.Max(0, Mathf.FloorToInt(num)); loopProgress = Mathf.Repeat(num, 1f); } else if (num <= startNormalized + 0.0001f) { loopProgress = 0f; loopIndex = Mathf.Max(0, _animatorSegmentLoopIndex); } else { float num2 = Mathf.Repeat(Mathf.Max(0f, num - startNormalized), durationNormalized); loopProgress = ((durationNormalized > 0.0001f) ? Mathf.Clamp01(num2 / durationNormalized) : 0f); loopIndex = Mathf.Max(0, _animatorSegmentLoopIndex); } } private void MaintainAnimatorSegmentLoop(Animator animator, AnimationClip? primaryClip) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)animator == (Object)null || (Object)(object)primaryClip == (Object)null || primaryClip.length <= 0.01f) { return; } if (!TryResolveMotionSegmentNormalizedRange(primaryClip, out var startNormalized, out var durationNormalized, out var _)) { AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0); if (!((AnimatorStateInfo)(ref currentAnimatorStateInfo)).loop && !((Motion)primaryClip).isLooping) { float num = Mathf.Max(0f, ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime); if (!(num < 0.9999f)) { _animatorSegmentLoopIndex += Mathf.Max(1, Mathf.FloorToInt(num)); animator.Play(0, 0, 0f); animator.Update(0f); } } return; } AnimatorStateInfo currentAnimatorStateInfo2 = animator.GetCurrentAnimatorStateInfo(0); float num2 = Mathf.Max(0f, ((AnimatorStateInfo)(ref currentAnimatorStateInfo2)).normalizedTime); if (num2 + 0.0001f < startNormalized) { animator.Play(0, 0, startNormalized); animator.Update(0f); return; } float num3 = Mathf.Max(0f, num2 - startNormalized); if (!(num3 < durationNormalized - 0.0001f)) { int num4 = Mathf.Max(1, Mathf.FloorToInt(num3 / durationNormalized)); _animatorSegmentLoopIndex += num4; float num5 = Mathf.Repeat(num3, durationNormalized); float num6 = startNormalized + num5; if (!(Mathf.Abs(num6 - num2) <= 0.0001f)) { animator.Play(0, 0, num6); animator.Update(0f); } } } private void StartAnimatorAtBeginning(Animator animator, AnimationClip? primaryClip) { _animatorSegmentLoopIndex = 0; _lastAnimatorLoopIndex = -1; _lastMorphLoopIndex = -1; float num = 0f; if ((Object)(object)primaryClip != (Object)null && primaryClip.length > 0.01f) { num = Mathf.Clamp01(ResolveMotionSegmentStartSeconds(primaryClip) / primaryClip.length); } animator.Play(0, 0, num); animator.Update(0f); } private bool ShouldUseDirectMorphSampling() { return ShouldSynchronizeMorphWithAnimator(); } private IEnumerable EnumerateSecondaryAnimators() { if (_activeAnimators == null || _activeAnimators.Length == 0) { yield break; } for (int index = 0; index < _activeAnimators.Length; index++) { Animator val = _activeAnimators[index]; if (!((Object)(object)val == (Object)null) && val != _activeAnimator && !((Object)(object)val.runtimeAnimatorController == (Object)null)) { yield return val; } } } private bool ShouldSynchronizeMorphWithAnimator() { if ((Object)(object)_loadedPrefab?.MorphClip != (Object)null && !_hasNativeFacialAnimationControl && (Object)(object)_activeAnimator != (Object)null && (Object)(object)_activeAnimator.runtimeAnimatorController != (Object)null) { return (Object)(object)_activePrimaryAnimatorClip != (Object)null; } return false; } private void ConfigureSecondaryNativeAnimators(AnimationClip? primaryClip, float animationSpeed) { foreach (Animator item in EnumerateSecondaryAnimators()) { item.cullingMode = (AnimatorCullingMode)0; item.applyRootMotion = false; item.updateMode = (AnimatorUpdateMode)0; item.speed = animationSpeed; ForceAnimatorLayerWeights(item, 1f); item.Rebind(); item.Update(0f); AnimationClip targetClip = ResolveAnimatorPlaybackClip(item); float num = ResolveClipStartNormalized(primaryClip, targetClip); item.Play(0, 0, num); item.Update(0f); } } private void RefreshSecondaryNativeAnimators(Animator primaryAnimator, AnimationClip? primaryClip) { if (_hasNativeFacialAnimationControl) { SynchronizeNativeFacialAnimatorsWithPrimary(primaryAnimator, primaryClip); } } private void SynchronizeNativeFacialAnimatorsWithPrimary(Animator primaryAnimator, AnimationClip? primaryClip) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)primaryAnimator == (Object)null) { return; } ResolveAnimatorSegmentProgress(primaryAnimator, primaryClip, out var loopProgress, out var _); foreach (Animator item in EnumerateSecondaryAnimators()) { AnimationClip val = ResolveAnimatorPlaybackClip(item); if (!((Object)(object)val == (Object)null) && !(val.length <= 0.01f)) { item.cullingMode = (AnimatorCullingMode)0; item.applyRootMotion = false; item.updateMode = (AnimatorUpdateMode)0; item.speed = primaryAnimator.speed; ForceAnimatorLayerWeights(item, 1f); float num = Mathf.Clamp01(loopProgress); AnimatorStateInfo currentAnimatorStateInfo = item.GetCurrentAnimatorStateInfo(0); float num2 = Mathf.Max(0f, ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime); float num3 = Mathf.Abs(Mathf.DeltaAngle(Mathf.Repeat(num2, 1f) * 360f, num * 360f)) / 360f; if ((!((AnimatorStateInfo)(ref currentAnimatorStateInfo)).loop && !((Motion)val).isLooping && num2 >= 0.999f && num <= 0.98f) || !(num3 <= 0.02f) || !(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length > 0f)) { item.Play(0, 0, num); item.Update(0f); } } } } private static AnimationClip? ResolveAnimatorPlaybackClip(Animator animator) { if ((Object)(object)animator == (Object)null) { return null; } return TryResolveCurrentAnimatorClip(animator) ?? ResolvePrimaryAnimatorClip(animator); } private float ResolveClipStartNormalized(AnimationClip? timingReferenceClip, AnimationClip? targetClip) { if ((Object)(object)targetClip == (Object)null || targetClip.length <= 0.01f) { return 0f; } return Mathf.Clamp01((((Object)(object)timingReferenceClip != (Object)null) ? Mathf.Max(0f, ResolveMotionSegmentStartSeconds(timingReferenceClip)) : 0f) / targetClip.length); } private static void ForceAnimatorLayerWeights(Animator animator, float weight) { if (!((Object)(object)animator == (Object)null)) { for (int i = 0; i < animator.layerCount; i++) { animator.SetLayerWeight(i, weight); } } } private bool HasNativeFacialAnimationControl(GameObject? dancer) { if ((Object)(object)dancer == (Object)null) { return false; } if (_hasCachedRuntimeComponents && _cachedRuntimeComponentRoot == dancer) { return _hasNativeFacialAnimationControl; } return DetectNativeFacialAnimationControl(dancer); } private void RefreshNativeFacialAnimationDetection(GameObject? dancer) { bool flag = DetectNativeFacialAnimationControl(dancer); if (_hasNativeFacialAnimationControl != flag) { LogVerbose($"Native facial animation detection changed: {flag}."); } _hasNativeFacialAnimationControl = flag; } private bool DetectNativeFacialAnimationControl(GameObject? dancer) { if ((Object)(object)dancer == (Object)null) { return false; } Animator[] array = (from animator in dancer.GetComponentsInChildren(true) where (Object)(object)animator != (Object)null && (Object)(object)animator.runtimeAnimatorController != (Object)null select animator).ToArray(); if (array.Length > 1) { return true; } for (int num = 0; num < array.Length; num++) { RuntimeAnimatorController runtimeAnimatorController = array[num].runtimeAnimatorController; if (!((Object)(object)runtimeAnimatorController == (Object)null) && IsLikelyNativeFacialController(runtimeAnimatorController)) { return true; } } return false; } private static bool IsLikelyNativeFacialController(RuntimeAnimatorController controller) { if ((Object)(object)controller == (Object)null) { return false; } if (ContainsFacialToken(((Object)controller).name)) { return true; } AnimationClip[] animationClips = controller.animationClips; if (animationClips == null || animationClips.Length == 0) { return false; } foreach (AnimationClip val in animationClips) { if (!((Object)(object)val == (Object)null) && ContainsFacialToken(((Object)val).name)) { return true; } } return false; } private static bool ContainsFacialToken(string? value) { string text = value ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { return false; } for (int i = 0; i < NativeFacialClipTokens.Length; i++) { string value2 = NativeFacialClipTokens[i]; if (!string.IsNullOrEmpty(value2) && text.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } } 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; } } [Serializable] internal sealed class DancePlaybackMetadata { public float SourceFrameRate = 30f; public int MotionStartFrame; public bool HasMotionEndFrame; public int MotionEndFrame; public float AudioSegmentStartSeconds; public float AudioSegmentDurationSeconds; public static DancePlaybackMetadata CreateDefault() { return new DancePlaybackMetadata { SourceFrameRate = 30f, MotionStartFrame = 0, HasMotionEndFrame = false, MotionEndFrame = 0, AudioSegmentStartSeconds = 0f, AudioSegmentDurationSeconds = 0f }; } public float ResolveAudioSegmentStartSeconds() { return Mathf.Max(0f, AudioSegmentStartSeconds); } public float ResolveMotionStartSeconds(float animationClipLength) { float num = Mathf.Max(0f, animationClipLength); float num2 = ((SourceFrameRate > 0.01f) ? SourceFrameRate : 30f); return Mathf.Clamp(Mathf.Max(0f, (float)MotionStartFrame) / num2, 0f, num); } public float ResolveMotionEndSeconds(float animationClipLength) { float num = Mathf.Max(0f, animationClipLength); float num2 = ResolveMotionStartSeconds(num); if (!HasMotionEndFrame || MotionEndFrame <= MotionStartFrame) { return num; } float num3 = ((SourceFrameRate > 0.01f) ? SourceFrameRate : 30f); return Mathf.Clamp((float)Mathf.Max(MotionStartFrame, MotionEndFrame) / num3, num2, num); } public float ResolveMotionSegmentDurationSeconds(float animationClipLength) { float num = Mathf.Max(0f, animationClipLength); float num2 = ResolveMotionStartSeconds(num); float num3 = ResolveMotionEndSeconds(num); float num4 = Mathf.Max(0f, num3 - num2); if (!(num4 > 0.01f)) { return num; } return num4; } public float ResolveAudioSegmentDurationSeconds(float animationClipLength, float audioClipLength) { float num = ResolveAudioSegmentStartSeconds(); float num2 = Mathf.Max(0f, audioClipLength - num); float num3 = Mathf.Max(0f, AudioSegmentDurationSeconds); if (num3 > 0.01f) { return Mathf.Min(num3, num2); } if (animationClipLength > 0.01f) { return Mathf.Min(animationClipLength, num2); } return num2; } } internal sealed class LoadedDancePrefab { public GameObject Template { get; } public AnimationClip? Clip { get; } public AnimationClip? MorphClip { get; } public DancePlaybackMetadata? PlaybackMetadata { get; } public float LocalMinY { get; } public float LocalHeight { get; } public Vector3 LocalBoundsCenter { get; } public LoadedPrefabSource Source { get; } public LoadedDancePrefab(GameObject template, AnimationClip? clip, AnimationClip? morphClip, DancePlaybackMetadata? playbackMetadata, float localMinY, float localHeight, Vector3 localBoundsCenter, LoadedPrefabSource source) { //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) Template = template; Clip = clip; MorphClip = morphClip; PlaybackMetadata = playbackMetadata; LocalMinY = localMinY; LocalHeight = localHeight; LocalBoundsCenter = localBoundsCenter; Source = source; } } internal enum LoadedPrefabSource { UnityAssetBundle = 1 } 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 const float BlendShapeWeightChangeEpsilon = 0.1f; private readonly Dictionary> _bindingsByGroupKey = new Dictionary>(StringComparer.OrdinalIgnoreCase); private readonly List _jawBindings = new List(); private readonly List _lipBindings = new List(); private readonly float[] _audioSamples = new float[256]; private AudioSource? _audioSource; private ManualLogSource? _logger; private bool _initialized; private float _currentMouthWeight; private string? _lastPrimaryShapeGroupKey; private string? _appliedPrimaryShapeGroupKey; private float _appliedPrimaryShapeWeight; private bool _smileWeightApplied; public void Initialize(AudioSource? audioSource, Animator? animator, ManualLogSource? logger) { ((Behaviour)this).enabled = true; _audioSource = audioSource; _logger = logger; _bindingsByGroupKey.Clear(); _jawBindings.Clear(); _lipBindings.Clear(); ResetAppliedManagedShapeState(); List list = new List(); SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val in componentsInChildren) { Mesh sharedMesh = val.sharedMesh; if ((Object)(object)sharedMesh == (Object)null) { continue; } List list2 = new List(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 value)) { value = new List(); _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; LogVerbose("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 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))); LogVerbose("Facial expression controller initialized. blendshapeGroups=[" + text + "], jawBones=[" + text2 + "], lipBones=[" + text3 + "], skinnedRenderers=" + ((list.Count == 0) ? "(none)" : string.Join(" | ", list)) + "."); ResetManagedWeights(); ApplySmileWeight(); } private void LateUpdate() { if (_initialized) { float mouthWeight = ResolveMouthWeight(); string text = ResolvePrimaryMouthShapeGroupKey(mouthWeight); UpdateManagedWeights(text, mouthWeight); ApplySmileWeight(); ApplyBoneMouthPose(mouthWeight); _lastPrimaryShapeGroupKey = text; } } private float ResolveMouthWeight() { 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)); } } } _currentMouthWeight = Mathf.Lerp(_currentMouthWeight, num, Time.deltaTime * 10f); return _currentMouthWeight; } private string? ResolvePrimaryMouthShapeGroupKey(float mouthWeight) { if (mouthWeight <= 4f) { return null; } string[] mouthShapePriority = MouthShapePriority; foreach (string text in mouthShapePriority) { if (_bindingsByGroupKey.ContainsKey(text)) { return text; } } return _lastPrimaryShapeGroupKey; } private void ResetManagedWeights() { foreach (List value in _bindingsByGroupKey.Values) { foreach (BlendShapeBinding item in value) { item.Renderer.SetBlendShapeWeight(item.Index, 0f); } } } private void ApplySmileWeight() { if (!_smileWeightApplied && _bindingsByGroupKey.ContainsKey("Smile")) { ApplyWeight("Smile", 10f); _smileWeightApplied = true; } } private void ApplyWeight(string groupKey, float weight) { if (_bindingsByGroupKey.TryGetValue(groupKey, out List value)) { for (int i = 0; i < value.Count; i++) { value[i].Renderer.SetBlendShapeWeight(value[i].Index, weight); } } } private void UpdateManagedWeights(string? primaryShapeGroupKey, float mouthWeight) { string text = ((!string.IsNullOrWhiteSpace(primaryShapeGroupKey) && mouthWeight > 4f) ? primaryShapeGroupKey : null); float num = ((text == null) ? 0f : mouthWeight); if (!string.IsNullOrWhiteSpace(_appliedPrimaryShapeGroupKey) && !string.Equals(_appliedPrimaryShapeGroupKey, text, StringComparison.OrdinalIgnoreCase)) { ApplyWeight(_appliedPrimaryShapeGroupKey, 0f); _appliedPrimaryShapeGroupKey = null; _appliedPrimaryShapeWeight = 0f; } if (string.IsNullOrWhiteSpace(text)) { if (!string.IsNullOrWhiteSpace(_appliedPrimaryShapeGroupKey) && _appliedPrimaryShapeWeight > 0.001f) { ApplyWeight(_appliedPrimaryShapeGroupKey, 0f); } _appliedPrimaryShapeGroupKey = null; _appliedPrimaryShapeWeight = 0f; } else if (!string.Equals(_appliedPrimaryShapeGroupKey, text, StringComparison.OrdinalIgnoreCase) || Mathf.Abs(_appliedPrimaryShapeWeight - num) > 0.1f) { ApplyWeight(text, num); _appliedPrimaryShapeGroupKey = text; _appliedPrimaryShapeWeight = num; } } private void ResetAppliedManagedShapeState() { _appliedPrimaryShapeGroupKey = null; _appliedPrimaryShapeWeight = 0f; _smileWeightApplied = false; } 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 hashSet = new HashSet(); AddTopBoneBindings(_jawBindings, JawBoneTokens, hashSet, 2); foreach (BonePoseBinding jawBinding in _jawBindings) { hashSet.Add(jawBinding.Transform); } AddTopBoneBindings(_lipBindings, LipBoneTokens, hashSet, 2); } private void AddTopBoneBindings(ICollection destination, IEnumerable tokens, ISet 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) BoneCandidate[] array = (from candidate in ((Component)this).GetComponentsInChildren(true) where (Object)(object)candidate != (Object)(object)((Component)this).transform where !excludedTransforms.Contains(candidate) select new BoneCandidate(candidate, ScoreBoneCandidate(((Object)candidate).name, tokens)) into candidate where candidate.Score > 0 orderby candidate.Score descending, ((Object)candidate.Transform).name.Length select candidate).ThenBy((BoneCandidate candidate) => ((Object)candidate.Transform).name, StringComparer.OrdinalIgnoreCase).Take(maxCount).ToArray(); for (int num = 0; num < array.Length; num++) { destination.Add(new BonePoseBinding(array[num].Transform, array[num].Transform.localPosition, array[num].Transform.localRotation)); } } private void LogVerbose(string message) { if (VerboseLogState.Enabled) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)message); } } } private static int ScoreBoneCandidate(string candidateName, IEnumerable 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 UnityAssetBundleLoader { private readonly struct TextureSlotInfo { public static readonly TextureSlotInfo Empty = new TextureSlotInfo(null, Vector2.one, Vector2.zero); public Texture? Texture { get; } public Vector2 Scale { get; } public Vector2 Offset { get; } public TextureSlotInfo(Texture? texture, Vector2 scale, Vector2 offset) { //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) Texture = texture; Scale = scale; Offset = offset; } } private const string PreferredPrefabAssetName = "assets/codexbuild/mikulobby.prefab"; private const string PreferredMorphClipAssetName = "assets/codexbuild/mikulobbymorph.anim"; private const string PreferredPlaybackMetadataAssetName = "assets/codexbuild/mikulobbyplayback.json"; private const string PreferredRuntimeVmdAssetName = "assets/codexbuild/mikulobbymotion.vmd.bytes"; private static readonly string[] FaceLikeTokens = new string[12] { "face", "head", "skin", "cheek", "blush", "mouth", "lip", "eye", "brow", "lash", "kao", "hada" }; private static readonly string[] TransparentTokens = new string[6] { "transparent", "trans", "fade", "glass", "decal", "alpha" }; private static readonly string[] CustomToonShaderTokens = new string[5] { "toon", "outline", "anime", "cel", "ramp" }; private static readonly string[] TexturePropertyCandidates = new string[12] { "_BaseMap", "_MainTex", "_BaseColorMap", "_BaseColorTexture", "_MainTexture", "_ShadeTexture", "_ShadeMultiplyTexture", "_UnlitTexture", "_ShadingGradeTexture", "_SphereAddTex", "_SphereTex", "_MatCap" }; private static readonly string[] ColorPropertyCandidates = new string[7] { "_BaseColor", "_Color", "_LitColor", "_MainColor", "_ShadeColor", "_SColor", "_TintColor" }; private static readonly string[] NormalPropertyCandidates = new string[2] { "_BumpMap", "_NormalMap" }; private static readonly string[] EmissionPropertyCandidates = new string[2] { "_EmissionMap", "_EmissiveMap" }; private static readonly string[] MetallicPropertyCandidates = new string[2] { "_MetallicGlossMap", "_MetallicSpecGlossMap" }; private static readonly string[] OcclusionPropertyCandidates = new string[1] { "_OcclusionMap" }; private static readonly string[] EmissionTogglePropertyCandidates = new string[2] { "_UseEmission", "_EmissionEnabled" }; private AssetBundle? _retainedAssetBundle; public LoadedDancePrefab Load(string bundlePath, ManualLogSource logger) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_0514: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Unknown result type (might be due to invalid IL or missing references) ValidateFile(bundlePath); UnloadRetainedBundle(); AssetBundle val = AssetBundle.LoadFromFile(bundlePath); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("AssetBundle.LoadFromFile returned null for '" + bundlePath + "'."); } bool flag = false; try { string[] allAssetNames = val.GetAllAssetNames(); LogVerbose(logger, "Inspecting Unity bundle '" + bundlePath + "'. Assets: " + string.Join(", ", allAssetNames)); GameObject val2 = LoadPreferredPrefab(val, allAssetNames, logger); AnimationClip val3 = LoadPreferredMorphClip(val, allAssetNames, logger); DancePlaybackMetadata dancePlaybackMetadata = LoadPreferredPlaybackMetadata(val, allAssetNames, logger); TextAsset val4 = LoadPreferredRuntimeVmdBytes(val, allAssetNames, logger); if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("No GameObject asset was found in '" + bundlePath + "'. Assets: " + string.Join(", ", allAssetNames)); } GameObject val5 = Object.Instantiate(val2); ((Object)val5).name = ((Object)val2).name; ((Object)val5).hideFlags = (HideFlags)61; val5.SetActive(false); NormalizeRenderers(val5, logger); NormalizeAudioSources(val5, logger); AnimationClip val6 = (((Object)(object)val4 != (Object)null) ? BuildRuntimeVmdClip(val5, val4.bytes, logger) : null); Bounds val7 = CalculateRendererBounds(val5); int num = val5.GetComponentsInChildren(true).Length; int num2 = val5.GetComponentsInChildren(true).Length; int num3 = val5.GetComponentsInChildren(true).SelectMany((Renderer renderer) => renderer.sharedMaterials).Count((Material material) => (Object)(object)material != (Object)null); Animator componentInChildren = val5.GetComponentInChildren(true); Animation componentInChildren2 = val5.GetComponentInChildren(true); AudioSource[] componentsInChildren = val5.GetComponentsInChildren(true); if ((Object)(object)val3 == (Object)null) { logger.LogWarning((object)("The Unity bundle '" + bundlePath + "' does not contain a pre-baked facial AnimationClip. Runtime VMD morph decoding has been removed, so only the simplified fallback facial controller can be used.")); } object obj; if (componentInChildren == null) { obj = null; } else { RuntimeAnimatorController runtimeAnimatorController = componentInChildren.runtimeAnimatorController; obj = ((runtimeAnimatorController == null) ? null : (from clip in (from @group in runtimeAnimatorController.animationClips?.Where((AnimationClip clip) => (Object)(object)clip != (Object)null).GroupBy((AnimationClip clip) => ((Object)clip).name, StringComparer.Ordinal) select @group.First() into clip orderby clip.length descending select clip).Take(8) select $"{((Object)clip).name}({clip.length:0.###}s)")); } if (obj == null) { obj = Array.Empty(); } string text = string.Join(", ", (IEnumerable)obj); string arg = string.Join(", ", from @group in (from material in val5.GetComponentsInChildren(true).SelectMany((Renderer renderer) => renderer.sharedMaterials) where (Object)(object)material != (Object)null group material by (!((Object)(object)material.shader != (Object)null)) ? "(null)" : ((Object)material.shader).name into @group orderby @group.Count() descending select @group).Take(8) select $"{@group.Key} x{@group.Count()}"); string[] obj2 = new string[19] { "Loaded Unity bundle prefab '", ((Object)val2).name, "' from '", bundlePath, "'. ", $"renderers={num}, skinnedRenderers={num2}, materials={num3}, ", $"animator={(Object)(object)componentInChildren != (Object)null}, animation={(Object)(object)componentInChildren2 != (Object)null}, ", "controller='", null, null, null, null, null, null, null, null, null, null, null }; object obj3; if (componentInChildren == null) { obj3 = null; } else { RuntimeAnimatorController runtimeAnimatorController2 = componentInChildren.runtimeAnimatorController; obj3 = ((runtimeAnimatorController2 != null) ? ((Object)runtimeAnimatorController2).name : null); } if (obj3 == null) { obj3 = "(none)"; } obj2[8] = (string)obj3; obj2[9] = "', avatar='"; object obj4; if (componentInChildren == null) { obj4 = null; } else { Avatar avatar = componentInChildren.avatar; obj4 = ((avatar != null) ? ((Object)avatar).name : null); } if (obj4 == null) { obj4 = "(none)"; } obj2[10] = (string)obj4; obj2[11] = "', clips=["; obj2[12] = text; obj2[13] = "], "; obj2[14] = $"audioSources={componentsInChildren.Length}, "; obj2[15] = $"embeddedMorphClip={(Object)(object)val3 != (Object)null}, "; obj2[16] = $"runtimeVmdClip={(Object)(object)val6 != (Object)null}, "; obj2[17] = $"playbackMetadata={dancePlaybackMetadata != null}, "; obj2[18] = $"boundsCenter={((Bounds)(ref val7)).center}, boundsSize={((Bounds)(ref val7)).size}, shaders=[{arg}]"; LogVerbose(logger, string.Concat(obj2)); flag = true; _retainedAssetBundle = val; return new LoadedDancePrefab(val5, val6, val3, dancePlaybackMetadata, ((Bounds)(ref val7)).min.y, ((Bounds)(ref val7)).size.y, ((Bounds)(ref val7)).center, LoadedPrefabSource.UnityAssetBundle); } finally { if (!flag) { val.Unload(false); } } } public void UnloadRetainedBundle() { if (!((Object)(object)_retainedAssetBundle == (Object)null)) { _retainedAssetBundle.Unload(false); _retainedAssetBundle = null; } } private static GameObject? LoadPreferredPrefab(AssetBundle assetBundle, string[] assetNames, ManualLogSource logger) { string text = assetNames.FirstOrDefault((string name) => string.Equals(name, "assets/codexbuild/mikulobby.prefab", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/mikulobby.prefab", StringComparison.OrdinalIgnoreCase)); if (!string.IsNullOrWhiteSpace(text)) { GameObject val = assetBundle.LoadAsset(text); if ((Object)(object)val != (Object)null) { LogVerbose(logger, "Selected preferred bundle prefab asset '" + text + "'."); return val; } } return assetBundle.LoadAllAssets().OrderByDescending(HasPlayableAnimation).ThenByDescending(CountRenderers) .FirstOrDefault(); } private static AnimationClip? LoadPreferredMorphClip(AssetBundle assetBundle, string[] assetNames, ManualLogSource logger) { string text = assetNames.FirstOrDefault((string name) => string.Equals(name, "assets/codexbuild/mikulobbymorph.anim", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/mikulobbymorph.anim", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/mikulobbyfacial.anim", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/facialmorph.anim", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/facial.anim", StringComparison.OrdinalIgnoreCase)); if (string.IsNullOrWhiteSpace(text)) { return null; } AnimationClip val = assetBundle.LoadAsset(text); if ((Object)(object)val == (Object)null) { logger.LogWarning((object)("The bundle contains a facial clip asset entry '" + text + "', but it could not be loaded as an AnimationClip.")); return null; } try { AnimationClip val2 = Object.Instantiate(val); ((Object)val2).name = (string.IsNullOrWhiteSpace(((Object)val).name) ? "MikuLobbyMorph" : ((Object)val).name); val2.legacy = true; val2.wrapMode = (WrapMode)2; LogVerbose(logger, "Loaded pre-baked facial AnimationClip '" + text + "' from the Unity bundle. " + $"clip='{((Object)val2).name}', length={val2.length:0.###}, legacy={val2.legacy}."); return val2; } catch (Exception ex) { logger.LogWarning((object)("Failed to prepare pre-baked facial AnimationClip '" + text + "' for runtime playback: " + ex.Message)); return null; } } private static TextAsset? LoadPreferredRuntimeVmdBytes(AssetBundle assetBundle, string[] assetNames, ManualLogSource logger) { string text = assetNames.FirstOrDefault((string name) => string.Equals(name, "assets/codexbuild/mikulobbymotion.vmd.bytes", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/mikulobbymotion.vmd.bytes", StringComparison.OrdinalIgnoreCase) || name.EndsWith(".vmd.bytes", StringComparison.OrdinalIgnoreCase)); if (string.IsNullOrWhiteSpace(text)) { return null; } TextAsset val = assetBundle.LoadAsset(text); if ((Object)(object)val == (Object)null || val.bytes == null || val.bytes.Length == 0) { logger.LogWarning((object)("The bundle contains runtime VMD asset entry '" + text + "', but it could not be loaded as non-empty bytes.")); return null; } LogVerbose(logger, $"Loaded runtime VMD bytes '{text}', bytes={val.bytes.Length}."); return val; } private static AnimationClip? BuildRuntimeVmdClip(GameObject templateRoot, byte[] vmdBytes, ManualLogSource logger) { if (vmdBytes != null && vmdBytes.Length != 0) { logger.LogWarning((object)"The bundle contains runtime VMD bytes, but runtime VMD decoding is disabled in the Thunderstore build. Use a pre-baked AnimationClip in the Unity bundle instead."); } return null; } private static DancePlaybackMetadata? LoadPreferredPlaybackMetadata(AssetBundle assetBundle, string[] assetNames, ManualLogSource logger) { string text = assetNames.FirstOrDefault((string name) => string.Equals(name, "assets/codexbuild/mikulobbyplayback.json", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/mikulobbyplayback.json", StringComparison.OrdinalIgnoreCase) || name.EndsWith("/playback.json", StringComparison.OrdinalIgnoreCase)); if (string.IsNullOrWhiteSpace(text)) { return null; } TextAsset val = assetBundle.LoadAsset(text); if ((Object)(object)val == (Object)null || string.IsNullOrWhiteSpace(val.text)) { logger.LogWarning((object)("The bundle contains playback metadata '" + text + "', but it could not be loaded as a TextAsset.")); return null; } try { DancePlaybackMetadata dancePlaybackMetadata = JsonUtility.FromJson(val.text); if (dancePlaybackMetadata == null) { logger.LogWarning((object)("Failed to deserialize playback metadata '" + text + "' from the Unity bundle.")); return null; } LogVerbose(logger, "Loaded playback metadata '" + text + "' from the Unity bundle. " + $"startFrame={dancePlaybackMetadata.MotionStartFrame}, hasEndFrame={dancePlaybackMetadata.HasMotionEndFrame}, endFrame={dancePlaybackMetadata.MotionEndFrame}, " + $"audioStart={dancePlaybackMetadata.AudioSegmentStartSeconds:0.###}, audioDuration={dancePlaybackMetadata.AudioSegmentDurationSeconds:0.###}, " + $"frameRate={dancePlaybackMetadata.SourceFrameRate:0.###}."); return dancePlaybackMetadata; } catch (Exception ex) { logger.LogWarning((object)("Failed to parse playback metadata '" + text + "': " + ex.Message)); return null; } } private static int HasPlayableAnimation(GameObject candidate) { Animator componentInChildren = candidate.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.runtimeAnimatorController != (Object)null) { return 2; } if ((Object)(object)candidate.GetComponentInChildren(true) != (Object)null) { return 1; } return 0; } private static int CountRenderers(GameObject candidate) { return candidate.GetComponentsInChildren(true).Length; } private static void NormalizeRenderers(GameObject root, ManualLogSource logger) { Shader val = Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Texture") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Universal Render Pipeline/Simple Lit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Legacy Shaders/Diffuse"); Transform[] componentsInChildren = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.layer = 0; } Renderer[] componentsInChildren2 = root.GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren2) { val2.enabled = true; val2.shadowCastingMode = (ShadowCastingMode)1; val2.receiveShadows = true; val2.allowOcclusionWhenDynamic = true; val2.lightProbeUsage = (LightProbeUsage)1; val2.reflectionProbeUsage = (ReflectionProbeUsage)1; Material[] sharedMaterials = val2.sharedMaterials; int expectedMaterialCount = GetExpectedMaterialCount(val2); Material[] materials = AlignMaterialSlots(sharedMaterials, expectedMaterialCount); val2.sharedMaterials = NormalizeMaterials(val2, materials, val); LogVerbose(logger, "Renderer '" + ((Object)val2).name + "' normalized. type=" + ((object)val2).GetType().Name + ", " + $"mesh='{GetSharedMeshName(val2)}', subMeshes={expectedMaterialCount}, " + $"materialsBefore={sharedMaterials.Length}, materialsAfter={val2.sharedMaterials.Length}."); SkinnedMeshRenderer val3 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null); if (val3 != null) { val3.updateWhenOffscreen = true; } } LogVerbose(logger, "Normalized Unity bundle renderers. fallback shader='" + (((val != null) ? ((Object)val).name : null) ?? "(none)") + "'."); } private static void NormalizeAudioSources(GameObject root, ManualLogSource logger) { AudioSource[] componentsInChildren = root.GetComponentsInChildren(true); foreach (AudioSource val in componentsInChildren) { AudioClip val2 = ResolveAudioClip(val); if ((Object)(object)val2 != (Object)null && (Object)(object)val.clip == (Object)null) { val.clip = val2; } val.playOnAwake = false; val.loop = false; val.spatialBlend = 0f; val.dopplerLevel = 0f; string[] obj = new string[9] { "AudioSource '", ((Object)val).name, "' normalized. clip='", ((val2 != null) ? ((Object)val2).name : null) ?? "(none)", "', ", $"length={((val2 != null) ? val2.length : 0f):0.###}, volume={val.volume:0.###}, ", "resource='", null, null }; AudioResource resource = val.resource; obj[7] = ((resource != null) ? ((Object)resource).name : null) ?? "(none)"; obj[8] = "'."; LogVerbose(logger, string.Concat(obj)); } } private static void LogVerbose(ManualLogSource logger, string message) { if (VerboseLogState.Enabled) { logger.LogInfo((object)message); } } private static int GetExpectedMaterialCount(Renderer renderer) { SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (val != null && (Object)(object)val.sharedMesh != (Object)null) { return Mathf.Max(1, val.sharedMesh.subMeshCount); } MeshFilter val2 = default(MeshFilter); if (((Component)renderer).TryGetComponent(ref val2) && (Object)(object)val2.sharedMesh != (Object)null) { return Mathf.Max(1, val2.sharedMesh.subMeshCount); } return Mathf.Max(1, renderer.sharedMaterials.Length); } private static string GetSharedMeshName(Renderer renderer) { SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (val != null) { if (!((Object)(object)val.sharedMesh != (Object)null)) { return "(none)"; } return ((Object)val.sharedMesh).name; } MeshFilter val2 = default(MeshFilter); if (((Component)renderer).TryGetComponent(ref val2) && (Object)(object)val2.sharedMesh != (Object)null) { return ((Object)val2.sharedMesh).name; } return "(none)"; } private static Material[] AlignMaterialSlots(Material[] materials, int expectedMaterialCount) { if (expectedMaterialCount <= 0) { return Array.Empty(); } if (materials.Length == expectedMaterialCount && materials.All((Material material) => (Object)(object)material != (Object)null)) { return materials; } Material[] array = (Material[])(object)new Material[expectedMaterialCount]; Material val = ((IEnumerable)materials).LastOrDefault((Func)((Material material) => (Object)(object)material != (Object)null)); for (int num = 0; num < expectedMaterialCount; num++) { array[num] = (Material)((num < materials.Length && (Object)(object)materials[num] != (Object)null) ? ((object)materials[num]) : ((object)val)); } return array; } private static Material[] NormalizeMaterials(Renderer renderer, Material[] materials, Shader? fallbackShader) { if (materials.Length == 0) { return materials; } bool faceLikeRenderer = IsFaceLikeRenderer(renderer); Material[] array = (Material[])(object)new Material[materials.Length]; bool flag = false; for (int i = 0; i < materials.Length; i++) { Material val = materials[i]; if ((Object)(object)val != (Object)null && CanUseSourceShader(val)) { array[i] = val; continue; } if ((Object)(object)fallbackShader == (Object)null) { array[i] = val; continue; } array[i] = CreateCompatibleMaterial(renderer, val, fallbackShader, i, faceLikeRenderer); flag = true; } if (!flag) { return materials; } return array; } private static Material CreateCompatibleMaterial(Renderer renderer, Material? source, Shader fallbackShader, int index, bool faceLikeRenderer) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) if (CanUseSourceShader(source)) { return source; } Material val = new Material(ResolveCompatibleFallbackShader(source, fallbackShader)) { name = (((Object)(object)source != (Object)null) ? (((Object)source).name + "_Runtime") : $"RuntimeMaterial_{index}") }; TextureSlotInfo textureSlot = ReadFirstTextureSlot(source, TexturePropertyCandidates); if ((Object)(object)textureSlot.Texture == (Object)null) { textureSlot = ReadFallbackBaseTextureSlot(source); } TextureSlotInfo textureSlot2 = ReadFirstTextureSlot(source, NormalPropertyCandidates); TextureSlotInfo textureSlot3 = ReadFirstTextureSlot(source, EmissionPropertyCandidates); TextureSlotInfo textureSlot4 = ReadFirstTextureSlot(source, MetallicPropertyCandidates); TextureSlotInfo textureSlot5 = ReadFirstTextureSlot(source, OcclusionPropertyCandidates); Color val2 = ResolveCompatibleBaseColor((Color)(((??)ReadFirstColor(source, ColorPropertyCandidates)) ?? Color.white)); Texture texture = textureSlot.Texture; _ = textureSlot2.Texture; Texture texture2 = textureSlot3.Texture; _ = textureSlot4.Texture; _ = textureSlot5.Texture; float num = (((Object)(object)source != (Object)null && source.HasProperty("_Cutoff")) ? Mathf.Clamp01(source.GetFloat("_Cutoff")) : 0f); float num2 = (((Object)(object)source != (Object)null && source.HasProperty("_Smoothness")) ? Mathf.Clamp01(source.GetFloat("_Smoothness")) : (((Object)(object)source != (Object)null && source.HasProperty("_Glossiness")) ? Mathf.Clamp01(source.GetFloat("_Glossiness")) : 0f)); if ((Object)(object)source != (Object)null && source.HasProperty("_Metallic")) { Mathf.Clamp01(source.GetFloat("_Metallic")); } bool flag = IsEmissionEnabled(source, texture2); Color val3 = ((flag && !faceLikeRenderer) ? ClampColor((Color)(((??)TryReadColor(source, "_EmissionColor")) ?? Color.black), 1f) : Color.black); val.color = val2; if (val.HasProperty("_BaseColor")) { val.SetColor("_BaseColor", val2); } if (val.HasProperty("_Color")) { val.SetColor("_Color", val2); } CopyTexture(val, "_BaseMap", textureSlot); CopyTexture(val, "_MainTex", textureSlot); CopyTexture(val, "_BumpMap", textureSlot2); CopyTexture(val, "_EmissionMap", textureSlot3); CopyTexture(val, "_MetallicGlossMap", textureSlot4); CopyTexture(val, "_OcclusionMap", textureSlot5); if (val.HasProperty("_BumpScale")) { val.SetFloat("_BumpScale", ((Object)(object)source != (Object)null && source.HasProperty("_BumpScale")) ? source.GetFloat("_BumpScale") : 1f); } if (val.HasProperty("_Metallic")) { val.SetFloat("_Metallic", 0f); } if (val.HasProperty("_Smoothness")) { val.SetFloat("_Smoothness", Mathf.Min(num2, 0.15f)); } if (val.HasProperty("_Glossiness")) { val.SetFloat("_Glossiness", Mathf.Min(num2, 0.15f)); } if (val.HasProperty("_OcclusionStrength")) { val.SetFloat("_OcclusionStrength", 0f); } if (val.HasProperty("_Cutoff")) { val.SetFloat("_Cutoff", num); } if (val.HasProperty("_SpecularHighlights")) { val.SetFloat("_SpecularHighlights", 0f); } if (val.HasProperty("_EnvironmentReflections")) { val.SetFloat("_EnvironmentReflections", 0f); } if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", val3); if (flag && ((Object)(object)texture2 != (Object)null || ((Color)(ref val3)).maxColorComponent > 0.001f)) { val.EnableKeyword("_EMISSION"); } else { val.DisableKeyword("_EMISSION"); } } if (val.HasProperty("_Cull") && (Object)(object)source != (Object)null && source.HasProperty("_Cull")) { val.SetFloat("_Cull", source.GetFloat("_Cull")); } ConfigureSurfaceMode(val, source, texture, val2, num, faceLikeRenderer); EnableShadowSupport(val); return val; } private static Color ResolveCompatibleBaseColor(Color sourceColor) { //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 ClampColor(sourceColor, 1f); } private static Shader ResolveCompatibleFallbackShader(Material? source, Shader defaultFallbackShader) { string shaderName = (((Object)(object)((source != null) ? source.shader : null) != (Object)null) ? (((Object)source.shader).name ?? string.Empty) : string.Empty); if (!string.IsNullOrWhiteSpace(shaderName) && CustomToonShaderTokens.Any((string token) => shaderName.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0)) { return Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Universal Render Pipeline/Simple Lit") ?? Shader.Find("Standard") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Texture") ?? defaultFallbackShader; } return defaultFallbackShader; } private static void EnableShadowSupport(Material? material) { if (!((Object)(object)material == (Object)null)) { if (material.HasProperty("_ReceiveShadows")) { material.SetFloat("_ReceiveShadows", 1f); } if (material.HasProperty("_CastShadows")) { material.SetFloat("_CastShadows", 1f); } material.SetShaderPassEnabled("ShadowCaster", true); } } private static bool CanUseSourceShader(Material? source) { if ((Object)(object)source == (Object)null || (Object)(object)source.shader == (Object)null) { return false; } string text = ((Object)source.shader).name ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { return false; } if (text.IndexOf("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("FallbackError", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } try { return source.shader.isSupported; } catch { return false; } } private static Color? TryReadColor(Material? source, string propertyName) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || !source.HasProperty(propertyName)) { return null; } return source.GetColor(propertyName); } private static Color? ReadFirstColor(Material? source, IEnumerable propertyNames) { foreach (string propertyName in propertyNames) { Color? result = TryReadColor(source, propertyName); if (result.HasValue) { return result; } } return null; } private static TextureSlotInfo ReadFirstTextureSlot(Material? source, IEnumerable propertyNames) { //IL_003c: 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) if ((Object)(object)source == (Object)null) { return TextureSlotInfo.Empty; } foreach (string propertyName in propertyNames) { if (source.HasProperty(propertyName)) { Texture texture = source.GetTexture(propertyName); if ((Object)(object)texture != (Object)null) { return new TextureSlotInfo(texture, source.GetTextureScale(propertyName), source.GetTextureOffset(propertyName)); } } } return TextureSlotInfo.Empty; } private static TextureSlotInfo ReadFallbackBaseTextureSlot(Material? source) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { return TextureSlotInfo.Empty; } string[] texturePropertyNames = source.GetTexturePropertyNames(); foreach (string text in texturePropertyNames) { if (text.IndexOf("bump", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("normal", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("emission", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("occlusion", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("metal", StringComparison.OrdinalIgnoreCase) < 0) { Texture texture = source.GetTexture(text); if ((Object)(object)texture != (Object)null) { return new TextureSlotInfo(texture, source.GetTextureScale(text), source.GetTextureOffset(text)); } } } return TextureSlotInfo.Empty; } private static bool IsTransparentMaterial(Material? source, Color color) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (color.a < 0.999f) { return true; } if ((Object)(object)source == (Object)null) { return false; } if (source.renderQueue >= 3000) { return true; } if (source.HasProperty("_Surface") && source.GetFloat("_Surface") > 0.5f) { return true; } if (source.IsKeywordEnabled("_SURFACE_TYPE_TRANSPARENT")) { return true; } string shaderName = (((Object)(object)source.shader != (Object)null) ? (((Object)source.shader).name ?? string.Empty) : string.Empty); return TransparentTokens.Any((string token) => shaderName.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)source).name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0); } private static bool TextureHasAlpha(Texture? texture) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) Texture2D val = (Texture2D)(object)((texture is Texture2D) ? texture : null); if (val == null) { return false; } string text = ((object)val.format/*cast due to .constrained prefix*/).ToString(); if (text.IndexOf("RGBA", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("ARGB", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("BGRA", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Alpha", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("DXT5", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("BC7", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("ETC2_RGBA", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("ASTC_RGBA", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static void ConfigureSurfaceMode(Material material, Material? source, Texture? baseTexture, Color baseColor, float cutoff, bool faceLikeRenderer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) bool num = IsTransparentMaterial(source, baseColor); bool flag = TextureHasAlpha(baseTexture); bool flag2 = cutoff > 0.001f || (flag && IsLikelyDecalMaterial(source, faceLikeRenderer)); if (num) { ConfigureTransparentMaterial(material, source); return; } if (flag2) { ConfigureAlphaClipMaterial(material, source); return; } if (material.HasProperty("_Surface")) { material.SetFloat("_Surface", 0f); } if (material.HasProperty("_AlphaClip")) { material.SetFloat("_AlphaClip", 0f); } if (material.HasProperty("_Cutoff")) { material.SetFloat("_Cutoff", 0f); } if (material.HasProperty("_SrcBlend")) { material.SetInt("_SrcBlend", 1); } if (material.HasProperty("_DstBlend")) { material.SetInt("_DstBlend", 0); } if (material.HasProperty("_ZWrite")) { material.SetInt("_ZWrite", 1); } material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.DisableKeyword("_ALPHATEST_ON"); material.renderQueue = 2000; } private static void ConfigureAlphaClipMaterial(Material material, Material? source) { if (material.HasProperty("_Surface")) { material.SetFloat("_Surface", 0f); } if (material.HasProperty("_AlphaClip")) { material.SetFloat("_AlphaClip", 1f); } if (material.HasProperty("_Cutoff")) { material.SetFloat("_Cutoff", ((Object)(object)source != (Object)null && source.HasProperty("_Cutoff")) ? source.GetFloat("_Cutoff") : 0.5f); } if (material.HasProperty("_SrcBlend")) { material.SetInt("_SrcBlend", 1); } if (material.HasProperty("_DstBlend")) { material.SetInt("_DstBlend", 0); } if (material.HasProperty("_ZWrite")) { material.SetInt("_ZWrite", 1); } material.EnableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.renderQueue = 2450; } private static void ConfigureTransparentMaterial(Material material, Material? source) { if (material.HasProperty("_Surface")) { material.SetFloat("_Surface", 1f); } if (material.HasProperty("_Blend")) { material.SetFloat("_Blend", 0f); } if (material.HasProperty("_SrcBlend")) { material.SetInt("_SrcBlend", 5); } if (material.HasProperty("_DstBlend")) { material.SetInt("_DstBlend", 10); } if (material.HasProperty("_ZWrite")) { material.SetInt("_ZWrite", 0); } if ((Object)(object)source != (Object)null && source.HasProperty("_Cutoff") && source.GetFloat("_Cutoff") > 0.001f) { if (material.HasProperty("_AlphaClip")) { material.SetFloat("_AlphaClip", 1f); } if (material.HasProperty("_Cutoff")) { material.SetFloat("_Cutoff", source.GetFloat("_Cutoff")); } } else if (material.HasProperty("_AlphaClip")) { material.SetFloat("_AlphaClip", 0f); } material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.DisableKeyword("_ALPHATEST_ON"); material.renderQueue = 3000; } private static bool IsLikelyDecalMaterial(Material? source, bool faceLikeRenderer) { if (faceLikeRenderer) { return true; } if ((Object)(object)source == (Object)null) { return false; } return FaceLikeTokens.Any((string token) => ((Object)source).name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0); } private static bool IsFaceLikeRenderer(Renderer renderer) { string path = BuildRendererPath(((Component)renderer).transform, ((Component)renderer).transform.root); return FaceLikeTokens.Any((string token) => ((Object)renderer).name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0); } private static string BuildRendererPath(Transform current, Transform root) { Stack stack = new Stack(); Transform val = current; while ((Object)(object)val != (Object)null) { stack.Push(((Object)val).name); if ((Object)(object)val == (Object)(object)root) { break; } val = val.parent; } return string.Join("/", stack); } private static void CopyTexture(Material target, string targetPropertyName, TextureSlotInfo textureSlot) { //IL_002b: 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) if (!((Object)(object)textureSlot.Texture == (Object)null) && target.HasProperty(targetPropertyName)) { target.SetTexture(targetPropertyName, textureSlot.Texture); target.SetTextureScale(targetPropertyName, textureSlot.Scale); target.SetTextureOffset(targetPropertyName, textureSlot.Offset); } } private static bool IsEmissionEnabled(Material? source, Texture? emissionTexture) { if ((Object)(object)emissionTexture != (Object)null) { return true; } if ((Object)(object)source == (Object)null) { return false; } string[] emissionTogglePropertyCandidates = EmissionTogglePropertyCandidates; foreach (string text in emissionTogglePropertyCandidates) { if (source.HasProperty(text) && source.GetFloat(text) > 0.5f) { return true; } } return source.IsKeywordEnabled("_EMISSION"); } private static Color ClampColor(Color color, float maxChannel) { //IL_000d: 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_002f: 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_004b: Unknown result type (might be due to invalid IL or missing references) maxChannel = Mathf.Max(0f, maxChannel); return new Color(Mathf.Clamp(color.r, 0f, maxChannel), Mathf.Clamp(color.g, 0f, maxChannel), Mathf.Clamp(color.b, 0f, maxChannel), Mathf.Clamp01(color.a)); } private static Bounds CalculateRendererBounds(GameObject root) { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0042: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = root.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return new Bounds(Vector3.zero, Vector3.zero); } Bounds bounds = componentsInChildren[0].bounds; for (int i = 1; i < componentsInChildren.Length; i++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[i].bounds); } return bounds; } private static void ValidateFile(string path) { if (!File.Exists(path)) { throw new FileNotFoundException("Required Unity asset bundle file was not found.", path); } } 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); } } } namespace MikuDanceProject.Core { internal enum DanceConfigKey { ModEnabled, EnableAudio, AudioVolume, AudioRangeMeters, StabilizeModelLighting, LightingExposureCompensation, ModelScale, SpawnModelKey, HairColorEnabled, HairColorR, HairColorG, HairColorB, ClothColorEnabled, ClothColorR, ClothColorG, ClothColorB, RandomizeColors, EnableVerboseLogs } internal sealed class LocalizedConfigEntry { public DanceConfigKey Key { get; } public ConfigEntryBase Entry { get; } public LocalizedConfigEntry(DanceConfigKey key, ConfigEntryBase entry) { Key = key; Entry = entry; } } internal static class DanceConfigLocalization { private const int SimplifiedChineseLanguageIndex = 9; private const string SettingsSection = "Settings"; private const string LocalizedSettingsSection = "设置"; private const string LegacyInternalSection = "Internal"; private const string LegacySavedAirportPlacementKey = "SavedAirportPlacement"; private static readonly BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public static bool DetectChineseLanguage() { bool isChineseLanguage; bool num = TryGetConfiguredGameLanguage(out isChineseLanguage); string languageName; bool flag = TryGetLocalizedTextLanguageName(out languageName); if (num) { return isChineseLanguage; } if (flag) { return IsChineseLanguageName(languageName); } if (!CultureInfo.CurrentUICulture.Name.StartsWith("zh", StringComparison.OrdinalIgnoreCase) && !CultureInfo.CurrentCulture.Name.StartsWith("zh", StringComparison.OrdinalIgnoreCase) && TimeZoneInfo.Local.Id.IndexOf("China", StringComparison.OrdinalIgnoreCase) < 0) { return TimeZoneInfo.Local.Id.IndexOf("Shanghai", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } public static string BuildLanguageDetectionSummary(bool isChineseLanguage) { bool isChineseLanguage2; string languageValueText; string text = (TryGetConfiguredGameLanguage(out isChineseLanguage2, out languageValueText) ? (languageValueText + "/" + (isChineseLanguage2 ? "Chinese" : "English")) : "unknown"); string languageName; string text2 = (TryGetLocalizedTextLanguageName(out languageName) ? languageName : "unknown"); return (isChineseLanguage ? "Chinese" : "English") + " (prefs=" + text + ", runtime=" + text2 + ")"; } public static string GetSectionName(bool isChineseLanguage) { if (!isChineseLanguage) { return "Settings"; } return "设置"; } public static string GetSavedAirportPlacementKeyName(bool isChineseLanguage) { if (!isChineseLanguage) { return "Saved Airport Placement"; } return "保存的机场展示位置"; } public static string GetSavedAirportPlacementDescription(bool isChineseLanguage) { if (!isChineseLanguage) { return "Internal serialized Airport showcase placement. Managed automatically by the plugin."; } return "内部使用的机场展示位置。插件会自动管理这个值。"; } public static string GetKeyName(DanceConfigKey configKey, bool isChineseLanguage) { if (isChineseLanguage) { switch (configKey) { case DanceConfigKey.ModEnabled: return "启用 Miku 展示"; case DanceConfigKey.EnableAudio: return "启用音乐"; case DanceConfigKey.AudioVolume: return "音乐音量"; case DanceConfigKey.AudioRangeMeters: return "音乐可听范围"; case DanceConfigKey.StabilizeModelLighting: return "稳定模型光照"; case DanceConfigKey.LightingExposureCompensation: return "肤色亮度"; case DanceConfigKey.ModelScale: return "模型大小"; case DanceConfigKey.SpawnModelKey: return "移动模型按键"; case DanceConfigKey.HairColorEnabled: return "启用头发颜色"; case DanceConfigKey.HairColorR: return "头发颜色 R"; case DanceConfigKey.HairColorG: return "头发颜色 G"; case DanceConfigKey.HairColorB: return "头发颜色 B"; case DanceConfigKey.ClothColorEnabled: return "启用服装颜色"; case DanceConfigKey.ClothColorR: return "服装颜色 R"; case DanceConfigKey.ClothColorG: return "服装颜色 G"; case DanceConfigKey.ClothColorB: return "服装颜色 B"; case DanceConfigKey.RandomizeColors: return "随机颜色"; case DanceConfigKey.EnableVerboseLogs: return "调试日志"; } } return configKey switch { DanceConfigKey.ModEnabled => "Enable Miku Showcase", DanceConfigKey.EnableAudio => "Enable Audio", DanceConfigKey.AudioVolume => "Audio Volume", DanceConfigKey.AudioRangeMeters => "Audio Range Meters", DanceConfigKey.StabilizeModelLighting => "Stabilize Model Lighting", DanceConfigKey.LightingExposureCompensation => "Skin Tone Brightness", DanceConfigKey.ModelScale => "Model Scale", DanceConfigKey.SpawnModelKey => "Spawn Model Key", DanceConfigKey.HairColorEnabled => "Hair Color Enabled", DanceConfigKey.HairColorR => "Hair Color R", DanceConfigKey.HairColorG => "Hair Color G", DanceConfigKey.HairColorB => "Hair Color B", DanceConfigKey.ClothColorEnabled => "Cloth Color Enabled", DanceConfigKey.ClothColorR => "Cloth Color R", DanceConfigKey.ClothColorG => "Cloth Color G", DanceConfigKey.ClothColorB => "Cloth Color B", DanceConfigKey.RandomizeColors => "Randomize Colors", DanceConfigKey.EnableVerboseLogs => "Verbose Logs", _ => string.Empty, }; } public static string GetDescription(DanceConfigKey configKey, bool isChineseLanguage) { if (isChineseLanguage) { switch (configKey) { case DanceConfigKey.ModEnabled: return "总开关。关闭后插件仍会加载,但不会生成或移动展示模型。"; case DanceConfigKey.EnableAudio: return "是否播放随展示模型一起打包的音乐。"; case DanceConfigKey.AudioVolume: return "打包音乐源使用的音量,范围 0 到 1。"; case DanceConfigKey.AudioRangeMeters: return "打包音乐源的最大可听距离,单位为米。"; case DanceConfigKey.StabilizeModelLighting: return "开启后会调整运行时材质,降低强光环境下模型过曝发白。"; case DanceConfigKey.LightingExposureCompensation: return "皮肤与脸部的亮度倍率。数值越低,肤色越暗;数值越高,肤色越亮。"; case DanceConfigKey.ModelScale: return "生成展示模型时使用的统一缩放倍率。"; case DanceConfigKey.SpawnModelKey: return "轻按此键会把模型移动到本地玩家附近的地面位置。在机场大厅按住 3 秒,会把大厅展示位置保存到配置文件供下次启动使用。"; case DanceConfigKey.HairColorEnabled: return "开启后用下方 RGB 滑块覆盖头发颜色(与原纹理相乘叠加)。关闭则使用模型原始颜色。"; case DanceConfigKey.HairColorR: return "头发颜色红色通道,范围 0 到 1。"; case DanceConfigKey.HairColorG: return "头发颜色绿色通道,范围 0 到 1。"; case DanceConfigKey.HairColorB: return "头发颜色蓝色通道,范围 0 到 1。"; case DanceConfigKey.ClothColorEnabled: return "开启后用下方 RGB 滑块覆盖服装颜色(与原纹理相乘叠加)。关闭则使用模型原始颜色。"; case DanceConfigKey.ClothColorR: return "服装颜色红色通道,范围 0 到 1。"; case DanceConfigKey.ClothColorG: return "服装颜色绿色通道,范围 0 到 1。"; case DanceConfigKey.ClothColorB: return "服装颜色蓝色通道,范围 0 到 1。"; case DanceConfigKey.RandomizeColors: return "开启后,每次生成模型时随机生成头发与服装颜色(覆盖下方 RGB 滑块的值)。每次按键生成颜色都不同。默认关闭。"; case DanceConfigKey.EnableVerboseLogs: return "开启后输出详细调试日志(资源加载、材质、动画同步等)。默认关闭,仅在排查问题时开启。"; } } return configKey switch { DanceConfigKey.ModEnabled => "Master switch. When disabled, the plugin stays loaded but will not spawn or move the display model.", DanceConfigKey.EnableAudio => "Whether the display model plays the bundled audio track.", DanceConfigKey.AudioVolume => "Audio volume applied to the bundled audio source. Range: 0 to 1.", DanceConfigKey.AudioRangeMeters => "Maximum audible range for the bundled audio source, in meters.", DanceConfigKey.StabilizeModelLighting => "When enabled, runtime materials are tuned to reduce over-bright scene lighting on the bundled model.", DanceConfigKey.LightingExposureCompensation => "Brightness multiplier for skin and face materials. Lower values darken the skin tone; higher values brighten it.", DanceConfigKey.ModelScale => "Uniform scale applied to the spawned display model.", DanceConfigKey.SpawnModelKey => "Tap this key to move the model to the local player's grounded position. Hold it for 3 seconds in the Airport lobby to save the lobby showcase position into this config file for future launches.", DanceConfigKey.HairColorEnabled => "When enabled, the RGB sliders below override the hair color (multiplied with the original texture). When disabled, the model's original color is used.", DanceConfigKey.HairColorR => "Hair color red channel, range 0 to 1.", DanceConfigKey.HairColorG => "Hair color green channel, range 0 to 1.", DanceConfigKey.HairColorB => "Hair color blue channel, range 0 to 1.", DanceConfigKey.ClothColorEnabled => "When enabled, the RGB sliders below override the cloth color (multiplied with the original texture). When disabled, the model's original color is used.", DanceConfigKey.ClothColorR => "Cloth color red channel, range 0 to 1.", DanceConfigKey.ClothColorG => "Cloth color green channel, range 0 to 1.", DanceConfigKey.ClothColorB => "Cloth color blue channel, 0 to 1.", DanceConfigKey.RandomizeColors => "When enabled, randomizes hair and cloth colors each time the model spawns (overrides the RGB sliders below). Each spawn produces different colors. Disabled by default.", DanceConfigKey.EnableVerboseLogs => "When enabled, emits verbose debug logs (asset loading, materials, animation sync, etc.). Off by default; turn on only when troubleshooting.", _ => string.Empty, }; } public static bool TryGetConfigKey(string keyName, out DanceConfigKey configKey) { foreach (DanceConfigKey value in Enum.GetValues(typeof(DanceConfigKey))) { if (IsConfigKeyName(keyName, value)) { configKey = value; return true; } } configKey = DanceConfigKey.ModEnabled; return false; } public static bool TryGetLocalizedSectionName(string sectionName, bool isChineseLanguage, out string localizedSectionName) { if (string.Equals(sectionName, "Settings", StringComparison.OrdinalIgnoreCase) || string.Equals(sectionName, "设置", StringComparison.Ordinal) || string.Equals(sectionName, "Internal", StringComparison.OrdinalIgnoreCase)) { localizedSectionName = GetSectionName(isChineseLanguage); return true; } localizedSectionName = string.Empty; return false; } public static void ApplyLocalizedDescriptions(ConfigFile configFile, bool isChineseLanguage) { ConfigEntryBase[] configEntriesSnapshot = GetConfigEntriesSnapshot(configFile); foreach (ConfigEntryBase val in configEntriesSnapshot) { if (val != null && !(val.Definition == (ConfigDefinition)null) && val.Description != null && TryGetConfigKey(val.Definition.Key, out var configKey)) { SetPrivateField(val.Description, "k__BackingField", GetDescription(configKey, isChineseLanguage)); } } } public static void RewriteConfigFileLocalization(string configFilePath, bool isChineseLanguage) { if (!string.IsNullOrWhiteSpace(configFilePath) && File.Exists(configFilePath)) { string[] array = File.ReadAllLines(configFilePath); string[] array2 = new string[array.Length]; bool flag = false; for (int i = 0; i < array.Length; i++) { string text = array[i] ?? string.Empty; flag |= !string.Equals(text, array2[i] = RewriteConfigFileLine(text, isChineseLanguage), StringComparison.Ordinal); } if (flag) { File.WriteAllLines(configFilePath, array2); } } } public static void MigrateLocalizedConfigEntries(ConfigFile configFile, IEnumerable visibleEntries) { IDictionary orphanedEntries = GetOrphanedEntries(configFile); if (orphanedEntries == null || orphanedEntries.Count == 0) { return; } bool flag = false; foreach (LocalizedConfigEntry visibleEntry in visibleEntries) { flag |= TryMigrateLocalizedConfigValue(visibleEntry.Entry, visibleEntry.Key, orphanedEntries); } if (flag) { configFile.Save(); } } public static void MigrateSavedAirportPlacement(ConfigFile configFile, ConfigEntryBase savedAirportPlacementEntry) { IDictionary orphanedEntries = GetOrphanedEntries(configFile); if (orphanedEntries == null || savedAirportPlacementEntry == null) { return; } foreach (ConfigDefinition savedAirportPlacementAliasDefinition in GetSavedAirportPlacementAliasDefinitions()) { if (!DefinitionsEqual(savedAirportPlacementAliasDefinition, savedAirportPlacementEntry.Definition) && orphanedEntries.Contains(savedAirportPlacementAliasDefinition)) { object obj = orphanedEntries[savedAirportPlacementAliasDefinition]; if (obj != null && string.IsNullOrWhiteSpace(savedAirportPlacementEntry.GetSerializedValue())) { savedAirportPlacementEntry.SetSerializedValue(obj.ToString()); } orphanedEntries.Remove(savedAirportPlacementAliasDefinition); } } } public static Dictionary BuildUiLocalizationMap(bool isChineseLanguage) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); AddUiLocalizationPair(dictionary, "MikuShowcase", GetLocalizedModDisplayName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "com.github.Thanks.MikuDance", GetLocalizedModDisplayName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "Settings", GetSectionName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "设置", GetSectionName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "Internal", GetSectionName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "SavedAirportPlacement", GetSavedAirportPlacementKeyName(isChineseLanguage)); AddUiLocalizationPair(dictionary, GetSavedAirportPlacementKeyName(isChineseLanguage: false), GetSavedAirportPlacementKeyName(isChineseLanguage)); AddUiLocalizationPair(dictionary, GetSavedAirportPlacementKeyName(isChineseLanguage: true), GetSavedAirportPlacementKeyName(isChineseLanguage)); foreach (DanceConfigKey value in Enum.GetValues(typeof(DanceConfigKey))) { string sectionName = GetSectionName(isChineseLanguage); string keyName = GetKeyName(value, isChineseLanguage); AddUiLocalizationPair(dictionary, "Settings", sectionName); AddUiLocalizationPair(dictionary, "设置", sectionName); AddUiLocalizationPair(dictionary, GetKeyName(value, isChineseLanguage: false), keyName); AddUiLocalizationPair(dictionary, ToReadableName(GetKeyName(value, isChineseLanguage: false)), keyName); AddUiLocalizationPair(dictionary, GetKeyName(value, isChineseLanguage: true), keyName); AddUiLocalizationPair(dictionary, GetLegacyKeyName(value), keyName); AddUiLocalizationPair(dictionary, ToReadableName(GetLegacyKeyName(value)), keyName); AddUiLocalizationPair(dictionary, GetDescription(value, isChineseLanguage: false), GetDescription(value, isChineseLanguage)); AddUiLocalizationPair(dictionary, GetDescription(value, isChineseLanguage: true), GetDescription(value, isChineseLanguage)); } return dictionary; } private static string RewriteConfigFileLine(string line, bool isChineseLanguage) { if (string.IsNullOrWhiteSpace(line)) { return line ?? string.Empty; } string text = line.Trim(); if (text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal)) { if (!TryGetLocalizedSectionName(text.Substring(1, text.Length - 2).Trim(), isChineseLanguage, out string localizedSectionName)) { return line; } int num = line.IndexOf('['); int num2 = line.LastIndexOf(']'); if (num >= 0 && num2 >= num) { return line.Substring(0, num + 1) + localizedSectionName + line.Substring(num2); } return line; } if (!TrySplitConfigSettingLine(line, out string leading, out string keyName, out string separatorAndValue) || (!TryGetConfigKey(keyName, out var configKey) && !IsSavedAirportPlacementKeyName(keyName))) { return line; } if (IsSavedAirportPlacementKeyName(keyName)) { return leading + GetSavedAirportPlacementKeyName(isChineseLanguage) + separatorAndValue; } return leading + GetKeyName(configKey, isChineseLanguage) + separatorAndValue; } private static bool TrySplitConfigSettingLine(string line, out string leading, out string keyName, out string separatorAndValue) { leading = string.Empty; keyName = string.Empty; separatorAndValue = string.Empty; if (string.IsNullOrWhiteSpace(line)) { return false; } string text = line.TrimStart(Array.Empty()); if (text.StartsWith("#", StringComparison.Ordinal) || text.StartsWith(";", StringComparison.Ordinal)) { return false; } int num = line.IndexOf('='); if (num <= 0) { return false; } int i; for (i = 0; i < num && char.IsWhiteSpace(line[i]); i++) { } int num2 = num - 1; while (num2 >= i && char.IsWhiteSpace(line[num2])) { num2--; } if (num2 < i) { return false; } leading = line.Substring(0, i); keyName = line.Substring(i, num2 - i + 1); separatorAndValue = line.Substring(num2 + 1); return true; } private static bool TryMigrateLocalizedConfigValue(ConfigEntryBase entry, DanceConfigKey configKey, IDictionary orphanedEntries) { if (entry == null || entry.Definition == (ConfigDefinition)null || orphanedEntries == null) { return false; } bool flag = false; foreach (ConfigDefinition aliasDefinition in GetAliasDefinitions(configKey)) { if (DefinitionsEqual(aliasDefinition, entry.Definition) || !orphanedEntries.Contains(aliasDefinition)) { continue; } if (!flag) { object obj = orphanedEntries[aliasDefinition]; if (obj != null) { entry.SetSerializedValue(obj.ToString()); } flag = true; } orphanedEntries.Remove(aliasDefinition); } return flag; } private static IEnumerable GetAliasDefinitions(DanceConfigKey configKey) { string[] array = new string[2] { "Settings", "设置" }; string[] keys = new string[3] { GetKeyName(configKey, isChineseLanguage: false), GetKeyName(configKey, isChineseLanguage: true), GetLegacyKeyName(configKey) }; string[] array2 = array; foreach (string section in array2) { string[] array3 = keys; foreach (string text in array3) { if (!string.IsNullOrWhiteSpace(text)) { yield return new ConfigDefinition(section, text); } } } } private static IEnumerable GetSavedAirportPlacementAliasDefinitions() { string[] array = new string[3] { "Settings", "设置", "Internal" }; string[] keys = new string[3] { "SavedAirportPlacement", GetSavedAirportPlacementKeyName(isChineseLanguage: false), GetSavedAirportPlacementKeyName(isChineseLanguage: true) }; string[] array2 = array; foreach (string section in array2) { string[] array3 = keys; foreach (string text in array3) { if (!string.IsNullOrWhiteSpace(text)) { yield return new ConfigDefinition(section, text); } } } } private static bool IsConfigKeyName(string keyName, DanceConfigKey configKey) { if (!string.Equals(keyName, GetKeyName(configKey, isChineseLanguage: false), StringComparison.OrdinalIgnoreCase) && !string.Equals(keyName, GetKeyName(configKey, isChineseLanguage: true), StringComparison.Ordinal)) { return string.Equals(keyName, GetLegacyKeyName(configKey), StringComparison.OrdinalIgnoreCase); } return true; } private static bool IsSavedAirportPlacementKeyName(string keyName) { if (!string.Equals(keyName, "SavedAirportPlacement", StringComparison.OrdinalIgnoreCase) && !string.Equals(keyName, GetSavedAirportPlacementKeyName(isChineseLanguage: false), StringComparison.OrdinalIgnoreCase)) { return string.Equals(keyName, GetSavedAirportPlacementKeyName(isChineseLanguage: true), StringComparison.Ordinal); } return true; } private static string GetLegacyKeyName(DanceConfigKey configKey) { return configKey switch { DanceConfigKey.ModEnabled => "ModEnabled", DanceConfigKey.EnableAudio => "EnableAudio", DanceConfigKey.AudioVolume => "AudioVolume", DanceConfigKey.AudioRangeMeters => "AudioRangeMeters", DanceConfigKey.StabilizeModelLighting => "StabilizeModelLighting", DanceConfigKey.LightingExposureCompensation => "LightingExposureCompensation", DanceConfigKey.ModelScale => "ModelScale", DanceConfigKey.SpawnModelKey => "SpawnModelKey", DanceConfigKey.HairColorEnabled => "HairColorEnabled", DanceConfigKey.HairColorR => "HairColorR", DanceConfigKey.HairColorG => "HairColorG", DanceConfigKey.HairColorB => "HairColorB", DanceConfigKey.ClothColorEnabled => "ClothColorEnabled", DanceConfigKey.ClothColorR => "ClothColorR", DanceConfigKey.ClothColorG => "ClothColorG", DanceConfigKey.ClothColorB => "ClothColorB", DanceConfigKey.EnableVerboseLogs => "EnableVerboseLogs", _ => string.Empty, }; } private static bool TryGetConfiguredGameLanguage(out bool isChineseLanguage) { string languageValueText; return TryGetConfiguredGameLanguage(out isChineseLanguage, out languageValueText); } private static bool TryGetConfiguredGameLanguage(out bool isChineseLanguage, out string languageValueText) { isChineseLanguage = false; languageValueText = string.Empty; try { if (!PlayerPrefs.HasKey("LanguageSetting")) { return false; } int result = PlayerPrefs.GetInt("LanguageSetting", int.MinValue); if (result != int.MinValue) { languageValueText = result.ToString(CultureInfo.InvariantCulture); isChineseLanguage = IsChineseLanguageIndex(result); return true; } string text = (languageValueText = PlayerPrefs.GetString("LanguageSetting", string.Empty)); if (string.IsNullOrWhiteSpace(text)) { return false; } if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) { isChineseLanguage = IsChineseLanguageIndex(result); return true; } isChineseLanguage = IsChineseLanguageName(text); return true; } catch { return false; } } private static bool TryGetLocalizedTextLanguageName(out string languageName) { languageName = string.Empty; try { languageName = ((object)Unsafe.As(ref LocalizedText.CURRENT_LANGUAGE)/*cast due to .constrained prefix*/).ToString(); return !string.IsNullOrWhiteSpace(languageName); } catch { return false; } } private static bool IsChineseLanguageName(string languageName) { if (string.IsNullOrWhiteSpace(languageName)) { return false; } if (int.TryParse(languageName.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return IsChineseLanguageIndex(result); } if (languageName.IndexOf("Chinese", StringComparison.OrdinalIgnoreCase) < 0 && languageName.IndexOf("中文", StringComparison.OrdinalIgnoreCase) < 0) { return languageName.StartsWith("zh", StringComparison.OrdinalIgnoreCase); } return true; } private static bool IsChineseLanguageIndex(int languageValue) { if (languageValue != 9) { return languageValue == 10; } return true; } private static ConfigEntryBase[] GetConfigEntriesSnapshot(ConfigFile configFile) { PropertyInfo property = typeof(ConfigFile).GetProperty("Entries", InstanceFlags); if (configFile == null || !(property?.GetValue(configFile) is IDictionary { Count: not 0 } dictionary)) { return Array.Empty(); } List list = new List(); foreach (DictionaryEntry item in dictionary) { object? value = item.Value; ConfigEntryBase val = (ConfigEntryBase)((value is ConfigEntryBase) ? value : null); if (val != null) { list.Add(val); } } return list.ToArray(); } private static IDictionary? GetOrphanedEntries(ConfigFile configFile) { return ((object)configFile)?.GetType().GetProperty("OrphanedEntries", InstanceFlags)?.GetValue(configFile) as IDictionary; } private static bool DefinitionsEqual(ConfigDefinition left, ConfigDefinition right) { if (string.Equals((left != null) ? left.Section : null, (right != null) ? right.Section : null, StringComparison.Ordinal)) { return string.Equals((left != null) ? left.Key : null, (right != null) ? right.Key : null, StringComparison.Ordinal); } return false; } private static void SetPrivateField(object target, string fieldName, object value) { if (target != null && !string.IsNullOrWhiteSpace(fieldName)) { target.GetType().GetField(fieldName, InstanceFlags)?.SetValue(target, value); } } private static void AddUiLocalizationPair(Dictionary map, string source, string localized) { if (map != null && !string.IsNullOrWhiteSpace(source) && !string.IsNullOrWhiteSpace(localized)) { string text = source.Trim(); string text2 = (map[text] = localized.Trim()); map[text2] = text2; string key = text.Replace(" ", string.Empty); string key2 = text2.Replace(" ", string.Empty); if (!map.ContainsKey(key)) { map[key] = text2; } if (!map.ContainsKey(key2)) { map[key2] = text2; } map[text.ToUpperInvariant()] = text2; map[text2.ToUpperInvariant()] = text2; } } private static string ToReadableName(string keyName) { if (string.IsNullOrWhiteSpace(keyName)) { return string.Empty; } List list = new List(keyName.Length + 8); for (int i = 0; i < keyName.Length; i++) { char c = keyName[i]; if (i > 0 && char.IsUpper(c) && !char.IsWhiteSpace(keyName[i - 1]) && !char.IsUpper(keyName[i - 1])) { list.Add(' '); } list.Add(c); } return new string(list.ToArray()); } private static string GetLocalizedModDisplayName(bool isChineseLanguage) { if (!isChineseLanguage) { return "MikuShowcase"; } return "Miku 展示"; } } internal sealed class DancePluginConfig { private readonly string _pluginDirectory; private readonly ConfigFile _configFile; private readonly ConfigEntry _savedAirportPlacement; private readonly List _visibleEntries = new List(); private Color _randomHairColor = Color.white; private Color _randomClothColor = Color.white; private static readonly Color[] HairColorPalette = (Color[])(object)new Color[10] { new Color(0.05f, 0.85f, 0.82f, 1f), new Color(0.1f, 0.55f, 0.9f, 1f), new Color(0.25f, 0.4f, 0.95f, 1f), new Color(0.55f, 0.35f, 0.9f, 1f), new Color(0.85f, 0.4f, 0.75f, 1f), new Color(0.9f, 0.6f, 0.85f, 1f), new Color(0.75f, 0.85f, 0.95f, 1f), new Color(0.3f, 0.85f, 0.7f, 1f), new Color(0.95f, 0.8f, 0.4f, 1f), new Color(0.8f, 0.3f, 0.55f, 1f) }; private static readonly Color[] ClothColorPalette = (Color[])(object)new Color[10] { new Color(0.05f, 0.05f, 0.08f, 1f), new Color(0.95f, 0.95f, 0.95f, 1f), new Color(0.8f, 0.1f, 0.15f, 1f), new Color(0.1f, 0.35f, 0.85f, 1f), new Color(0.85f, 0.45f, 0.65f, 1f), new Color(0.4f, 0.2f, 0.65f, 1f), new Color(0.15f, 0.55f, 0.45f, 1f), new Color(0.9f, 0.75f, 0.2f, 1f), new Color(0.25f, 0.25f, 0.3f, 1f), new Color(0.95f, 0.55f, 0.15f, 1f) }; public ConfigEntry ModEnabled { get; } public ConfigEntry EnableAudio { get; } public ConfigEntry AudioVolume { get; } public ConfigEntry AudioRangeMeters { get; } public ConfigEntry StabilizeModelLighting { get; } public ConfigEntry LightingExposureCompensation { get; } public ConfigEntry ModelScale { get; } public ConfigEntry SpawnModelKey { get; } public ConfigEntry HairColorEnabled { get; } public ConfigEntry HairColorR { get; } public ConfigEntry HairColorG { get; } public ConfigEntry HairColorB { get; } public ConfigEntry ClothColorEnabled { get; } public ConfigEntry ClothColorR { get; } public ConfigEntry ClothColorG { get; } public ConfigEntry ClothColorB { get; } public ConfigEntry RandomizeColors { get; } public ConfigEntry EnableVerboseLogs { get; } public bool IsChineseLanguage { get; private set; } public IReadOnlyList VisibleEntries => _visibleEntries; public float ResolvedModelScale => Mathf.Clamp(ModelScale.Value, 0.1f, 3f); public float ResolvedAudioVolume => Mathf.Clamp01(AudioVolume.Value); public float ResolvedAudioRangeMeters => Mathf.Clamp(AudioRangeMeters.Value, 1f, 30f); public float ResolvedLightingExposureCompensation => Mathf.Clamp(LightingExposureCompensation.Value, 0.4f, 1f); public DancePluginConfig(ConfigFile config, string pluginDirectory) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) _configFile = config; _pluginDirectory = Path.GetFullPath(pluginDirectory); IsChineseLanguage = DanceConfigLocalization.DetectChineseLanguage(); ModEnabled = BindEntry(DanceConfigKey.ModEnabled, defaultValue: true, null); EnableAudio = BindEntry(DanceConfigKey.EnableAudio, defaultValue: true, null); AudioVolume = BindEntry(DanceConfigKey.AudioVolume, 0.1f, (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 1f)); AudioRangeMeters = BindEntry(DanceConfigKey.AudioRangeMeters, 5f, (AcceptableValueBase?)(object)new AcceptableValueRange(1f, 30f)); StabilizeModelLighting = BindEntry(DanceConfigKey.StabilizeModelLighting, defaultValue: true, null); LightingExposureCompensation = BindEntry(DanceConfigKey.LightingExposureCompensation, 0.82f, (AcceptableValueBase?)(object)new AcceptableValueRange(0.4f, 1f)); ModelScale = BindEntry(DanceConfigKey.ModelScale, 1.2f, (AcceptableValueBase?)(object)new AcceptableValueRange(0.1f, 3f)); SpawnModelKey = BindEntry(DanceConfigKey.SpawnModelKey, (KeyCode)289, null); HairColorEnabled = BindEntry(DanceConfigKey.HairColorEnabled, defaultValue: false, null); HairColorR = BindEntry(DanceConfigKey.HairColorR, 0f, (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 1f)); HairColorG = BindEntry(DanceConfigKey.HairColorG, 0f, (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 1f)); HairColorB = BindEntry(DanceConfigKey.HairColorB, 0f, (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 1f)); ClothColorEnabled = BindEntry(DanceConfigKey.ClothColorEnabled, defaultValue: false, null); ClothColorR = BindEntry(DanceConfigKey.ClothColorR, 0f, (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 1f)); ClothColorG = BindEntry(DanceConfigKey.ClothColorG, 0f, (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 1f)); ClothColorB = BindEntry(DanceConfigKey.ClothColorB, 0f, (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 1f)); RandomizeColors = BindEntry(DanceConfigKey.RandomizeColors, defaultValue: false, null); EnableVerboseLogs = BindEntry(DanceConfigKey.EnableVerboseLogs, defaultValue: false, null); _savedAirportPlacement = config.Bind(DanceConfigLocalization.GetSectionName(IsChineseLanguage), DanceConfigLocalization.GetSavedAirportPlacementKeyName(IsChineseLanguage), string.Empty, DanceConfigLocalization.GetSavedAirportPlacementDescription(IsChineseLanguage)); DanceConfigLocalization.MigrateSavedAirportPlacement(config, (ConfigEntryBase)(object)_savedAirportPlacement); DanceConfigLocalization.MigrateLocalizedConfigEntries(config, _visibleEntries); RemoveObsoleteConfigEntries(config.ConfigFilePath); VerboseLogState.Update(EnableVerboseLogs.Value); EnableVerboseLogs.SettingChanged += delegate { VerboseLogState.Update(EnableVerboseLogs.Value); }; Save(); } public void RefreshRandomColors() { //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_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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!RandomizeColors.Value) { _randomHairColor = Color.white; _randomClothColor = Color.white; } else { _randomHairColor = HairColorPalette[Random.Range(0, HairColorPalette.Length)]; _randomClothColor = ClothColorPalette[Random.Range(0, ClothColorPalette.Length)]; } } public bool TryResolveHairColor(out Color color) { //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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (RandomizeColors.Value) { color = _randomHairColor; return true; } if (!HairColorEnabled.Value) { color = Color.white; return false; } color = new Color(HairColorR.Value, HairColorG.Value, HairColorB.Value, 1f); return true; } public bool TryResolveClothColor(out Color color) { //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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (RandomizeColors.Value) { color = _randomClothColor; return true; } if (!ClothColorEnabled.Value) { color = Color.white; return false; } color = new Color(ClothColorR.Value, ClothColorG.Value, ClothColorB.Value, 1f); return true; } public string ResolveUnityBundlePath() { string[] array = new string[3] { Path.Combine(_pluginDirectory, "miku_lobby_display.bundle"), Path.Combine(_pluginDirectory, "UnityBundle\\miku_lobby_display.bundle"), Path.Combine(_pluginDirectory, "Assets\\UnityBundle\\miku_lobby_display.bundle") }; return array.Select(Path.GetFullPath).FirstOrDefault(File.Exists) ?? Path.GetFullPath(array[0]); } public void Save() { _configFile.Save(); DanceConfigLocalization.RewriteConfigFileLocalization(_configFile.ConfigFilePath, IsChineseLanguage); } public bool RefreshLocalization(bool isChineseLanguage, bool saveConfigFile) { bool result = IsChineseLanguage != isChineseLanguage; IsChineseLanguage = isChineseLanguage; DanceConfigLocalization.ApplyLocalizedDescriptions(_configFile, IsChineseLanguage); if (saveConfigFile) { Save(); return result; } DanceConfigLocalization.RewriteConfigFileLocalization(_configFile.ConfigFilePath, IsChineseLanguage); return result; } public bool TryGetSavedAirportPlacement(out Vector3 position, out Vector3 forward) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_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) position = default(Vector3); forward = Vector3.forward; string value = _savedAirportPlacement.Value; if (string.IsNullOrWhiteSpace(value)) { return false; } string[] array = value.Split(new char[1] { '|' }); if (array.Length != 2) { return false; } if (!TryParseVector3(array[0], out position) || !TryParseVector3(array[1], out forward)) { position = default(Vector3); forward = Vector3.forward; return false; } forward = Vector3.ProjectOnPlane(forward, Vector3.up); if (((Vector3)(ref forward)).sqrMagnitude <= 0.0001f) { forward = Vector3.forward; } else { ((Vector3)(ref forward)).Normalize(); } return true; } public void SaveAirportPlacement(Vector3 position, 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_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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) Vector3 value = Vector3.ProjectOnPlane(forward, Vector3.up); if (((Vector3)(ref value)).sqrMagnitude <= 0.0001f) { value = Vector3.forward; } else { ((Vector3)(ref value)).Normalize(); } _savedAirportPlacement.Value = SerializeVector3(position) + "|" + SerializeVector3(value); Save(); } private ConfigEntry BindEntry(DanceConfigKey configKey, T defaultValue, AcceptableValueBase? acceptableValues) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown ConfigEntry val = _configFile.Bind(DanceConfigLocalization.GetSectionName(IsChineseLanguage), DanceConfigLocalization.GetKeyName(configKey, IsChineseLanguage), defaultValue, new ConfigDescription(DanceConfigLocalization.GetDescription(configKey, IsChineseLanguage), acceptableValues, Array.Empty())); _visibleEntries.Add(new LocalizedConfigEntry(configKey, (ConfigEntryBase)(object)val)); return val; } private static void RemoveObsoleteConfigEntries(string configPath) { if (!File.Exists(configPath)) { return; } HashSet obsoleteKeys = new HashSet { "AssetRootPath", "ModelPath", "MotionPath", "VerticalOffset", "ModelPitchCorrection", "ModelRollCorrection", "LobbyPositionX", "LobbyPositionY", "LobbyPositionZ", "GroundProbeMaxDistance", "UseManualLobbyPlacement", "ManualLobbyPositionX", "ManualLobbyPositionY", "ManualLobbyPositionZ", "ManualLobbyForwardX", "ManualLobbyForwardY", "ManualLobbyForwardZ", "PitchOffset", "YawOffset", "RollOffset", "ElevatorForwardOffset", "ElevatorRightOffset", "FallbackPositionX", "FallbackPositionY", "FallbackPositionZ", "SpawnForwardOffset", "SpawnRightOffset", "HairColor", "ClothColor", "PreferredLobbyPositionX", "PreferredLobbyPositionY", "PreferredLobbyPositionZ", "ModelYawCorrection" }; string[] array = File.ReadAllLines(configPath); List list = new List(array.Length); for (int i = 0; i < array.Length; i++) { string text = array[i]; if (!IsObsoleteConfigValueLine(text, obsoleteKeys)) { list.Add(text); continue; } while (list.Count > 0 && string.IsNullOrWhiteSpace(list[list.Count - 1])) { list.RemoveAt(list.Count - 1); } while (list.Count > 0 && list[list.Count - 1].StartsWith("#", StringComparison.Ordinal)) { list.RemoveAt(list.Count - 1); } for (; i + 1 < array.Length && string.IsNullOrWhiteSpace(array[i + 1]); i++) { } } if (list.Count != array.Length) { File.WriteAllLines(configPath, list); } } private static bool IsObsoleteConfigValueLine(string line, HashSet obsoleteKeys) { int num = line.IndexOf(" = ", StringComparison.Ordinal); if (num <= 0) { return false; } string item = line.Substring(0, num); return obsoleteKeys.Contains(item); } private static string SerializeVector3(Vector3 value) { return string.Join(",", value.x.ToString("R", CultureInfo.InvariantCulture), value.y.ToString("R", CultureInfo.InvariantCulture), value.z.ToString("R", CultureInfo.InvariantCulture)); } private static bool TryParseVector3(string serialized, out Vector3 value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) value = default(Vector3); string[] array = serialized.Split(new char[1] { ',' }); if (array.Length != 3) { return false; } if (!float.TryParse(array[0], NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var result3)) { return false; } value = new Vector3(result, result2, result3); return true; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.github.Thanks.MikuDance", "MikuShowcase", "1.0.2")] public sealed class MikuDancePlugin : BaseUnityPlugin { private const float LocalizationRefreshIntervalSeconds = 0.25f; private DancePluginConfig? _pluginConfig; private float _nextLocalizationRefreshTime; private void Awake() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown string text = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath; DancePluginConfig dancePluginConfig = (_pluginConfig = new DancePluginConfig(((BaseUnityPlugin)this).Config, text)); GameObject val = new GameObject("MikuDanceController"); Object.DontDestroyOnLoad((Object)val); val.AddComponent().Initialize(dancePluginConfig, ((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogDebug((object)("MikuShowcase plugin initialized. pluginDirectory='" + text + "', bundlePath='" + dancePluginConfig.ResolveUnityBundlePath() + "', configPath='" + ((BaseUnityPlugin)this).Config.ConfigFilePath + "'.")); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MikuShowcase] Config language: " + DanceConfigLocalization.BuildLanguageDetectionSummary(dancePluginConfig.IsChineseLanguage))); } private void Start() { ((MonoBehaviour)this).StartCoroutine(RegisterModConfigRoutine()); } private void Update() { if (_pluginConfig != null && !(Time.unscaledTime < _nextLocalizationRefreshTime)) { _nextLocalizationRefreshTime = Time.unscaledTime + 0.25f; bool flag = DanceConfigLocalization.DetectChineseLanguage(); if (_pluginConfig.IsChineseLanguage != flag && _pluginConfig.RefreshLocalization(flag, saveConfigFile: true)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MikuShowcase] Config language changed: " + (flag ? "Chinese" : "English"))); } OptionalModConfigBridge.TryLocalizeVisibleUi(_pluginConfig); } } private IEnumerator RegisterModConfigRoutine() { if (_pluginConfig == null) { yield break; } for (int attempt = 0; attempt < 20; attempt++) { if (OptionalModConfigBridge.TryRegister(_pluginConfig, ((BaseUnityPlugin)this).Logger)) { break; } yield return (object)new WaitForSecondsRealtime(0.5f); } } } internal static class OptionalModConfigBridge { private const string ModConfigPluginGuid = "com.github.PEAKModding.PEAKLib.ModConfig"; private const string ModConfigPluginTypeName = "PEAKLib.ModConfig.ModConfigPlugin"; private static readonly BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static bool _registered; public static bool TryRegister(DancePluginConfig config, ManualLogSource logger) { if (_registered) { return true; } try { Type type = FindLoadedType("PEAKLib.ModConfig.ModConfigPlugin"); if (type == null) { return false; } if (type.GetField("instance", AllBindings)?.GetValue(null) == null) { return false; } _registered = true; TryLocalizeVisibleUi(config); logger.LogDebug((object)"ModConfig v1.6+ detected. Relying on automatic config entry discovery by ModConfig."); return true; } catch (Exception arg) { logger.LogError((object)$"Failed to detect ModConfig bridge: {arg}"); return true; } } public static void TryLocalizeVisibleUi(DancePluginConfig config) { if (config == null || !TryGetModConfigMenuInstance(out Type menuType, out object menuInstance) || menuType == null || menuInstance == null) { return; } Behaviour val = (Behaviour)((menuInstance is Behaviour) ? menuInstance : null); if (val == null || (Object)(object)val == (Object)null) { return; } try { if (!val.isActiveAndEnabled || !((Component)val).gameObject.activeInHierarchy) { return; } } catch { return; } Dictionary map = DanceConfigLocalization.BuildUiLocalizationMap(config.IsChineseLanguage); foreach (Transform item in EnumerateModConfigUiRoots(menuInstance, menuType)) { ApplyTextLocalizationToRoot(item, map); } ApplyTextLocalizationToLoadedUi(map); } private static Type? FindLoadedType(string fullName) { return (from assembly in AppDomain.CurrentDomain.GetAssemblies() select assembly.GetType(fullName, throwOnError: false, ignoreCase: false)).FirstOrDefault((Type type) => type != null); } private static bool TryGetModConfigMenuInstance(out Type? menuType, out object? menuInstance) { menuType = null; menuInstance = null; if (!Chainloader.PluginInfos.TryGetValue("com.github.PEAKModding.PEAKLib.ModConfig", out var value) || value == null || (Object)(object)value.Instance == (Object)null) { return false; } Assembly assembly = ((object)value.Instance).GetType().Assembly; menuType = assembly.GetType("PEAKLib.ModConfig.Components.ModdedSettingsMenu"); menuInstance = menuType?.GetProperty("Instance", AllBindings)?.GetValue(null); if (menuType != null) { return menuInstance != null; } return false; } private static IEnumerable EnumerateModConfigUiRoots(object menuInstance, Type menuType) { HashSet visited = new HashSet(); foreach (Transform item in EnumerateCandidateTransforms(menuInstance, menuType)) { if ((Object)(object)item != (Object)null && visited.Add(((Object)item).GetInstanceID())) { yield return item; } } } private static IEnumerable EnumerateCandidateTransforms(object menuInstance, Type menuType) { Component val = (Component)((menuInstance is Component) ? menuInstance : null); if (val != null) { yield return val.transform; } object? obj = menuType.GetProperty("Content", AllBindings)?.GetValue(menuInstance); Transform val2 = (Transform)((obj is Transform) ? obj : null); if (val2 != null) { yield return val2; } } private static void ApplyTextLocalizationToRoot(Transform root, Dictionary map) { if (!((Object)(object)root == (Object)null) && map != null && map.Count != 0) { TMP_Text[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ApplyTextLocalization(componentsInChildren[i], map); } } } private static void ApplyTextLocalizationToLoadedUi(Dictionary map) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (map == null || map.Count == 0) { return; } try { TMP_Text[] array = Resources.FindObjectsOfTypeAll(); foreach (TMP_Text val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { ApplyTextLocalization(val, map); } } } } catch (Exception) { } } private static void ApplyTextLocalization(TMP_Text text, Dictionary map) { if (!((Object)(object)text == (Object)null) && map != null && map.Count != 0) { string text2 = ((text.text == null) ? string.Empty : text.text.Trim()); if (!string.IsNullOrWhiteSpace(text2) && map.TryGetValue(text2, out string value) && !string.Equals(text2, value, StringComparison.Ordinal)) { text.text = value; } } } } internal static class PluginConstants { public const string Guid = "com.github.Thanks.MikuDance"; public const string Name = "MikuShowcase"; public const string Version = "1.0.2"; public const string DefaultUnityBundleFileName = "miku_lobby_display.bundle"; public const string LegacyUnityBundlePath = "UnityBundle\\miku_lobby_display.bundle"; public const string LegacyAssetsUnityBundlePath = "Assets\\UnityBundle\\miku_lobby_display.bundle"; } internal static class VerboseLogState { private static volatile bool _enabled; public static bool Enabled => _enabled; public static void Update(bool enabled) { _enabled = enabled; } } }