Decompiled source of ScallionMiku v1.0.3
plugins/ScallionMiku.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("ScallionMiku")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3")] [assembly: AssemblyProduct("ScallionMiku")] [assembly: AssemblyTitle("ScallionMiku")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] [module: UnverifiableCode] namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public sealed class IgnoresAccessChecksToAttribute : Attribute { private readonly string _assemblyName; public string AssemblyName => _assemblyName; public IgnoresAccessChecksToAttribute(string assemblyName) { _assemblyName = assemblyName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] public sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte value) { NullableFlags = new byte[1] { value }; } public NullableAttribute(byte[] value) { NullableFlags = value; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] public sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte value) { Flag = value; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] public sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int version) { Version = version; } } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class BepInAutoPluginAttribute : Attribute { private string _guid; private string _name; private string _version; public string GUID { get { return _guid; } set { _guid = value; } } public string Name { get { return _name; } set { _name = value; } } public string Version { get { return _version; } set { _version = value; } } public BepInAutoPluginAttribute(string guid = null, string name = null, string version = null) { _guid = guid; _name = name; _version = version; } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class PatcherAutoPluginAttribute : Attribute { private string _guid; private string _name; private string _version; public string GUID { get { return _guid; } set { _guid = value; } } public string Name { get { return _name; } set { _name = value; } } public string Version { get { return _version; } set { _version = value; } } public PatcherAutoPluginAttribute(string guid = null, string name = null, string version = null) { _guid = guid; _name = name; _version = version; } } } namespace ScallionMiku { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.github.Thanks.ScallionMiku", "ScallionMiku", "1.0.3")] public class Plugin : BaseUnityPlugin { private enum ConfigKey { ModEnabled, WorldScale, BackpackScale, PositionOffsetX, PositionOffsetY, PositionOffsetZ, FaceExpression } private enum FaceExpressionOption { None, Smile, Blink, Wink, WinkRight, Wink2, Wink2Right, A, I, U, E, O, A2, MouthCornerUp, MouthCornerDown, Hau } [CompilerGenerated] private sealed class <EnumerateCandidateTransforms>d__182 : IEnumerable<Transform>, IEnumerable, IEnumerator<Transform>, IDisposable, IEnumerator { private int <>1__state; private Transform <>2__current; private int <>l__initialThreadId; private object menuInstance; public object <>3__menuInstance; private Type menuType; public Type <>3__menuType; Transform IEnumerator<Transform>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnumerateCandidateTransforms>d__182(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { object? obj2; Transform val2; switch (<>1__state) { default: return false; case 0: { <>1__state = -1; object obj = menuInstance; Component val = (Component)((obj is Component) ? obj : null); if (val != null) { <>2__current = val.transform; <>1__state = 1; return true; } goto IL_004d; } case 1: <>1__state = -1; goto IL_004d; case 2: { <>1__state = -1; break; } IL_004d: obj2 = menuType?.GetProperty("Content", InstanceFlags)?.GetValue(menuInstance); val2 = (Transform)((obj2 is Transform) ? obj2 : null); if (val2 != null) { <>2__current = val2; <>1__state = 2; return true; } break; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<Transform> IEnumerable<Transform>.GetEnumerator() { <EnumerateCandidateTransforms>d__182 <EnumerateCandidateTransforms>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <EnumerateCandidateTransforms>d__ = this; } else { <EnumerateCandidateTransforms>d__ = new <EnumerateCandidateTransforms>d__182(0); } <EnumerateCandidateTransforms>d__.menuInstance = <>3__menuInstance; <EnumerateCandidateTransforms>d__.menuType = <>3__menuType; return <EnumerateCandidateTransforms>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<Transform>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <EnumerateModConfigUiRoots>d__181 : IEnumerable<Transform>, IEnumerable, IEnumerator<Transform>, IDisposable, IEnumerator { private int <>1__state; private Transform <>2__current; private int <>l__initialThreadId; private object menuInstance; public object <>3__menuInstance; private Type menuType; public Type <>3__menuType; private HashSet<int> <visited>5__2; private IEnumerator<Transform> <>7__wrap2; Transform IEnumerator<Transform>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnumerateModConfigUiRoots>d__181(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <visited>5__2 = null; <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <visited>5__2 = new HashSet<int>(); <>7__wrap2 = EnumerateCandidateTransforms(menuInstance, menuType).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap2.MoveNext()) { Transform current = <>7__wrap2.Current; if ((Object)(object)current != (Object)null && <visited>5__2.Add(((Object)current).GetInstanceID())) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap2 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<Transform> IEnumerable<Transform>.GetEnumerator() { <EnumerateModConfigUiRoots>d__181 <EnumerateModConfigUiRoots>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <EnumerateModConfigUiRoots>d__ = this; } else { <EnumerateModConfigUiRoots>d__ = new <EnumerateModConfigUiRoots>d__181(0); } <EnumerateModConfigUiRoots>d__.menuInstance = <>3__menuInstance; <EnumerateModConfigUiRoots>d__.menuType = <>3__menuType; return <EnumerateModConfigUiRoots>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<Transform>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <GetAliasDefinitions>d__161 : IEnumerable<ConfigDefinition>, IEnumerable, IEnumerator<ConfigDefinition>, IDisposable, IEnumerator { private int <>1__state; private ConfigDefinition <>2__current; private int <>l__initialThreadId; private ConfigKey configKey; public ConfigKey <>3__configKey; private string <canonicalKey>5__2; private string <localizedKey>5__3; private string <canonicalSection>5__4; private string <localizedSection>5__5; ConfigDefinition IEnumerator<ConfigDefinition>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetAliasDefinitions>d__161(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <canonicalKey>5__2 = null; <localizedKey>5__3 = null; <canonicalSection>5__4 = null; <localizedSection>5__5 = null; <>1__state = -2; } private bool MoveNext() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <canonicalKey>5__2 = GetConfigKeyName(configKey); <localizedKey>5__3 = GetKeyName(configKey, isChineseLanguage: true); <canonicalSection>5__4 = GetConfigSectionName(configKey); <localizedSection>5__5 = GetSectionName(configKey, isChineseLanguage: true); <>2__current = new ConfigDefinition(<canonicalSection>5__4, <canonicalKey>5__2); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = new ConfigDefinition(<canonicalSection>5__4, <localizedKey>5__3); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = new ConfigDefinition(<localizedSection>5__5, <canonicalKey>5__2); <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = new ConfigDefinition(<localizedSection>5__5, <localizedKey>5__3); <>1__state = 4; return true; case 4: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<ConfigDefinition> IEnumerable<ConfigDefinition>.GetEnumerator() { <GetAliasDefinitions>d__161 <GetAliasDefinitions>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetAliasDefinitions>d__ = this; } else { <GetAliasDefinitions>d__ = new <GetAliasDefinitions>d__161(0); } <GetAliasDefinitions>d__.configKey = <>3__configKey; return <GetAliasDefinitions>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<ConfigDefinition>)this).GetEnumerator(); } } private const float LiveConfigRefreshInterval = 0.03f; private const int SimplifiedChineseLanguageIndex = 9; private const string ModConfigPluginGuid = "com.github.PEAKModding.PEAKLib.ModConfig"; private const float ModConfigUiLocalizationIntervalSeconds = 0.25f; private static readonly string[] LegacyPluginIds = new string[2] { "com.github.Thanks.MikuBongFix", "com.github.FelineEntity.MikuBongFix" }; private const string BundleFileName = "ScallionMiku"; private const string ExternalIconFileName = "ScallionMikuUI.png"; private const string PrefabAssetPath = "assets/葱音未来_by_翼月生/scallionmiku.prefab"; private const string MaterialAssetPath = "assets/葱音未来_by_翼月生/materials/scallionmiku-8.shintai.mat"; private const string IconTextureAssetPath = "assets/葱音未来_by_翼月生/textures/身体.png"; private const string MainTextureAssetPath = "assets/葱音未来_by_翼月生/textures/身体.png"; private const string ConfigSection = "Main"; private const string LocalizedConfigSection = "主要"; private const string WorldScaleConfigKey = "Fufu Size In World"; private const string BackpackModelScaleConfigKey = "Backpack Model Scale"; private const string LegacyFufuBackpackScaleConfigKey = "Fufu Size In Backpack"; private const string LegacyMikuBackpackScaleConfigKey = "Miku Size In Backpack"; private const float WorldMinScaleMultiplier = 0.4f; private const float WorldMaxScaleMultiplier = 1.1f; private const float BackpackMinScaleMultiplier = 0.2f; private const float BackpackMaxScaleMultiplier = 1f; private const float PositionOffsetMin = -2f; private const float PositionOffsetMax = 2f; private const float DefaultWorldScaleMultiplier = 0.9f; private const float DefaultBackpackScaleMultiplier = 0.4f; private const string ExpressionConfigKey = "Face Expression"; private const string LocalizedExpressionConfigKey = "表情"; private const string DefaultExpressionName = "None"; private const float DefaultExpressionWeight = 1f; private const float RuntimeScaleAdjustment = 0.78f; private const float BaseScaleMultiplier = 1.5f; private const float BundledBaseScaleMin = 0.04f; private const float BundledBaseScaleMax = 1.2f; private const FaceExpressionOption DefaultExpressionOption = FaceExpressionOption.None; private static readonly Vector3 DefaultBundledReplacementBaseScale = new Vector3(0.52f, 0.52f, 0.52f); private static readonly Vector3 RuntimeReferenceVisibleSizeAtBaseScale = new Vector3(1.5852638f, 1.2168914f, 0.8999324f); private static readonly Vector3 DefaultPositionOffset = Vector3.zero; private static readonly string[] PreferredTextureProps = new string[2] { "_BaseMap", "_MainTex" }; private static readonly string[] PrefabNameHints = new string[3] { "scallionmiku", "miku", "scallion" }; private static readonly string[] MaterialNameHints = new string[3] { "scallionmiku-8.shintai", "shintai", "miku" }; private static readonly string[] IconTextureNameHints = new string[4] { "身体", "shintai", "miku", "scallionmiku" }; private static readonly string[] MainTextureNameHints = new string[5] { "身体", "shintai", "miku", "scallionmiku", "albedo" }; private static readonly Color MikuStyleTint = new Color(0.98f, 1f, 1f, 1f); private static ConfigEntry<bool> _modEnabled; private static ConfigEntry<float> _worldScaleMultiplier; private static ConfigEntry<float> _backpackScaleMultiplier; private static ConfigEntry<float> _positionOffsetX; private static ConfigEntry<float> _positionOffsetY; private static ConfigEntry<float> _positionOffsetZ; private static ConfigEntry<FaceExpressionOption> _expressionOption; private bool _liveConfigStateInitialized; private bool _lastObservedModEnabled; private float _lastObservedWorldScale; private float _lastObservedBackpackScale; private Vector3 _lastObservedPositionOffset; private string _lastObservedExpressionName; private bool _pendingLiveConfigRefresh; private float _nextLiveConfigRefreshTime; private bool _liveConfigEventsBound; private bool _lastDetectedChineseLanguage; private bool _isRefreshingLanguage; private bool _pendingConfigFileLocalizationRefresh; private bool _pendingConfigFileLocalizationSave; private float _nextModConfigUiLocalizationTime; private static readonly BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly BindingFlags StaticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static readonly PropertyInfo ConfigFileEntriesProperty = typeof(ConfigFile).GetProperty("Entries", InstanceFlags); private static ManualLogSource _log; private static AssetBundle _bundle; private static GameObject _mochiPrefab; private static Material _mochiMaterial; private static Material _runtimeMikuMaterial; private static Texture2D _mochiTexture; private static Texture2D _mikuMainTexture; private static Vector3 _bundledReplacementBaseScale = DefaultBundledReplacementBaseScale; private static RuntimeReplacementModel _runtimeReplacementModel; public const string Name = "ScallionMiku"; public const string Id = "com.github.Thanks.ScallionMiku"; public const string Version = "1.0.3"; internal static Harmony Harmony = new Harmony("com.github.Thanks.ScallionMiku"); internal static ManualLogSource Log { get { return _log; } private set { _log = value; } } internal static AssetBundle Bundle { get { return _bundle; } private set { _bundle = value; } } internal static GameObject MochiPrefab { get { return _mochiPrefab; } private set { _mochiPrefab = value; } } internal static Material MochiMaterial { get { return _mochiMaterial; } private set { _mochiMaterial = value; } } internal static Material RuntimeMikuMaterial { get { return _runtimeMikuMaterial; } private set { _runtimeMikuMaterial = value; } } internal static Texture2D MochiTexture { get { return _mochiTexture; } private set { _mochiTexture = value; } } internal static Texture2D MikuMainTexture { get { return _mikuMainTexture; } private set { _mikuMainTexture = value; } } internal static RuntimeReplacementModel RuntimeReplacementModel { get { return _runtimeReplacementModel; } private set { _runtimeReplacementModel = value; } } internal static bool ModEnabled { get { if (_modEnabled != null) { return _modEnabled.Value; } return true; } } internal static bool KeepOriginalRendererRefs => RuntimeReplacementModel == null; internal static bool EnableVisibilityGuard => true; internal static float WorldScaleMultiplier { get { if (_worldScaleMultiplier != null) { return Mathf.Clamp(_worldScaleMultiplier.Value, 0.4f, 1.1f); } return 0.9f; } } internal static float DefaultWorldScaleSetting => 0.9f; internal static float BackpackScaleMultiplier { get { if (_backpackScaleMultiplier != null) { return Mathf.Clamp(_backpackScaleMultiplier.Value, 0.2f, 1f); } return 0.4f; } } internal static float DefaultBackpackScaleSetting => 0.4f; internal static Vector3 ReplacementBaseScale { get { //IL_0026: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) if (RuntimeReplacementModel == null) { return _bundledReplacementBaseScale * 0.78f * 1.5f; } return RuntimeReplacementModel.RecommendedBaseScale * 0.78f * 1.5f; } } internal static Vector3 PositionOffset => new Vector3((_positionOffsetX == null) ? DefaultPositionOffset.x : Mathf.Clamp(_positionOffsetX.Value, -2f, 2f), (_positionOffsetY == null) ? DefaultPositionOffset.y : Mathf.Clamp(_positionOffsetY.Value, -2f, 2f), (_positionOffsetZ == null) ? DefaultPositionOffset.z : Mathf.Clamp(_positionOffsetZ.Value, -2f, 2f)); internal static string ExpressionName { get { string text = ((_expressionOption == null) ? "None" : GetExpressionName(_expressionOption.Value)); if (!string.IsNullOrEmpty(text)) { return text; } return "None"; } } internal static float ExpressionWeight => 1f; internal static string ReplacementDisplayName => "Miku"; internal static int ReplacementRefreshRevision { get; private set; } = 1; internal static string directory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; _lastDetectedChineseLanguage = DetectChineseLanguage(); MigrateLegacyConfigIfNeeded(); InitializeConfig(_lastDetectedChineseLanguage); NormalizeMigratedScaleConfigIfNeeded(); MarkConfigFileLocalizationDirty(saveConfigFile: true); LoadAssets(); try { Harmony.PatchAll(Assembly.GetExecutingAssembly()); } catch (Exception ex) { Log.LogError((object)("Failed to apply Harmony patches: " + ex)); } BindLiveConfigEvents(); CaptureLiveConfigState(); Log.LogInfo((object)("[ScallionMiku] Config language: " + BuildLanguageDetectionSummary(_lastDetectedChineseLanguage))); } private void Update() { HandleLanguageChangeIfNeeded(); HandlePendingConfigFileLocalizationRefresh(); TryLocalizeVisibleModConfigUiThrottled(); if (HasLiveConfigStateChanged()) { CaptureLiveConfigState(); _pendingLiveConfigRefresh = true; } if (_pendingLiveConfigRefresh && !(Time.realtimeSinceStartup < _nextLiveConfigRefreshTime)) { RefreshReplacementInstancesNow(); } } private bool HasLiveConfigStateChanged() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (!_liveConfigStateInitialized) { return true; } if (_lastObservedModEnabled != ModEnabled) { return true; } if (!Mathf.Approximately(_lastObservedWorldScale, WorldScaleMultiplier)) { return true; } if (!Mathf.Approximately(_lastObservedBackpackScale, BackpackScaleMultiplier)) { return true; } if (_lastObservedPositionOffset != PositionOffset) { return true; } return !string.Equals(_lastObservedExpressionName, ExpressionName, StringComparison.Ordinal); } private void CaptureLiveConfigState() { //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) _lastObservedModEnabled = ModEnabled; _lastObservedWorldScale = WorldScaleMultiplier; _lastObservedBackpackScale = BackpackScaleMultiplier; _lastObservedPositionOffset = PositionOffset; _lastObservedExpressionName = ExpressionName; _liveConfigStateInitialized = true; } private void BindLiveConfigEvents() { if (!_liveConfigEventsBound) { BindLiveConfigEvent<bool>(_modEnabled); BindLiveConfigEvent<float>(_worldScaleMultiplier); BindLiveConfigEvent<float>(_backpackScaleMultiplier); BindLiveConfigEvent<float>(_positionOffsetX); BindLiveConfigEvent<float>(_positionOffsetY); BindLiveConfigEvent<float>(_positionOffsetZ); BindLiveConfigEvent<FaceExpressionOption>(_expressionOption); _liveConfigEventsBound = true; } } private void BindLiveConfigEvent<T>(ConfigEntry<T> entry) { if (entry != null) { entry.SettingChanged -= OnLiveConfigSettingChanged; entry.SettingChanged += OnLiveConfigSettingChanged; } } private void OnLiveConfigSettingChanged(object sender, EventArgs args) { MarkConfigFileLocalizationDirty(saveConfigFile: false); CaptureLiveConfigState(); if (Time.realtimeSinceStartup >= _nextLiveConfigRefreshTime) { RefreshReplacementInstancesNow(); } else { _pendingLiveConfigRefresh = true; } } private void RefreshReplacementInstancesNow() { _pendingLiveConfigRefresh = false; _nextLiveConfigRefreshTime = Time.realtimeSinceStartup + 0.03f; ReplacementRefreshRevision = ((ReplacementRefreshRevision == int.MaxValue) ? 1 : (ReplacementRefreshRevision + 1)); Patch_AskRoutine.HandleModConfigStateChanged(); ItemPatch.RefreshAllReplacementInstances(); } private void MigrateLegacyConfigIfNeeded() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || File.Exists(configFilePath) || LegacyPluginIds == null) { return; } for (int i = 0; i < LegacyPluginIds.Length; i++) { string text = LegacyPluginIds[i]; if (!string.IsNullOrEmpty(text)) { string text2 = Path.Combine(Paths.ConfigPath, text + ".cfg"); if (File.Exists(text2)) { File.Copy(text2, configFilePath, overwrite: false); ((BaseUnityPlugin)this).Config.Reload(); VerboseLog("Migrated legacy config to: " + configFilePath); break; } } } } catch (Exception ex) { Log.LogWarning((object)("Failed to migrate legacy config file: " + ex.Message)); } } private void InitializeConfig(bool isChineseLanguage) { RemoveConfigVersionSettingIfNeeded(); NormalizeLegacyExpressionConfigIfNeeded(); _modEnabled = BindEntry(ConfigKey.ModEnabled, defaultValue: true, isChineseLanguage); _worldScaleMultiplier = BindEntry(ConfigKey.WorldScale, 0.9f, isChineseLanguage); _backpackScaleMultiplier = BindEntry(ConfigKey.BackpackScale, 0.4f, isChineseLanguage); _positionOffsetX = BindEntry(ConfigKey.PositionOffsetX, DefaultPositionOffset.x, isChineseLanguage); _positionOffsetY = BindEntry(ConfigKey.PositionOffsetY, DefaultPositionOffset.y, isChineseLanguage); _positionOffsetZ = BindEntry(ConfigKey.PositionOffsetZ, DefaultPositionOffset.z, isChineseLanguage); _expressionOption = BindEntry(ConfigKey.FaceExpression, FaceExpressionOption.None, isChineseLanguage); MigrateLocalizedConfigEntries(); } private ConfigEntry<T> BindEntry<T>(ConfigKey configKey, T defaultValue, bool isChineseLanguage) { return ((BaseUnityPlugin)this).Config.Bind<T>(GetSectionName(configKey, isChineseLanguage), GetKeyName(configKey, isChineseLanguage), defaultValue, CreateConfigDescription(configKey, isChineseLanguage)); } private ConfigDescription CreateConfigDescription(ConfigKey configKey, bool isChineseLanguage) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown string localizedDescription = GetLocalizedDescription(configKey, isChineseLanguage); switch (configKey) { case ConfigKey.WorldScale: return new ConfigDescription(localizedDescription, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.4f, 1.1f), Array.Empty<object>()); case ConfigKey.BackpackScale: return new ConfigDescription(localizedDescription, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 1f), Array.Empty<object>()); case ConfigKey.PositionOffsetX: case ConfigKey.PositionOffsetY: case ConfigKey.PositionOffsetZ: return new ConfigDescription(localizedDescription, (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 2f), Array.Empty<object>()); default: return new ConfigDescription(localizedDescription, (AcceptableValueBase)null, Array.Empty<object>()); } } private void RemoveConfigVersionSettingIfNeeded() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return; } string[] array = File.ReadAllLines(configFilePath); List<string> list = new List<string>(array.Length); bool flag = false; bool flag2 = false; for (int i = 0; i < array.Length; i++) { string text = array[i] ?? string.Empty; string text2 = text.Trim(); if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { flag2 = string.Equals(text2.Substring(1, text2.Length - 2).Trim(), "Internal", StringComparison.OrdinalIgnoreCase); if (flag2) { flag = true; continue; } } if (flag2) { flag = true; } else { list.Add(text); } } if (flag) { File.WriteAllLines(configFilePath, list.ToArray()); ((BaseUnityPlugin)this).Config.Reload(); VerboseLog("Removed obsolete Internal/Config Version config entry."); } } catch (Exception ex) { Log.LogWarning((object)("Failed to remove obsolete Config Version entry: " + ex.Message)); } } private void NormalizeLegacyExpressionConfigIfNeeded() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return; } string[] array = File.ReadAllLines(configFilePath); bool flag = false; for (int i = 0; i < array.Length; i++) { if (TrySplitConfigSettingLine(array[i], out var leading, out var keyName, out var separatorAndValue) && IsConfigKeyName(keyName, ConfigKey.FaceExpression)) { int num = separatorAndValue.IndexOf('='); string obj = ((num >= 0) ? separatorAndValue.Substring(num + 1).Trim() : string.Empty); if (!TryParseExpressionOption(obj, out var option)) { option = FaceExpressionOption.None; } string text = option.ToString(); if (!string.Equals(obj, text, StringComparison.Ordinal)) { string keyName2 = GetKeyName(ConfigKey.FaceExpression, _lastDetectedChineseLanguage); array[i] = leading + keyName2 + " = " + text; flag = true; } } } if (flag) { File.WriteAllLines(configFilePath, array); ((BaseUnityPlugin)this).Config.Reload(); VerboseLog("Migrated Face Expression config from PMX morph text to enum value for PEAKLib.ModConfig compatibility."); } } catch (Exception ex) { Log.LogWarning((object)("Failed to normalize Face Expression config value: " + ex.Message)); } } private static bool TryParseExpressionOption(string rawValue, out FaceExpressionOption option) { option = FaceExpressionOption.None; if (string.IsNullOrEmpty(rawValue)) { return false; } string text = rawValue.Trim().Trim(new char[1] { '"' }); if (Enum.TryParse<FaceExpressionOption>(text, ignoreCase: true, out option) && Enum.IsDefined(typeof(FaceExpressionOption), option)) { return true; } for (int i = 0; i <= 15; i++) { FaceExpressionOption faceExpressionOption = (FaceExpressionOption)i; if (string.Equals(text, GetExpressionName(faceExpressionOption), StringComparison.Ordinal)) { option = faceExpressionOption; return true; } } return false; } private static string GetExpressionName(FaceExpressionOption option) { return option switch { FaceExpressionOption.Smile => "笑い", FaceExpressionOption.Blink => "まばたき", FaceExpressionOption.Wink => "ウィンク", FaceExpressionOption.WinkRight => "ウィンク右", FaceExpressionOption.Wink2 => "ウィンク2", FaceExpressionOption.Wink2Right => "ウィンク2右", FaceExpressionOption.A => "あ", FaceExpressionOption.I => "い", FaceExpressionOption.U => "う", FaceExpressionOption.E => "え", FaceExpressionOption.O => "お", FaceExpressionOption.A2 => "あ2", FaceExpressionOption.MouthCornerUp => "口角上げ", FaceExpressionOption.MouthCornerDown => "口角下げ", FaceExpressionOption.Hau => "はぅ", _ => "None", }; } private void MarkConfigFileLocalizationDirty(bool saveConfigFile) { _pendingConfigFileLocalizationRefresh = true; _pendingConfigFileLocalizationSave |= saveConfigFile; } private void HandlePendingConfigFileLocalizationRefresh() { if (_pendingConfigFileLocalizationRefresh && !_isRefreshingLanguage) { bool pendingConfigFileLocalizationSave = _pendingConfigFileLocalizationSave; _pendingConfigFileLocalizationRefresh = false; _pendingConfigFileLocalizationSave = false; TryRefreshLocalizedConfigFile(_lastDetectedChineseLanguage, pendingConfigFileLocalizationSave); } } private void HandleLanguageChangeIfNeeded() { bool flag = DetectChineseLanguage(); if (flag != _lastDetectedChineseLanguage) { ReinitializeLocalizedConfig(flag); } } private void ReinitializeLocalizedConfig(bool isChineseLanguage) { if (_isRefreshingLanguage) { return; } _isRefreshingLanguage = true; try { _lastDetectedChineseLanguage = isChineseLanguage; ApplyLocalizedConfigMetadata(isChineseLanguage); MarkConfigFileLocalizationDirty(saveConfigFile: true); Log.LogInfo((object)("[ScallionMiku] Config language changed: " + (isChineseLanguage ? "Chinese" : "English"))); } catch (Exception ex) { Log.LogWarning((object)("[ScallionMiku] Failed to update config language: " + ex.Message)); } finally { _isRefreshingLanguage = false; } } private void ApplyLocalizedConfigMetadata(bool isChineseLanguage) { try { ConfigEntryBase[] configEntriesSnapshot = GetConfigEntriesSnapshot(((BaseUnityPlugin)this).Config); foreach (ConfigEntryBase val in configEntriesSnapshot) { if (val != null && !(val.Definition == (ConfigDefinition)null) && val.Description != null && TryGetConfigKey(val.Definition.Key, out var configKey)) { string localizedDescription = GetLocalizedDescription(configKey, isChineseLanguage); if (!string.IsNullOrWhiteSpace(localizedDescription)) { SetPrivateField(val.Description, "<Description>k__BackingField", localizedDescription); } } } TryLocalizeVisibleModConfigUi(); } catch (Exception ex) { Log.LogWarning((object)("[ScallionMiku] Failed to apply localized config metadata: " + ex.Message)); } } private static ConfigEntryBase[] GetConfigEntriesSnapshot(ConfigFile configFile) { if (configFile == null || !(ConfigFileEntriesProperty != null) || !(ConfigFileEntriesProperty.GetValue(configFile) is IDictionary dictionary) || dictionary.Count == 0) { return Array.Empty<ConfigEntryBase>(); } List<ConfigEntryBase> list = new List<ConfigEntryBase>(); 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 void SetPrivateField(object target, string fieldName, object value) { if (target != null && !string.IsNullOrWhiteSpace(fieldName)) { target.GetType().GetField(fieldName, InstanceFlags)?.SetValue(target, value); } } private void TryRefreshLocalizedConfigFile(bool isChineseLanguage, bool saveConfigFile) { try { if (((BaseUnityPlugin)this).Config != null && !string.IsNullOrWhiteSpace(((BaseUnityPlugin)this).Config.ConfigFilePath)) { if (saveConfigFile) { ((BaseUnityPlugin)this).Config.Save(); } RewriteConfigFileLocalization(((BaseUnityPlugin)this).Config.ConfigFilePath, isChineseLanguage); } } catch (Exception ex) { Log.LogWarning((object)("[ScallionMiku] Failed to refresh localized config file: " + ex.Message)); } } private 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); } } } 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 var localizedSectionName)) { return line; } int num = line.IndexOf('['); int num2 = line.LastIndexOf(']'); if (num < 0 || num2 < num) { return line; } return line.Substring(0, num + 1) + localizedSectionName + line.Substring(num2); } if (!TrySplitConfigSettingLine(line, out var leading, out var keyName, out var separatorAndValue)) { return line; } if (!TryGetConfigKey(keyName, out var configKey)) { return line; } 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<char>()); 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 TryGetLocalizedSectionName(string sectionName, bool isChineseLanguage, out string localizedSectionName) { if (string.Equals(sectionName, "Main", StringComparison.OrdinalIgnoreCase) || string.Equals(sectionName, "主要", StringComparison.Ordinal)) { localizedSectionName = (isChineseLanguage ? "主要" : "Main"); return true; } localizedSectionName = string.Empty; return false; } private void MigrateLocalizedConfigEntries() { IDictionary orphanedEntries = GetOrphanedEntries(((BaseUnityPlugin)this).Config); if (orphanedEntries != null && orphanedEntries.Count != 0 && (false | TryMigrateLocalizedConfigValue((ConfigEntryBase)(object)_modEnabled, ConfigKey.ModEnabled, orphanedEntries) | TryMigrateLocalizedConfigValue((ConfigEntryBase)(object)_worldScaleMultiplier, ConfigKey.WorldScale, orphanedEntries) | TryMigrateLocalizedConfigValue((ConfigEntryBase)(object)_backpackScaleMultiplier, ConfigKey.BackpackScale, orphanedEntries) | TryMigrateLocalizedConfigValue((ConfigEntryBase)(object)_positionOffsetX, ConfigKey.PositionOffsetX, orphanedEntries) | TryMigrateLocalizedConfigValue((ConfigEntryBase)(object)_positionOffsetY, ConfigKey.PositionOffsetY, orphanedEntries) | TryMigrateLocalizedConfigValue((ConfigEntryBase)(object)_positionOffsetZ, ConfigKey.PositionOffsetZ, orphanedEntries) | TryMigrateLocalizedConfigValue((ConfigEntryBase)(object)_expressionOption, ConfigKey.FaceExpression, orphanedEntries))) { ((BaseUnityPlugin)this).Config.Save(); } } private static bool TryMigrateLocalizedConfigValue(ConfigEntryBase entry, ConfigKey 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(NormalizeSerializedConfigValue(configKey, obj.ToString())); } flag = true; } orphanedEntries.Remove(aliasDefinition); } return flag; } private static string NormalizeSerializedConfigValue(ConfigKey configKey, string serializedValue) { if (configKey == ConfigKey.FaceExpression && TryParseExpressionOption(serializedValue, out var option)) { return option.ToString(); } return serializedValue; } [IteratorStateMachine(typeof(<GetAliasDefinitions>d__161))] private static IEnumerable<ConfigDefinition> GetAliasDefinitions(ConfigKey configKey) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetAliasDefinitions>d__161(-2) { <>3__configKey = configKey }; } 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 bool DetectChineseLanguage() { bool isChineseLanguage; bool num = TryGetConfiguredGameLanguage(out isChineseLanguage); string languageName; bool flag = TryGetLocalizedTextLanguageName(out languageName); if (num && isChineseLanguage) { return true; } if (flag && IsChineseLanguageName(languageName)) { return true; } return false; } private 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 + ")"; } 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)(Language)(ref LocalizedText.CURRENT_LANGUAGE)).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 string GetConfigSectionName(ConfigKey configKey) { return GetSectionName(configKey, isChineseLanguage: false); } private static string GetSectionName(ConfigKey configKey, bool isChineseLanguage) { if (!isChineseLanguage) { return "Main"; } return "主要"; } private static string GetConfigKeyName(ConfigKey configKey) { return GetKeyName(configKey, isChineseLanguage: false); } private static string GetKeyName(ConfigKey configKey, bool isChineseLanguage) { if (isChineseLanguage) { switch (configKey) { case ConfigKey.ModEnabled: return "启用葱音未来替换"; case ConfigKey.WorldScale: return "世界模型大小"; case ConfigKey.BackpackScale: return "背包模型大小"; case ConfigKey.PositionOffsetX: return "模型位置偏移 X"; case ConfigKey.PositionOffsetY: return "模型位置偏移 Y"; case ConfigKey.PositionOffsetZ: return "模型位置偏移 Z"; case ConfigKey.FaceExpression: return "表情"; } } return configKey switch { ConfigKey.ModEnabled => "Enable Fufu Replacement", ConfigKey.WorldScale => "Fufu Size In World", ConfigKey.BackpackScale => "Backpack Model Scale", ConfigKey.PositionOffsetX => "Model Position Offset X", ConfigKey.PositionOffsetY => "Model Position Offset Y", ConfigKey.PositionOffsetZ => "Model Position Offset Z", ConfigKey.FaceExpression => "Face Expression", _ => string.Empty, }; } private static string GetLocalizedDescription(ConfigKey configKey, bool isChineseLanguage) { if (isChineseLanguage) { switch (configKey) { case ConfigKey.ModEnabled: return "总开关。关闭后会恢复原版 BingBong 的外观、名称、图标和碰撞体。"; case ConfigKey.WorldScale: return "葱音未来模型在手持或放在世界中时的大小倍率。"; case ConfigKey.BackpackScale: return "葱音未来模型显示在背包中时的大小倍率。"; case ConfigKey.PositionOffsetX: return "运行时模型在 X 轴上的额外本地位置偏移。"; case ConfigKey.PositionOffsetY: return "运行时模型在 Y 轴上的额外本地位置偏移。"; case ConfigKey.PositionOffsetZ: return "运行时模型在 Z 轴上的额外本地位置偏移。"; case ConfigKey.FaceExpression: return "基础 PMX 表情。枚举会在运行时映射回实际 morph 名称,例如 Smile=笑い,Blink=まばたき,Wink=ウィンク。"; } } return configKey switch { ConfigKey.ModEnabled => "Master switch for the mod. When disabled, the original BingBong visuals, name, icon, and colliders are restored.", ConfigKey.WorldScale => "Scale multiplier for Fufu while held or lying in the world.", ConfigKey.BackpackScale => "Scale multiplier for the replacement model while the item is shown in the backpack.", ConfigKey.PositionOffsetX => "Extra local position offset on the X axis for the runtime model.", ConfigKey.PositionOffsetY => "Extra local position offset on the Y axis for the runtime model.", ConfigKey.PositionOffsetZ => "Extra local position offset on the Z axis for the runtime model.", ConfigKey.FaceExpression => "Base PMX facial expression. Mapping: Smile=笑い, Blink=まばたき, Wink=ウィンク, WinkRight=ウィンク右, Wink2=ウィンク2, Wink2Right=ウィンク2右, A=あ, I=い, U=う, E=え, O=お, A2=あ2, MouthCornerUp=口角上げ, MouthCornerDown=口角下げ, Hau=はぅ.", _ => string.Empty, }; } private static bool TryGetConfigKey(string keyName, out ConfigKey configKey) { foreach (ConfigKey value in Enum.GetValues(typeof(ConfigKey))) { if (IsConfigKeyName(keyName, value)) { configKey = value; return true; } } configKey = ConfigKey.ModEnabled; return false; } private static bool IsConfigKeyName(string keyName, ConfigKey configKey) { if (!string.Equals(keyName, GetConfigKeyName(configKey), StringComparison.OrdinalIgnoreCase)) { return string.Equals(keyName, GetKeyName(configKey, isChineseLanguage: true), StringComparison.Ordinal); } return true; } private void TryLocalizeVisibleModConfigUiThrottled() { if (!(Time.unscaledTime < _nextModConfigUiLocalizationTime)) { _nextModConfigUiLocalizationTime = Time.unscaledTime + 0.25f; TryLocalizeVisibleModConfigUi(); } } private void TryLocalizeVisibleModConfigUi() { if (!TryGetModConfigMenuInstance(out var menuType, out var menuInstance)) { 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<string, string> map = BuildModConfigUiLocalizationMap(DetectChineseLanguage()); foreach (Transform item in EnumerateModConfigUiRoots(menuInstance, menuType)) { ApplyTextLocalizationToRoot(item, map); } ApplyTextLocalizationToLoadedUi(map); } 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", StaticFlags)?.GetValue(null); if (menuType != null) { return menuInstance != null; } return false; } [IteratorStateMachine(typeof(<EnumerateModConfigUiRoots>d__181))] private static IEnumerable<Transform> EnumerateModConfigUiRoots(object menuInstance, Type menuType) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnumerateModConfigUiRoots>d__181(-2) { <>3__menuInstance = menuInstance, <>3__menuType = menuType }; } [IteratorStateMachine(typeof(<EnumerateCandidateTransforms>d__182))] private static IEnumerable<Transform> EnumerateCandidateTransforms(object menuInstance, Type menuType) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnumerateCandidateTransforms>d__182(-2) { <>3__menuInstance = menuInstance, <>3__menuType = menuType }; } private static void ApplyTextLocalizationToRoot(Transform root, Dictionary<string, string> map) { if (!((Object)(object)root == (Object)null) && map != null && map.Count != 0) { TMP_Text[] componentsInChildren = ((Component)root).GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ApplyTextLocalization(componentsInChildren[i], map); } } } private static void ApplyTextLocalizationToLoadedUi(Dictionary<string, string> 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<TMP_Text>(); 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 { } } private static void ApplyTextLocalization(TMP_Text text, Dictionary<string, string> 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 var value) && !string.Equals(text2, value, StringComparison.Ordinal)) { text.text = value; } } } private static Dictionary<string, string> BuildModConfigUiLocalizationMap(bool isChineseLanguage) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); AddUiLocalizationPair(dictionary, "ScallionMiku", GetLocalizedModDisplayName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "ScallionMiku", GetLocalizedModDisplayName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "com.github.Thanks.ScallionMiku", GetLocalizedModDisplayName(isChineseLanguage)); AddUiLocalizationPair(dictionary, "Main", GetSectionName(ConfigKey.ModEnabled, isChineseLanguage)); AddUiLocalizationPair(dictionary, "主要", GetSectionName(ConfigKey.ModEnabled, isChineseLanguage)); foreach (ConfigKey value in Enum.GetValues(typeof(ConfigKey))) { string sectionName = GetSectionName(value, isChineseLanguage); string keyName = GetKeyName(value, isChineseLanguage); AddUiLocalizationPair(dictionary, GetConfigSectionName(value), sectionName); AddUiLocalizationPair(dictionary, GetSectionName(value, isChineseLanguage: true), sectionName); AddUiLocalizationPair(dictionary, GetConfigKeyName(value), keyName); AddUiLocalizationPair(dictionary, ToReadableName(GetConfigKeyName(value)), keyName); AddUiLocalizationPair(dictionary, GetKeyName(value, isChineseLanguage: true), keyName); AddUiLocalizationPair(dictionary, GetLocalizedDescription(value, isChineseLanguage: false), GetLocalizedDescription(value, isChineseLanguage)); AddUiLocalizationPair(dictionary, GetLocalizedDescription(value, isChineseLanguage: true), GetLocalizedDescription(value, isChineseLanguage)); } AddExpressionOptionUiLocalization(dictionary, isChineseLanguage); return dictionary; } private static void AddExpressionOptionUiLocalization(Dictionary<string, string> map, bool isChineseLanguage) { AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.None, isChineseLanguage, "无"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.Smile, isChineseLanguage, "笑い"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.Blink, isChineseLanguage, "眨眼"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.Wink, isChineseLanguage, "眨左眼"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.WinkRight, isChineseLanguage, "眨右眼"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.Wink2, isChineseLanguage, "眨左眼 2"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.Wink2Right, isChineseLanguage, "眨右眼 2"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.A, isChineseLanguage, "口型 あ"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.I, isChineseLanguage, "口型 い"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.U, isChineseLanguage, "口型 う"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.E, isChineseLanguage, "口型 え"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.O, isChineseLanguage, "口型 お"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.A2, isChineseLanguage, "口型 あ2"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.MouthCornerUp, isChineseLanguage, "嘴角上扬"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.MouthCornerDown, isChineseLanguage, "嘴角下垂"); AddExpressionOptionUiLocalizationPair(map, FaceExpressionOption.Hau, isChineseLanguage, "はぅ"); } private static void AddExpressionOptionUiLocalizationPair(Dictionary<string, string> map, FaceExpressionOption option, bool isChineseLanguage, string chineseLabel) { string text = option.ToString(); if (isChineseLanguage) { AddUiLocalizationPair(map, text, chineseLabel); } else { AddUiLocalizationPair(map, chineseLabel, text); } } private static void AddUiLocalizationPair(Dictionary<string, string> map, string source, string localized) { if (map != null && !string.IsNullOrWhiteSpace(source) && !string.IsNullOrWhiteSpace(localized)) { string text = source.Trim(); string text3 = (map[text] = localized.Trim()); map[text3] = text3; string key = text.Replace(" ", string.Empty); string key2 = text3.Replace(" ", string.Empty); if (!map.ContainsKey(key)) { map[key] = text3; } if (!map.ContainsKey(key2)) { map[key2] = text3; } map[text.ToUpperInvariant()] = text3; map[text3.ToUpperInvariant()] = text3; } } private static string ToReadableName(string keyName) { if (string.IsNullOrWhiteSpace(keyName)) { return string.Empty; } List<char> list = new List<char>(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 "ScallionMiku"; } return "葱音未来"; } private void NormalizeMigratedScaleConfigIfNeeded() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (!string.IsNullOrEmpty(configFilePath) && File.Exists(configFilePath) && (FileContainsSetting(configFilePath, "Miku Size In World") || FileContainsSetting(configFilePath, "Fufu Size In Backpack") || FileContainsSetting(configFilePath, "Miku Size In Backpack") || FileContainsSetting(configFilePath, "Enable Miku Replacement"))) { bool flag = false; if (TryReadFloatSetting(configFilePath, "Miku Size In World", out var value) && _worldScaleMultiplier != null && _worldScaleMultiplier.Value <= 0.4001f) { _worldScaleMultiplier.Value = Mathf.Clamp(value, 0.4f, 1.1f); flag = true; } if (!FileContainsSetting(configFilePath, "Backpack Model Scale") && TryReadFirstFloatSetting(configFilePath, out var value2, "Fufu Size In Backpack", "Miku Size In Backpack") && _backpackScaleMultiplier != null) { _backpackScaleMultiplier.Value = Mathf.Clamp(value2, 0.2f, 1f); flag = true; } if (flag) { ((BaseUnityPlugin)this).Config.Save(); VerboseLog("Normalized migrated ScallionMiku scale settings for current runtime model."); } } } catch (Exception ex) { Log.LogWarning((object)("Failed to normalize migrated config values: " + ex.Message)); } } private static bool FileContainsSetting(string configPath, string key) { if (string.IsNullOrEmpty(configPath) || string.IsNullOrEmpty(key) || !File.Exists(configPath)) { return false; } string[] array = File.ReadAllLines(configPath); foreach (string text in array) { if (text != null && text.StartsWith(key + " =", StringComparison.Ordinal)) { return true; } } return false; } private static bool TryReadFloatSetting(string configPath, string key, out float value) { value = 0f; if (string.IsNullOrEmpty(configPath) || string.IsNullOrEmpty(key) || !File.Exists(configPath)) { return false; } string[] array = File.ReadAllLines(configPath); foreach (string text in array) { if (text != null && text.StartsWith(key + " =", StringComparison.Ordinal)) { return float.TryParse(text.Substring((key + " =").Length).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out value); } } return false; } private static bool TryReadFirstFloatSetting(string configPath, out float value, params string[] keys) { value = 0f; if (keys == null || keys.Length == 0) { return false; } foreach (string key in keys) { if (TryReadFloatSetting(configPath, key, out value)) { return true; } } return false; } private void LoadAssets() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Texture2D val = LoadExternalIconTexture(); _bundledReplacementBaseScale = DefaultBundledReplacementBaseScale; string text = ResolveBundlePath(); RuntimeReplacementModel = null; Bundle = null; MochiPrefab = null; MochiMaterial = null; MochiTexture = val; MikuMainTexture = null; RuntimeMikuMaterial = null; if (File.Exists(text)) { if (!TryLoadReplacementBundle(text, val)) { Log.LogError((object)("Found ScallionMiku bundle but failed to initialize replacement from: " + text)); } } else { Log.LogError((object)("ScallionMiku bundle is missing. Bundle-only runtime is enabled, so no PMX fallback will be loaded: " + text)); } } private bool TryLoadReplacementBundle(string bundlePath, Texture2D externalIconTexture) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) Bundle = AssetBundle.LoadFromFile(bundlePath); if ((Object)(object)Bundle == (Object)null) { Log.LogError((object)("Failed to load ScallionMiku AssetBundle: " + bundlePath)); return false; } RuntimeReplacementModel = null; MochiPrefab = LoadBundleAssetWithFallback<GameObject>("assets/葱音未来_by_翼月生/scallionmiku.prefab", PrefabNameHints); MochiMaterial = LoadBundleAssetWithFallback<Material>("assets/葱音未来_by_翼月生/materials/scallionmiku-8.shintai.mat", MaterialNameHints); MochiTexture = externalIconTexture ?? LoadBundleAssetWithFallback<Texture2D>("assets/葱音未来_by_翼月生/textures/身体.png", IconTextureNameHints); Texture2D val = LoadBundleAssetWithFallback<Texture2D>("assets/葱音未来_by_翼月生/textures/身体.png", MainTextureNameHints); MikuMainTexture = CreateReadableTexture(val) ?? val; if ((Object)(object)MochiPrefab == (Object)null) { Log.LogError((object)"Failed to load replacement prefab from asset bundle."); Bundle.Unload(false); Bundle = null; return false; } _bundledReplacementBaseScale = CalculateBundledReplacementBaseScale(MochiPrefab); ConfigureMochiMaterial(MikuMainTexture); RuntimeMikuMaterial = CreateRuntimeMikuMaterial(MikuMainTexture); ItemPatch.SanitizeLoadedPrefabRendererMaterials(MochiPrefab, "TryLoadReplacementBundle"); if ((Object)(object)RuntimeMikuMaterial == (Object)null) { Log.LogWarning((object)"Runtime fallback material was not created. The bundled material will be used when available."); } if ((Object)(object)MochiTexture == (Object)null) { Log.LogWarning((object)"Failed to load replacement icon texture."); } if ((Object)(object)MikuMainTexture == (Object)null) { Log.LogWarning((object)"Failed to load replacement main texture."); } VerboseLog("Loaded ScallionMiku replacement from asset bundle: " + bundlePath); return true; } private static Vector3 CalculateBundledReplacementBaseScale(GameObject prefab) { //IL_0009: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { return DefaultBundledReplacementBaseScale; } Vector3 val; if (!TryCalculatePrefabBounds(prefab.transform, out var combinedBounds, out var rendererCount)) { ManualLogSource log = Log; val = DefaultBundledReplacementBaseScale; log.LogWarning((object)("Failed to calculate bundled prefab bounds. Falling back to default bundle base scale: " + ((Vector3)(ref val)).ToString("F4"))); return DefaultBundledReplacementBaseScale; } float num = Mathf.Max(((Bounds)(ref combinedBounds)).size.y, 0.0001f); float num2 = RuntimeReferenceVisibleSizeAtBaseScale.y * 0.78f * 1.5f; float num3 = Mathf.Clamp(num2 / num, 0.04f, 1.2f); Vector3 result = default(Vector3); ((Vector3)(ref result))..ctor(num3, num3, num3); string[] obj = new string[8] { "Auto-calculated ScallionMiku bundle base scale. rendererCount=", rendererCount.ToString(CultureInfo.InvariantCulture), ", prefabBoundsSize=", null, null, null, null, null }; val = ((Bounds)(ref combinedBounds)).size; obj[3] = ((Vector3)(ref val)).ToString("F4"); obj[4] = ", targetHeight="; obj[5] = num2.ToString("F4", CultureInfo.InvariantCulture); obj[6] = ", baseScale="; obj[7] = ((Vector3)(ref result)).ToString("F4"); VerboseLog(string.Concat(obj)); return result; } private static bool TryCalculatePrefabBounds(Transform root, out Bounds combinedBounds, out int rendererCount) { //IL_0001: 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_005d: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_0101: Unknown result type (might be due to invalid IL or missing references) combinedBounds = default(Bounds); rendererCount = 0; if ((Object)(object)root == (Object)null) { return false; } bool hasBounds = false; Matrix4x4 worldToLocalMatrix = root.worldToLocalMatrix; MeshRenderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { MeshFilter component = ((Component)val).GetComponent<MeshFilter>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null)) { AppendTransformedBounds(worldToLocalMatrix, ((Component)val).transform.localToWorldMatrix, component.sharedMesh.bounds, ref combinedBounds, ref hasBounds); rendererCount++; } } } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.sharedMesh == (Object)null)) { Bounds localBounds = ((Renderer)val2).localBounds; Vector3 size = ((Bounds)(ref localBounds)).size; Bounds sourceBounds = ((((Vector3)(ref size)).sqrMagnitude > 1E-06f) ? ((Renderer)val2).localBounds : val2.sharedMesh.bounds); AppendTransformedBounds(worldToLocalMatrix, ((Component)val2).transform.localToWorldMatrix, sourceBounds, ref combinedBounds, ref hasBounds); rendererCount++; } } return hasBounds; } private static void AppendTransformedBounds(Matrix4x4 rootWorldToLocal, Matrix4x4 childLocalToWorld, Bounds sourceBounds, ref Bounds combinedBounds, ref bool hasBounds) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_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) //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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0045: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_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_005e: Unknown result type (might be due to invalid IL or missing references) Matrix4x4 val = rootWorldToLocal * childLocalToWorld; Vector3 center = ((Bounds)(ref sourceBounds)).center; Vector3 extents = ((Bounds)(ref sourceBounds)).extents; for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { Vector3 val2 = center + Vector3.Scale(extents, new Vector3((float)i, (float)j, (float)k)); Vector3 val3 = ((Matrix4x4)(ref val)).MultiplyPoint3x4(val2); if (!hasBounds) { combinedBounds = new Bounds(val3, Vector3.zero); hasBounds = true; } else { ((Bounds)(ref combinedBounds)).Encapsulate(val3); } } } } } private static string ResolveBundlePath() { return Path.Combine(directory, "ScallionMiku"); } private Texture2D LoadExternalIconTexture() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_00aa: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(directory, "ScallionMikuUI.png"); if (!File.Exists(text)) { return null; } try { using FileStream fileStream = File.OpenRead(text); Bitmap val = new Bitmap((Stream)fileStream); try { int width = ((Image)val).Width; int height = ((Image)val).Height; Color32[] array = (Color32[])(object)new Color32[width * height]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { Color pixel = val.GetPixel(j, height - 1 - i); array[i * width + j] = new Color32(pixel.R, pixel.G, pixel.B, pixel.A); } } Texture2D val2 = new Texture2D(width, height, (TextureFormat)4, false, false) { name = Path.GetFileNameWithoutExtension(text) }; val2.SetPixels32(array); ((Texture)val2).filterMode = (FilterMode)1; ((Texture)val2).wrapMode = (TextureWrapMode)1; ((Texture)val2).anisoLevel = 1; val2.Apply(false, false); return val2; } finally { ((IDisposable)val)?.Dispose(); } } catch (Exception ex) { Log.LogWarning((object)("Failed to load external icon texture '" + text + "': " + ex.Message)); return null; } } internal static GameObject CreateReplacementVisualInstance(string name) { if (RuntimeReplacementModel != null) { return RuntimeReplacementModel.Instantiate(name); } if ((Object)(object)MochiPrefab == (Object)null) { return null; } return Object.Instantiate<GameObject>(MochiPrefab); } internal static void VerboseLog(string message) { } private static T LoadBundleAssetWithFallback<T>(string preferredPath, params string[] nameHints) where T : Object { if ((Object)(object)Bundle == (Object)null) { return default(T); } if (!string.IsNullOrEmpty(preferredPath)) { T val = Bundle.LoadAsset<T>(preferredPath); if ((Object)(object)val != (Object)null) { return val; } } string[] allAssetNames = Bundle.GetAllAssetNames(); if (allAssetNames != null) { foreach (string text in allAssetNames) { if (AssetNameLooksRelevant(text, preferredPath, nameHints)) { T val2 = Bundle.LoadAsset<T>(text); if ((Object)(object)val2 != (Object)null) { VerboseLog("Loaded fallback " + typeof(T).Name + " from bundle path: " + text); return val2; } } } } T[] array = Bundle.LoadAllAssets<T>(); if (array == null || array.Length == 0) { Log.LogWarning((object)("No " + typeof(T).Name + " assets found in bundle for requested path: " + preferredPath)); return default(T); } T val3 = FindAssetByObjectName(array, preferredPath, nameHints); if ((Object)(object)val3 != (Object)null) { VerboseLog("Loaded fallback " + typeof(T).Name + " by object name: " + ((Object)val3).name); return val3; } if (array.Length == 1) { Log.LogWarning((object)("Loaded only available " + typeof(T).Name + " asset as fallback: " + ((Object)array[0]).name)); return array[0]; } Log.LogWarning((object)("Unable to identify " + typeof(T).Name + " for requested path '" + preferredPath + "'. Candidates: " + string.Join(", ", Array.ConvertAll(array, (T asset) => (!((Object)(object)asset != (Object)null)) ? "<null>" : ((Object)asset).name)))); return default(T); } private static T FindAssetByObjectName<T>(T[] assets, string preferredPath, string[] nameHints) where T : Object { string needle = (string.IsNullOrEmpty(preferredPath) ? string.Empty : Path.GetFileNameWithoutExtension(preferredPath)); foreach (T val in assets) { if (!((Object)(object)val == (Object)null)) { string value = ((Object)val).name ?? string.Empty; if (NameMatches(value, needle) || NameMatchesAnyHint(value, nameHints)) { return val; } } } return default(T); } private static bool AssetNameLooksRelevant(string assetName, string preferredPath, string[] nameHints) { if (string.IsNullOrEmpty(assetName)) { return false; } if (!string.IsNullOrEmpty(preferredPath)) { if (assetName.Equals(preferredPath, StringComparison.OrdinalIgnoreCase)) { return true; } string fileName = Path.GetFileName(preferredPath); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(preferredPath); if (!string.IsNullOrEmpty(fileName) && assetName.EndsWith(fileName, StringComparison.OrdinalIgnoreCase)) { return true; } if (NameMatches(assetName, fileNameWithoutExtension)) { return true; } } return NameMatchesAnyHint(assetName, nameHints); } private static bool NameMatchesAnyHint(string value, string[] hints) { if (string.IsNullOrEmpty(value) || hints == null) { return false; } for (int i = 0; i < hints.Length; i++) { if (NameMatches(value, hints[i])) { return true; } } return false; } private static bool NameMatches(string value, string needle) { if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(needle)) { return false; } return value.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0; } private static void ConfigureMochiMaterial(Texture2D mikuMainTexture) { if ((Object)(object)MochiMaterial == (Object)null) { return; } if ((Object)(object)MochiMaterial.shader == (Object)null || !MochiMaterial.shader.isSupported) { Shader val = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); if ((Object)(object)val != (Object)null) { MochiMaterial.shader = val; } } if ((Object)(object)mikuMainTexture != (Object)null) { ApplyTextureSet(MochiMaterial, mikuMainTexture); } ApplyMikuColorStyle(MochiMaterial); VerboseLog("Configured bundled material: " + ((Object)MochiMaterial).name); } private static bool TryAssignTextureIfMissing(Material material, string propertyName, Texture2D texture) { //IL_0043: 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) if ((Object)(object)material == (Object)null || (Object)(object)texture == (Object)null || string.IsNullOrEmpty(propertyName) || !material.HasProperty(propertyName)) { return false; } try { if ((Object)(object)material.GetTexture(propertyName) != (Object)null) { return false; } material.SetTexture(propertyName, (Texture)(object)texture); material.SetTextureScale(propertyName, Vector2.one); material.SetTextureOffset(propertyName, Vector2.zero); return true; } catch (Exception ex) { VerboseLog("Skip texture assignment on material '" + ((Object)material).name + "', property '" + propertyName + "': " + ex.Message); return false; } } private static void TryAssignTextureIfMissing(Material material, string[] propertyNames, Texture2D texture) { if (!((Object)(object)material == (Object)null) && !((Object)(object)texture == (Object)null) && propertyNames != null) { for (int i = 0; i < propertyNames.Length; i++) { TryAssignTextureIfMissing(material, propertyNames[i], texture); } } } private static void ApplyTextureSet(Material material, Texture2D albedo) { if (!((Object)(object)material == (Object)null)) { TryAssignTextureIfMissing(material, PreferredTextureProps, albedo); ApplyMikuColorStyle(material); } } private static void ApplyMikuColorStyle(Material material) { //IL_001d: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)material == (Object)null)) { if (material.HasProperty("_Tint")) { material.SetColor("_Tint", MikuStyleTint); } if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", MikuStyleTint); } if (material.HasProperty("_Color")) { material.SetColor("_Color", MikuStyleTint); } if (material.HasProperty("_Smoothness")) { material.SetFloat("_Smoothness", 0.3f); } if (material.HasProperty("_Glossiness")) { material.SetFloat("_Glossiness", 0.3f); } if (material.HasProperty("_Metallic")) { material.SetFloat("_Metallic", 0f); } if (material.HasProperty("_BumpScale")) { material.SetFloat("_BumpScale", 0f); } if (material.HasProperty("_OcclusionStrength")) { material.SetFloat("_OcclusionStrength", 0f); } if (material.HasProperty("_SpecularHighlights")) { material.SetFloat("_SpecularHighlights", 0f); } if (material.HasProperty("_EnvironmentReflections")) { material.SetFloat("_EnvironmentReflections", 0f); } if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", Color.black); material.DisableKeyword("_EMISSION"); } material.DisableKeyword("_NORMALMAP"); material.DisableKeyword("_METALLICSPECGLOSSMAP"); material.DisableKeyword("_OCCLUSIONMAP"); } } private static Texture2D CreateReadableTexture(Texture2D source) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown if ((Object)(object)source == (Object)null) { return null; } try { source.GetPixel(0, 0); return source; } catch { } RenderTexture temporary = RenderTexture.GetTemporary(((Texture)source).width, ((Texture)source).height, 0, (RenderTextureFormat)0); RenderTexture active = RenderTexture.active; try { Graphics.Blit((Texture)(object)source, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, true, false) { name = ((Object)source).name + "_Readable" }; val.ReadPixels(new Rect(0f, 0f, (float)((Texture)source).width, (float)((Texture)source).height), 0, 0); val.Apply(true, false); return val; } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); } } private static Material CreateRuntimeMikuMaterial(Texture2D texture) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown Shader val = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("W/Peak_Standard"); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Failed to create runtime material because no compatible shader was found."); return null; } Material val2 = new Material(val) { name = "Miku_RuntimeMaterial", renderQueue = 2000, color = Color.white }; if ((Object)(object)texture != (Object)null) { TryAssignTextureIfMissing(val2, "_BaseMap", texture); TryAssignTextureIfMissing(val2, "_MainTex", texture); } if (val2.HasProperty("_Surface")) { val2.SetFloat("_Surface", 0f); } if (val2.HasProperty("_Blend")) { val2.SetFloat("_Blend", 0f); } if (val2.HasProperty("_ZWrite")) { val2.SetFloat("_ZWrite", 1f); } if (val2.HasProperty("_Cull")) { val2.SetFloat("_Cull", 0f); } val2.SetOverrideTag("RenderType", "Opaque"); val2.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); val2.EnableKeyword("_SURFACE_TYPE_OPAQUE"); ApplyMikuColorStyle(val2); return val2; } } public class MikuMarker : MonoBehaviour { public bool HasAppliedState; public int LastRefreshRevision = -1; public int LastLayer = int.MinValue; public ItemState LastItemState; public bool LastShouldShow; public bool HiddenByOriginalRule; public Vector3 LastLocalPosition; public Quaternion LastLocalRotation = Quaternion.identity; public Vector3 LastLocalScale; } public class MikuCollisionMarker : MonoBehaviour { } public class MikuTwinTailClothState : MonoBehaviour { public int MeshInstanceId; public int MovableVertexCount; } public class MikuScaleRefreshGuard : MonoBehaviour { private bool _pendingRefresh; private bool _hardReset; private int _targetFrame = -1; private bool _clothSuspendedForPause; public void QueueRefresh(bool hardReset) { _pendingRefresh = true; _hardReset |= hardReset; _targetFrame = Mathf.Max(_targetFrame, Time.frameCount + 1); } private void LateUpdate() { bool flag = Time.timeScale <= 0.0001f; if (flag) { SuspendClothsForPause(); } else if (_clothSuspendedForPause) { ResumeClothsAfterPause(); } if (_pendingRefresh && Time.frameCount >= _targetFrame) { _pendingRefresh = false; _targetFrame = -1; RefreshSkinnedMeshes(); RefreshCloths(_hardReset || flag); _hardReset = false; } } private void RefreshSkinnedMeshes() { //IL_0059: 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_003f: 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_006b: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } val.updateWhenOffscreen = true; Vector3 size; Bounds val2; if ((Object)(object)val.sharedMesh != (Object)null) { Bounds bounds = val.sharedMesh.bounds; size = ((Bounds)(ref bounds)).size; if (((Vector3)(ref size)).sqrMagnitude > 1E-06f) { val2 = val.sharedMesh.bounds; goto IL_006b; } } val2 = ((Renderer)val).localBounds; goto IL_006b; IL_006b: Bounds localBounds = val2; size = ((Bounds)(ref localBounds)).size; if (((Vector3)(ref size)).sqrMagnitude > 1E-06f) { ((Bounds)(ref localBounds)).Expand(new Vector3(0.2f, 0.25f, 0.2f)); ((Renderer)val).localBounds = localBounds; } } } private void RefreshCloths(bool hardReset) { Cloth[] componentsInChildren = ((Component)this).GetComponentsInChildren<Cloth>(true); foreach (Cloth val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } val.ClearTransformMotion(); if (hardReset && val.enabled) { val.enabled = false; if (!_clothSuspendedForPause) { val.enabled = true; } } val.ClearTransformMotion(); } } private void SuspendClothsForPause() { Cloth[] componentsInChildren = ((Component)this).GetComponentsInChildren<Cloth>(true); foreach (Cloth val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { val.ClearTransformMotion(); if (val.enabled) { val.enabled = false; } } } _clothSuspendedForPause = true; } private void ResumeClothsAfterPause() { RefreshSkinnedMeshes(); Cloth[] componentsInChildren = ((Component)this).GetComponentsInChildren<Cloth>(true); foreach (Cloth val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { val.enabled = true; val.ClearTransformMotion(); } } _clothSuspendedForPause = false; } } public class MikuDeformGuard : MonoBehaviour { private const float SqueezeDuration = 0.78f; private const float SqueezeCompressPhase = 0.42f; private Transform[] _allTransforms = Array.Empty<Transform>(); private Vector3[] _initialChildScales = Array.Empty<Vector3>(); private Vector3 _rootLocalPosition; private Quaternion _rootLocalRotation; private Vector3 _rootLocalScale; private Item _boundItem; private bool _wasUsing; private float _squeezeElapsed = 0.78f; internal Item BoundItem => _boundItem; public void Initialize(Vector3 rootLocalPosition, Quaternion rootLocalRotation, Vector3 rootLocalScale) { //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) //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) _rootLocalPosition = rootLocalPosition; _rootLocalRotation = rootLocalRotation; _rootLocalScale = rootLocalScale; _wasUsing = false; _squeezeElapsed = 0.78f; Capture(); } public void Bind(Item item) { _boundItem = item; } public void SetRootTarget(Vector3 rootLocalPosition, Quaternion rootLocalRotation, Vector3 rootLocalScale) { //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) //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) _rootLocalPosition = rootLocalPosition; _rootLocalRotation = rootLocalRotation; _rootLocalScale = rootLocalScale; } private bool IsHeldAndUsing() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if ((Object)(object)_boundItem != (Object)null && (int)_boundItem.itemState == 1) { if (!_boundItem.isUsingPrimary) { return _boundItem.isUsingSecondary; } return true; } return false; } private void UpdateSingleSqueezeState() { bool flag = IsHeldAndUsing(); if (flag && !_wasUsing) { _squeezeElapsed = 0f; } _wasUsing = flag; if (_squeezeElapsed < 0.78f) { _squeezeElapsed += Time.deltaTime; } } private float EvaluateSingleSqueezeWeight() { if (_squeezeElapsed >= 0.78f) { return 0f; } float num = Mathf.Clamp01(_squeezeElapsed / 0.78f); if (num <= 0.42f) { return Mathf.SmoothStep(0f, 1f, num / 0.42f); } float num2 = (num - 0.42f) / 0.58000004f; return Mathf.SmoothStep(1f, 0f, Mathf.Clamp01(num2)); } private Vector3 GetDesiredRootScale(float squeezeWeight) { //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_0044: 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) if (squeezeWeight <= 0.0005f) { return _rootLocalScale; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(1f - 0.14f * squeezeWeight, 1f + 0.11f * squeezeWeight, 1f - 0.14f * squeezeWeight); return Vector3.Scale(_rootLocalScale, val); } public void Capture() { //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) _allTransforms = ((Component)this).GetComponentsInChildren<Transform>(true); _initialChildScales = (Vector3[])(object)new Vector3[_allTransforms.Length]; for (int i = 0; i < _allTransforms.Length; i++) { _initialChildScales[i] = _allTransforms[i].localScale; } } private void LateUpdate() { //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_0050: 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_0040: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if (_allTransforms.Length == 0 || _allTransforms.Length != _initialChildScales.Length) { Capture(); } if (((Component)this).transform.localPosition != _rootLocalPosition) { ((Component)this).transform.localPosition = _rootLocalPosition; } if (((Component)this).transform.localRotation != _rootLocalRotation) { ((Component)this).transform.localRotation = _rootLocalRotation; } UpdateSingleSqueezeState(); float squeezeWeight = EvaluateSingleSqueezeWeight(); Vector3 desiredRootScale = GetDesiredRootScale(squeezeWeight); if (((Component)this).transform.localScale != desiredRootScale) { ((Component)this).transform.localScale = desiredRootScale; } for (int i = 0; i < _allTransforms.Length; i++) { Transform val = _allTransforms[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)((Component)this).transform) && val.localScale != _initialChildScales[i]) { val.localScale = _initialChildScales[i]; } } } } public class MikuRendererGuard : MonoBehaviour { private const float RefreshInterval = 0.1f; private float _nextRefreshTime; private Item _boundItem; private Renderer[] _cachedRenderers = Array.Empty<Renderer>(); internal Item BoundItem => _boundItem; public void Bind(Item item) { _boundItem = item; } private void LateUpdate() { if (!Plugin.ModEnabled || !Plugin.EnableVisibilityGuard) { return; } MikuMarker component = ((Component)this).GetComponent<MikuMarker>(); if ((Object)(object)component != (Object)null && component.HiddenByOriginalRule) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup < _nextRefreshTime) { return; } _nextRefreshTime = realtimeSinceStartup + 0.1f; if (!((Component)this).gameObject.activeSelf) { ((Component)this).gameObject.SetActive(true); } int num = (((Object)(object)_boundItem != (Object)null) ? ((Component)_boundItem).gameObject.layer : ((Component)this).gameObject.layer); if (((Component)this).gameObject.layer != num) { ((Component)this).gameObject.layer = num; } Renderer[] renderableChildren = GetRenderableChildren(); foreach (Renderer val in renderableChildren) { if (!((Object)(object)val == (Object)null)) { EnsureRendererVisible(val, num); } } } private Renderer[] GetRenderableChildren() { if (_cachedRenderers.Length == 0 || HasNullRenderer(_cachedRenderers)) { _cachedRenderers = ((Component)this).GetComponentsInChildren<Renderer>(true); } return _cachedRenderers; } private static bool HasNullRenderer(Renderer[] renderers) { for (int i = 0; i < renderers.Length; i++) { if ((Object)(object)renderers[i] == (Object)n