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 System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using AtlyssShlongs.Core; using AtlyssShlongs.Data; using AtlyssShlongs.Equipment; using AtlyssShlongs.Input; using AtlyssShlongs.Network; using AtlyssShlongs.Patches; using AtlyssShlongs.UI; using AtlyssShlongs.Util; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CodeTalker.Networking; using CodeTalker.Packets; using HarmonyLib; using MonoMod.RuntimeDetour; using TemtemTests; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyFileVersion("3.1.0.0")] [assembly: AssemblyInformationalVersion("3.1.0")] [assembly: AssemblyCompany("AtlyssShlongs")] [assembly: AssemblyProduct("AtlyssShlongs")] [assembly: AssemblyTitle("AtlyssShlongs")] [assembly: AssemblyConfiguration("Debug")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.1.0.0")] [module: UnverifiableCode] namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace TemtemTests { [Flags] public enum SyncField : ushort { None = 0, Position = 1, Scale = 2, BallsSize = 4, Preset = 8, Arousal = 0x10, Futa = 0x20, Clothing = 0x40, Rotation = 0x80, ErectAngle = 0x100, Color = 0x200, BodyParts = 0x400, BallColor = 0x800, Hide = 0x1000, Bulge = 0x2000, All = 0x3FFF } public class ShlongSyncPacket : PacketBase { internal const int ColorWireOffset = 1000000; internal const int ColorWireScale = 10000; public override string PacketSourceGUID => "com.atlyss.shlongs"; public ushort ChangedFields { get; set; } public float DickOffsetX { get; set; } public float DickOffsetY { get; set; } public float DickSizeOffset { get; set; } public float BallsSizeOffset { get; set; } public int CurrentDick { get; set; } public float ArousalTarget { get; set; } public bool FutaToggle { get; set; } public bool ClothingOverride { get; set; } public float BaseRotationX { get; set; } public float BaseRotationY { get; set; } public float BaseRotationZ { get; set; } public float ErectAngleOffset { get; set; } public float ScaleX { get; set; } public float ScaleY { get; set; } public float ScaleZ { get; set; } public float ColorR { get; set; } = 1f; public float ColorG { get; set; } = 1f; public float ColorB { get; set; } = 1f; public int ColorMode { get; set; } public bool MatchBody { get; set; } public int TextureSourceMode { get; set; } public string BodyPartsData { get; set; } public float BallColorR { get; set; } = 1f; public float BallColorG { get; set; } = 1f; public float BallColorB { get; set; } = 1f; public int BallColorMode { get; set; } public bool BallMatchBody { get; set; } = true; public int BallTextureSourceMode { get; set; } public bool HideToggle { get; set; } public float BulgeAmount { get; set; } public float BulgePosition { get; set; } public float BulgeWidth { get; set; } = 1f; public float BulgeSharpness { get; set; } = 1f; public float BulgeLerpSpeed { get; set; } = 2f; public int ColorRWire { get; set; } public int ColorGWire { get; set; } public int ColorBWire { get; set; } public int BallColorRWire { get; set; } public int BallColorGWire { get; set; } public int BallColorBWire { get; set; } public int MatchBodyWire { get; set; } public int BallMatchBodyWire { get; set; } internal static int EncodeColorWire(float v) { float num = ((v < -100f) ? (-100f) : ((v > 100f) ? 100f : v)); return 1000000 + (int)Math.Round(num * 10000f); } internal static float DecodeColorWire(int encoded) { return (float)(encoded - 1000000) / 10000f; } internal static bool HasColorWire(int encoded) { return encoded != 0; } internal static int EncodeBoolWire(bool value) { return (!value) ? 1 : 2; } internal static bool HasBoolWire(int encoded) { return encoded == 1 || encoded == 2; } internal static bool DecodeBoolWire(int encoded, bool fallback) { return encoded switch { 1 => false, 2 => true, _ => fallback, }; } } } namespace AtlyssShlongs { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.atlyss.shlongs", "AtlyssShlongs", "3.1.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static AssetManager Assets; internal static PresetRegistry Presets; internal static NetworkManager Network; internal static Dictionary Controllers; internal static ProfileSaveData[] LoadedProfiles; internal static ConfigEntry DebugMode; internal static UserPresetManager UserPresets; internal static bool CharMenuON; internal static string LocalSteamId; private SettingsWindow _settingsWindow; private bool _runtimeHooksInstalled; private static bool _listenerRegistered; private float _lastUpdateTime; private bool _bundleLoaded; private static readonly object _logLimitLock = new object(); private static readonly Dictionary _logLimitCounts = new Dictionary(); internal static bool IsDebug => DebugMode != null && DebugMode.Value; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; LoadedProfiles = new ProfileSaveData[120]; UserPresets = new UserPresetManager(Paths.ConfigPath); CosmeticDisplayManager.Initialize(); PluginConfig.Initialize(((BaseUnityPlugin)this).Config); DebugMode = PluginConfig.DebugMode; InputManager.Initialize(((BaseUnityPlugin)this).Config); } private void Start() { Controllers = new Dictionary(); Presets = new PresetRegistry(); bool flag = PluginConfig.EnableLifecycleDiagnostics != null && PluginConfig.EnableLifecycleDiagnostics.Value; bool flag2 = PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value; if (PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && !PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value) { if (IsDebug) { Log.LogWarning((object)"Fix 101/102 diagnostic mode was disabled by the persisted config. Forcing BlockCloneRuntimeSpawnForDiagnostics=true so the attach-vs-spawn experiment is actually exercised."); } PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value = true; ((BaseUnityPlugin)this).Config.Save(); } bool flag3 = PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value; bool flag4 = PluginConfig.EnableLocalCosmeticDisplay != null && PluginConfig.EnableLocalCosmeticDisplay.Value; if (IsDebug) { LogDebug("Diagnostics config: Lifecycle=" + flag + ", RequestedBlockCloneRuntimeSpawn=" + flag2 + ", EffectiveBlockCloneRuntimeSpawn=" + flag3 + ", EnableLocalCosmeticDisplay=" + flag4); if (flag3) { LogDebug("Fix 105 diagnostic mitigation is ACTIVE: gameplay clone runtime rig creation will be blocked for both local and non-local players because the latest log showed local clone visibility restoration reintroduced the map-transition failure."); } } _settingsWindow = new SettingsWindow(); _settingsWindow.InitSectionConfig(((BaseUnityPlugin)this).Config); Assets = new AssetManager(Log); if (!Assets.LoadBundle(((BaseUnityPlugin)this).Info.Location)) { LogErrorLimited("plugin.bundle_load_failed", "AssetBundle load failed — plugin will not function.", 1); return; } _bundleLoaded = true; Assets.LoadPresetPrefabs(Presets.GetAllPresets()); Network = new NetworkManager(Controllers, Log); TryInitExtension("AtlyssShlongs.UI.ColorModeExtension"); LoadingDiagnostics.EnsureSceneHook(); TransitionWatchdog.Start(); LogDebug("AtlyssShlongs v3 plugin loaded!"); } private void Update() { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Invalid comparison between Unknown and I4 //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) try { if (_settingsWindow != null) { _settingsWindow.Update(); } else { LogWarningLimited("plugin.settings_window_null", "[GUI] SettingsWindow is null; GUI hotkey cannot open the window. Check AssetBundle load / Start() path.", 1); } } catch (Exception ex) { LogWarningLimited("plugin.settings_window_update", "[GUI] SettingsWindow.Update failed: " + ex.GetType().Name + ": " + ex.Message); } if (IsDebug && _lastUpdateTime > 0f) { float num = Time.unscaledTime - _lastUpdateTime; if (num > 5f) { LogDebug("[Stall] Update gap=" + num.ToString("F2") + "s frame=" + Time.frameCount); } } _lastUpdateTime = Time.unscaledTime; bool flag = (Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 0; TransitionWatchdog.Tick(); if (flag) { return; } try { if ((Object)(object)Player._mainPlayer != (Object)null) { LocalSteamId = Player._mainPlayer.Network_steamID; } } catch { } Network?.ProcessPending(); if (IsDebug) { LoadingDiagnostics.PeriodicDump(); } if (!_runtimeHooksInstalled && ShouldInstallRuntimeHooks()) { InstallRuntimeHooks(); } if (Time.frameCount % 600 == 0) { CharMenuON = (Object)(object)Object.FindObjectOfType() != (Object)null; } if (_runtimeHooksInstalled && Time.frameCount % 1800 == 0) { try { PlayerRaceModel[] array = Object.FindObjectsOfType(); foreach (PlayerRaceModel val in array) { if (!((Object)(object)val == (Object)null) && (Object)(object)((Component)val).GetComponent() == (Object)null) { RaceModelPatch.AttachToRaceModel(val); } } } catch (Exception ex2) { LogWarningLimited("plugin.sweep", "[Sweep] Exception: " + ex2.Message); } } if (_runtimeHooksInstalled && Time.frameCount % 600 == 0) { ModelAttacher.PurgeDestroyedEntries(); } if (DebugMode != null && DebugMode.Value && Time.frameCount % 600 == 0) { string[] obj2 = new string[15] { "[Heartbeat] frame=", Time.frameCount.ToString(), " controllers=", ((Controllers != null) ? Controllers.Count : 0).ToString(), " allInstances=", ShlongController.AllInstances.Count.ToString(), " activeDicks=", ModelAttacher.ActiveDickMeshObjects.Count.ToString(), " cosmeticRigs=", CosmeticDisplayManager.ActiveCount.ToString(), " gameCondition=", ((Object)(object)Player._mainPlayer != (Object)null) ? ((object)Unsafe.As(ref Player._mainPlayer._currentGameCondition)/*cast due to .constrained prefix*/).ToString() : "null", " scene=", null, null }; Scene activeScene = SceneManager.GetActiveScene(); obj2[13] = ((Scene)(ref activeScene)).name; obj2[14] = LifecycleDiagnostics.BuildHeartbeatSnapshot(); LogDebug(string.Concat(obj2)); } CosmeticDisplayManager.Tick(); } private void OnGUI() { _settingsWindow?.OnGUI(); } private void LateUpdate() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 if (!((Object)(object)Player._mainPlayer != (Object)null) || (int)Player._mainPlayer._currentGameCondition != 0) { CosmeticDisplayManager.UpdateDisplay(); } } private bool ShouldInstallRuntimeHooks() { if (!_bundleLoaded) { return false; } return (Object)(object)Object.FindObjectOfType() != (Object)null || (Object)(object)Object.FindObjectOfType() != (Object)null; } private void InstallRuntimeHooks() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown Harmony val = new Harmony("com.atlyss.shlongs.v3"); val.PatchAll(); RaceModelPatch.Install(); if (!_listenerRegistered && Network != null) { if (Network.RegisterListener()) { _listenerRegistered = true; LogDebug("CodeTalker listener registered"); } else { LogErrorLimited("plugin.codetlaker_listener", "Failed to register CodeTalker listener (duplicate?)"); } } PlayerRaceModel[] array = Object.FindObjectsOfType(); foreach (PlayerRaceModel self in array) { RaceModelPatch.AttachToRaceModel(self); } _runtimeHooksInstalled = true; LogDebug("AtlyssShlongs v3 runtime hooks installed."); } private static void TryInitExtension(string fullTypeName) { try { Type type = FindTypeInAllAssemblies(fullTypeName); if (!(type == null)) { type.GetMethod("Initialize", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(null, null); LogDebug("Extension initialized: " + fullTypeName); } } catch (Exception ex) { LogWarningLimited("plugin.extension." + fullTypeName, fullTypeName + " init failed: " + ex.Message); } } private static Type FindTypeInAllAssemblies(string fullTypeName) { Type type = Type.GetType(fullTypeName); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { type = assembly.GetType(fullTypeName); if (type != null) { return type; } } return null; } internal static void LogDebug(string message) { if (IsDebug && Log != null) { Log.LogInfo((object)("[DBG] " + message)); } } internal static void LogWarningLimited(string key, string message, int maxCount = 2) { if (Log == null) { return; } lock (_logLimitLock) { _logLimitCounts.TryGetValue(key, out var value); if (value >= maxCount) { return; } _logLimitCounts[key] = value + 1; } Log.LogWarning((object)message); } internal static void LogErrorLimited(string key, string message, int maxCount = 2) { if (Log == null) { return; } lock (_logLimitLock) { _logLimitCounts.TryGetValue(key, out var value); if (value >= maxCount) { return; } _logLimitCounts[key] = value + 1; } Log.LogError((object)message); } } public static class PluginConfig { public static ConfigEntry DebugMode; public static ConfigEntry EnableLifecycleDiagnostics; public static ConfigEntry BlockCloneRuntimeSpawnForDiagnostics; public static ConfigEntry EnableLocalCosmeticDisplay; public static ConfigEntry ShowShlongInCharacterSelect; public static ConfigEntry HideOtherPlayersShlongs; private static ConfigEntry CharacterSelectVisibilityDefaultOffMigrationApplied; public static ConfigEntry HotkeysEnabled; public static ConfigEntry EnableRemoteJiggleExperimental; public static ConfigEntry RemoteJiggleStrength; public static ConfigEntry RemoteJiggleStiffness; public static ConfigEntry RemoteJiggleDamping; public static ConfigEntry RemoteJiggleMaxDegrees; public static ConfigEntry EnableLocalCosmeticJiggleExperimental; public static ConfigEntry RemoteJiggleDebugPulse; public static ConfigEntry RemoteJiggleDebugPulseRoot; public static ConfigEntry RemoteJiggleVelocityToDegrees; public static ConfigEntry RemoteJiggleAngularToDegrees; public static ConfigEntry RemoteJiggleMinimumKick; public static ConfigEntry RemoteJiggleMode; public static ConfigEntry ApplyCharacterHbcToMatchedShlongs; public const string RemoteJiggleModeProcedural = "Procedural"; public const string RemoteJiggleModeNativeDynamicBone = "NativeDynamicBoneExperimental"; public static bool UseNativeRemoteDynamicBone => EnableRemoteJiggleExperimental != null && EnableRemoteJiggleExperimental.Value && RemoteJiggleMode != null && RemoteJiggleMode.Value == "NativeDynamicBoneExperimental"; public static void Initialize(ConfigFile config) { DebugMode = config.Bind("Debug", "Enable Debug Logging", false, "When enabled, detailed debug logs are written to the BepInEx console."); EnableLifecycleDiagnostics = config.Bind("Debug", "Enable Lifecycle Diagnostics", true, "Track attach/spawn/register/unregister lifecycle counters and include them in heartbeat logs."); BlockCloneRuntimeSpawnForDiagnostics = config.Bind("Debug", "Block Clone Runtime Spawn For Diagnostics", true, "Diagnostic mitigation: skip creating runtime dick rigs for all player clones during gameplay. Enabled by default because current evidence shows even the local gameplay clone rig can reintroduce map-transition failures."); EnableLocalCosmeticDisplay = config.Bind("Gameplay", "Enable Local Cosmetic Display", true, "Fix 126: When clone runtime spawn is blocked, show lightweight cosmetic-only rigs for all players (local + remote). CosmeticDisplayManager creates presentation-only display rigs that are architecturally isolated from ShlongController lifecycle (no AllInstances, no teardown participation, no respawn flag). Rigs are staggered at 2/frame to avoid GPU stalls."); ShowShlongInCharacterSelect = config.Bind("Gameplay", "Show Shlong In Character Select", false, "Global default for character selection / character creation preview models. Individual character files can override this with Character Select Preview = Use Global / Show / Hide. Disabled by default so character menu previews stay hidden unless explicitly enabled."); CharacterSelectVisibilityDefaultOffMigrationApplied = config.Bind("Migrations", "Character Select Visibility Default Off Migration Applied", false, "Internal migration flag. When false, the old default-visible character menu preview setting is reset to hidden once."); if (CharacterSelectVisibilityDefaultOffMigrationApplied != null && !CharacterSelectVisibilityDefaultOffMigrationApplied.Value) { if (ShowShlongInCharacterSelect != null) { ShowShlongInCharacterSelect.Value = false; } CharacterSelectVisibilityDefaultOffMigrationApplied.Value = true; config.Save(); } HideOtherPlayersShlongs = config.Bind("Gameplay", "Hide Multiplayer Shlongs", false, "Hide shlong display rigs for other players on this client. Your own shlong and your synced state are not affected."); HotkeysEnabled = config.Bind("Keybinds", "Enable Hotkeys", true, "When disabled, all hotkeys (except Open GUI) are ignored."); EnableRemoteJiggleExperimental = config.Bind("Debug", "Enable Remote Jiggle Experimental", true, "Enables remote cosmetic jiggle. Native DynamicBone test mode is now the recommended default; disable this to turn remote jiggle off."); RemoteJiggleMode = config.Bind("Debug", "Remote Jiggle Mode", "NativeDynamicBoneExperimental", "Remote jiggle implementation. NativeDynamicBoneExperimental = recommended solo-style DynamicBone on cosmetic display rigs. Procedural = fallback custom simulation."); if (RemoteJiggleMode.Value != "Procedural" && RemoteJiggleMode.Value != "NativeDynamicBoneExperimental") { RemoteJiggleMode.Value = "Procedural"; } RemoteJiggleStrength = config.Bind("Debug", "Remote Jiggle Strength", 4.53f, "Strength multiplier for fallback procedural remote jiggle. Clamped to 0..6. Default matches the Test Soft fallback preset."); RemoteJiggleStiffness = config.Bind("Debug", "Remote Jiggle Stiffness", 30.7f, "Spring stiffness for fallback procedural remote jiggle. Default matches the Test Soft fallback preset."); RemoteJiggleDamping = config.Bind("Debug", "Remote Jiggle Damping", 0.92f, "Spring damping for fallback procedural remote jiggle. Clamped to 0..1. Default matches the Test Soft fallback preset."); RemoteJiggleMaxDegrees = config.Bind("Debug", "Remote Jiggle Max Degrees", 25.6f, "Maximum angular offset in degrees for fallback procedural remote jiggle. Clamped to 0..45. Default matches the Test Soft fallback preset."); EnableLocalCosmeticJiggleExperimental = config.Bind("Debug", "Enable Local Cosmetic Jiggle Experimental", false, "Experimental: also applies procedural jiggle to the local player's cosmetic display rig. Disabled by default to avoid double-jiggle if the local player already has a runtime rig."); RemoteJiggleDebugPulse = config.Bind("Debug", "Remote Jiggle Debug Pulse", false, "Debug: applies a visible sine-wave jiggle to cosmetic rigs to prove chain binding. If the rig visibly pulses, chains are bound. For testing only."); RemoteJiggleDebugPulseRoot = config.Bind("Debug", "Remote Jiggle Debug Pulse Root", false, "Debug: when true, applies a visible sine-wave rotation directly to the rig display root or size bone to confirm UpdateProceduralJiggle is running. Bone pulse invisible + Root pulse visible means chain binding is wrong. Default false."); RemoteJiggleVelocityToDegrees = config.Bind("Debug", "Remote Jiggle Velocity To Degrees", 7.72f, "Scales player velocity into fallback procedural jiggle angular offset. Higher = more reaction to movement. Clamped to 0..8. Default matches the Test Soft fallback preset."); RemoteJiggleAngularToDegrees = config.Bind("Debug", "Remote Jiggle Angular To Degrees", 3.47f, "Scales player rotation speed into fallback procedural jiggle angular offset. Clamped to 0..4. Default matches the Test Soft fallback preset."); RemoteJiggleMinimumKick = config.Bind("Debug", "Remote Jiggle Minimum Kick", 2.6f, "Minimum fallback procedural jiggle kick applied when the player is moving but target magnitude is small. Clamped to 0..3. Default matches the Test Soft fallback preset."); ApplyCharacterHbcToMatchedShlongs = config.Bind("Color", "Apply Character Hue Brightness Contrast", true, "Legacy compatibility key. The separate UI checkbox has been removed; Match Body Color now always carries the visible body Hue/Brightness/Contrast/Saturation layer when matching the body."); if (ApplyCharacterHbcToMatchedShlongs != null && !ApplyCharacterHbcToMatchedShlongs.Value) { ApplyCharacterHbcToMatchedShlongs.Value = true; } MigrateLegacyRemoteJiggleDefaults(config); } private static void MigrateLegacyRemoteJiggleDefaults(ConfigFile config) { if (EnableRemoteJiggleExperimental != null && !EnableRemoteJiggleExperimental.Value && RemoteJiggleMode != null && RemoteJiggleMode.Value == "Procedural" && Approximately(RemoteJiggleStrength, 0.35f) && Approximately(RemoteJiggleStiffness, 10f) && Approximately(RemoteJiggleDamping, 0.9f) && Approximately(RemoteJiggleMaxDegrees, 5f) && Approximately(RemoteJiggleVelocityToDegrees, 0.35f) && Approximately(RemoteJiggleAngularToDegrees, 0.1f) && Approximately(RemoteJiggleMinimumKick, 0.04f)) { EnableRemoteJiggleExperimental.Value = true; RemoteJiggleMode.Value = "NativeDynamicBoneExperimental"; RemoteJiggleStrength.Value = 4.53f; RemoteJiggleStiffness.Value = 30.7f; RemoteJiggleDamping.Value = 0.92f; RemoteJiggleMaxDegrees.Value = 25.6f; RemoteJiggleVelocityToDegrees.Value = 7.72f; RemoteJiggleAngularToDegrees.Value = 3.47f; RemoteJiggleMinimumKick.Value = 2.6f; config.Save(); if (Plugin.IsDebug) { Plugin.LogDebug("[ConfigMigration] Remote jiggle legacy defaults migrated to NativeDynamicBoneExperimental + Test Soft fallback values."); } } } private static bool Approximately(ConfigEntry entry, float value) { if (entry == null) { return false; } return Math.Abs(entry.Value - value) < 0.0001f; } } } namespace AtlyssShlongs.Util { public static class TransformExtensions { public static Transform RecursiveFindChild(this Transform parent, string childName) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown foreach (Transform item in parent) { Transform val = item; if (((Object)val).name == childName) { return val; } Transform val2 = val.RecursiveFindChild(childName); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } } } namespace AtlyssShlongs.UI { internal static class ColorModeExtension { private const int MODE_TINT = 0; private const int MODE_RGB = 1; private const int MODE_HEX = 2; private const int MODE_PICKER = 3; private const int MODE_HSV = 4; private static readonly string[] TabLabels = new string[5] { "Tint", "RGB", "Hex", "Picker", "HSV" }; private static readonly CultureInfo Cult = new CultureInfo("en-US"); private static bool[] _pendingColorSync = new bool[2]; private static float[] _lastColorChangeTime = new float[2]; private const int TARGET_DICK = 0; private const int TARGET_BALL = 1; private static int _editTarget; private static readonly string[] TargetLabels = new string[2] { "Shlong / Shaft", "Balls & Sheath" }; private static readonly string[] _hexInputs = new string[2] { "#FFFFFF", "#FFFFFF" }; private static readonly float[] _hues = new float[2]; private static readonly float[] _sats = new float[2] { 1f, 1f }; private static readonly float[] _vals = new float[2] { 1f, 1f }; private static Texture2D _previewTex; private static Texture2D _svTex; private static Texture2D _hueTex; private static float _svTexHue = -1f; private static int _svSize = 128; public static void Initialize() { SettingsWindow.OnDrawColorUI = DrawColorUI; ShlongController.OnApplySolidColor = ApplySolidColor; } private static bool ApplySolidColor(Material mat, Color color) { //IL_0007: 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_002a: Unknown result type (might be due to invalid IL or missing references) if (ApplySolidToProperty(mat, "_Color", color)) { return true; } if (ApplySolidToProperty(mat, "_BaseColor", color)) { return true; } return ApplySolidFallback(mat, color); } private static bool ApplySolidToProperty(Material mat, string propName, Color color) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_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) if (!mat.HasProperty(propName)) { return false; } Color color2 = mat.GetColor(propName); mat.SetColor(propName, new Color(color.r, color.g, color.b, color2.a)); return true; } private static bool ApplySolidFallback(Material mat, Color color) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //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_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) //IL_004c: 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) try { Shader shader = mat.shader; int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if ((int)shader.GetPropertyType(i) == 0) { string propertyName = shader.GetPropertyName(i); Color color2 = mat.GetColor(propertyName); mat.SetColor(propertyName, new Color(color.r, color.g, color.b, color2.a)); return true; } } } catch { } return false; } private static bool SupportsSeparateBallsSheathColor(ShlongController sc) { if ((Object)(object)sc == (Object)null) { return false; } if (Plugin.Presets != null) { PresetData preset = Plugin.Presets.GetPreset(sc.PresetIndex); if (preset != null && preset.AssetSource == PresetAssetSource.Test) { return true; } } if (sc.HasBallsSheathSlots) { return true; } return sc.BallMeshes != null && sc.BallMeshes.Length != 0; } private unsafe static void DrawColorUI(ShlongController sc) { //IL_00b6: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0574: Unknown result type (might be due to invalid IL or missing references) //IL_0579: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label("Color", GUI.skin.box, Array.Empty()); if (SupportsSeparateBallsSheathColor(sc)) { _editTarget = GUILayout.Toolbar(_editTarget, TargetLabels, Array.Empty()); GUILayout.Label("Editing: " + TargetLabels[_editTarget], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(16f) }); } else { _editTarget = 0; GUILayout.Label("Shlong / Shaft Color", GUI.skin.box, Array.Empty()); } GUILayout.Space(2f); bool flag = _editTarget == 0; Color val = (flag ? sc.ColorTint : sc.BallColorTint); int num = (flag ? sc.ColorMode : sc.BallColorMode); bool flag2 = (flag ? sc.MatchBody : sc.BallMatchBody); bool flag3 = flag2; flag2 = GUILayout.Toggle(flag2, " Match Body Color (additive tint)", Array.Empty()); if (flag2 != flag3) { if (flag) { sc.InvalidateColorMaterialCache(dick: true, balls: false); } else { sc.InvalidateColorMaterialCache(dick: false, balls: true); } val = Color.white; WriteTargetState(sc, flag, val, num, flag2); SyncHSVFromColor(val); SyncHexFromColor(val); ApplyTarget(sc, flag); bool hasBallsSheathSlots = sc.HasBallsSheathSlots; if (hasBallsSheathSlots) { CosmeticDisplayManager.ForceRefreshColorsFor(sc, dick: true, balls: true); } else { CosmeticDisplayManager.ForceRefreshColorsFor(sc, flag, !flag); } SyncField forceFields = (flag ? SyncField.Color : SyncField.BallColor); if (hasBallsSheathSlots) { forceFields = SyncField.Color | SyncField.BallColor; } if (Plugin.IsDebug) { string[] obj = new string[16] { "[ColorMatchToggle] group=", flag ? "shaft" : "balls", " split=", hasBallsSheathSlots.ToString(), " matchBody=", flag2.ToString(), " forceFields=", forceFields.ToString(), " color=", null, null, null, null, null, null, null }; Color colorTint = sc.ColorTint; obj[9] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[10] = " ballColor="; colorTint = sc.BallColorTint; obj[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[12] = " ballMatch="; obj[13] = sc.BallMatchBody.ToString(); obj[14] = " frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } _pendingColorSync[(!flag) ? 1u : 0u] = false; sc.RequestSyncImmediate(forceSave: true, forceFields); } int targetTextureSource = GetTargetTextureSource(sc, flag); bool flag4 = targetTextureSource == 0; bool flag5 = GUILayout.Toggle(flag4, " Use Body Texture", Array.Empty()); if (flag5 != flag4) { SetTargetTextureSource(sc, flag, (!flag5) ? 1 : 0); sc.InvalidateColorMaterialCache(flag, !flag); ApplyTarget(sc, flag); bool hasBallsSheathSlots2 = sc.HasBallsSheathSlots; if (hasBallsSheathSlots2) { CosmeticDisplayManager.ForceRefreshColorsFor(sc, dick: true, balls: true); } else { CosmeticDisplayManager.ForceRefreshColorsFor(sc, flag, !flag); } SyncField forceFields2 = (flag ? SyncField.Color : SyncField.BallColor); if (hasBallsSheathSlots2) { forceFields2 = SyncField.Color | SyncField.BallColor; } _pendingColorSync[(!flag) ? 1u : 0u] = false; sc.RequestSyncImmediate(forceSave: true, forceFields2); } GUILayout.Label("Off = clean solid color; Match Body Color remains a separate hue/HBC choice.", Array.Empty()); if (num < 0 || num >= TabLabels.Length) { num = 0; } int num2 = num; int num3 = GUILayout.Toolbar(num, TabLabels, Array.Empty()); if (num3 != num2) { val = ConvertColorForModeSwitch(val, num2, num3); num = num3; WriteTargetState(sc, flag, val, num, flag2); SyncHSVFromColor(val); SyncHexFromColor(val); ApplyTarget(sc, flag); SyncField forceFields3 = (flag ? SyncField.Color : SyncField.BallColor); _pendingColorSync[(!flag) ? 1u : 0u] = false; sc.RequestSyncImmediate(forceSave: true, forceFields3); } GUILayout.Space(4f); switch (num) { case 0: DrawTintTab(sc, flag); break; case 1: DrawRGBTab(sc, flag); break; case 2: DrawHexTab(sc, flag); break; case 3: DrawPickerTab(sc, flag); break; case 4: DrawHSVTab(sc, flag); break; } GUILayout.Space(4f); DrawPreview(sc, flag); string text = (flag ? "Reset Shlong / Shaft Color" : "Reset Balls & Sheath Color"); if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { sc.InvalidateColorMaterialCache(flag, !flag); WriteTargetState(sc, flag, Color.white, 0, matchBody: true); SetTargetTextureSource(sc, flag, 0); _hexInputs[_editTarget] = "#FFFFFF"; _hues[_editTarget] = 0f; _sats[_editTarget] = 0f; _vals[_editTarget] = 1f; ApplyTarget(sc, flag); CosmeticDisplayManager.ForceRefreshColorsFor(sc, flag, !flag); SyncField forceFields4 = (flag ? SyncField.Color : SyncField.BallColor); _pendingColorSync[(!flag) ? 1u : 0u] = false; if (Plugin.IsDebug) { Plugin.LogDebug("[ColorReset] group=" + (flag ? "shaft" : "balls") + " color=" + ((object)Color.white/*cast due to .constrained prefix*/).ToString() + " mode=" + 0 + " matchBody=true forceFields=" + forceFields4); } sc.RequestSyncImmediate(forceSave: true, forceFields4); } FlushColorSyncIfNeeded(sc, flag); } private static Color GetTargetColor(ShlongController sc, bool isDick) { //IL_000d: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return isDick ? sc.ColorTint : sc.BallColorTint; } private static int GetTargetTextureSource(ShlongController sc, bool isDick) { return ShlongController.NormalizeTextureSourceMode(isDick ? sc.TextureSourceMode : sc.BallTextureSourceMode); } private static void SetTargetTextureSource(ShlongController sc, bool isDick, int mode) { mode = ShlongController.NormalizeTextureSourceMode(mode); if (isDick) { sc.TextureSourceMode = mode; } else { sc.BallTextureSourceMode = mode; } } private static void WriteTargetState(ShlongController sc, bool isDick, Color color, int mode, bool matchBody) { //IL_0022: 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_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) if (isDick) { sc.ColorTint = color; sc.ColorMode = mode; sc.MatchBody = matchBody; } else { sc.BallColorTint = color; sc.BallColorMode = mode; sc.BallMatchBody = matchBody; } } private static void SetTargetColor(ShlongController sc, bool isDick, Color color) { //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) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (isDick) { sc.ColorTint = color; } else { sc.BallColorTint = color; } } private static void ApplyTarget(ShlongController sc, bool isDick) { if (isDick) { sc.ApplyColorTint(); } else { sc.ApplyBallColorTint(); } } private static Color ConvertColorForModeSwitch(Color curColor, int fromMode, int toMode) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_0050: 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_007a: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) bool flag = fromMode == 0; bool flag2 = toMode == 0; if (flag && !flag2) { return new Color(Mathf.Clamp01(curColor.r), Mathf.Clamp01(curColor.g), Mathf.Clamp01(curColor.b)); } if (!flag && flag2) { return new Color(Mathf.Clamp(curColor.r, 0f, 2f), Mathf.Clamp(curColor.g, 0f, 2f), Mathf.Clamp(curColor.b, 0f, 2f), 1f); } return curColor; } private static void DrawTintTab(ShlongController sc, bool isDick) { //IL_0003: 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_0010: 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) Color targetColor = GetTargetColor(sc, isDick); float r = targetColor.r; float g = targetColor.g; float b = targetColor.b; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("R: " + (r - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float nr = GUILayout.HorizontalSlider(r, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("G: " + (g - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float ng = GUILayout.HorizontalSlider(g, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("B: " + (b - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float nb = GUILayout.HorizontalSlider(b, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); HandleSliderSync(sc, isDick, r, g, b, nr, ng, nb); } private static void DrawRGBTab(ShlongController sc, bool isDick) { //IL_0003: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) Color targetColor = GetTargetColor(sc, isDick); float num = Mathf.Clamp01(targetColor.r); float num2 = Mathf.Clamp01(targetColor.g); float num3 = Mathf.Clamp01(targetColor.b); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("R: " + num.ToString("F2", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float nr = GUILayout.HorizontalSlider(num, 0f, 1f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("G: " + num2.ToString("F2", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float ng = GUILayout.HorizontalSlider(num2, 0f, 1f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("B: " + num3.ToString("F2", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float nb = GUILayout.HorizontalSlider(num3, 0f, 1f, Array.Empty()); GUILayout.EndHorizontal(); HandleSliderSync(sc, isDick, num, num2, num3, nr, ng, nb); } private static void DrawHexTab(ShlongController sc, bool isDick) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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) int editTarget = _editTarget; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Hex:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); string text = GUILayout.TextField(_hexInputs[editTarget], 9, Array.Empty()); GUILayout.EndHorizontal(); if (text != _hexInputs[editTarget]) { _hexInputs[editTarget] = text; string text2 = (text.StartsWith("#") ? text : ("#" + text)); Color val = default(Color); if (ColorUtility.TryParseHtmlString(text2, ref val)) { SetTargetColor(sc, isDick, val); ApplyTarget(sc, isDick); SyncHSVFromColor(val); MarkColorChanged(isDick); } } GUILayout.Label("Current: #" + ColorUtility.ToHtmlStringRGB(GetTargetColor(sc, isDick)), Array.Empty()); } private static void DrawPickerTab(ShlongController sc, bool isDick) { //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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Invalid comparison between Unknown and I4 //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) int editTarget = _editTarget; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("H: " + (_hues[editTarget] * 360f).ToString("F0") + "°", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num = GUILayout.HorizontalSlider(_hues[editTarget], 0f, 1f, Array.Empty()); GUILayout.EndHorizontal(); EnsureHueTexture(); Rect rect = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(12f) }); GUI.DrawTexture(rect, (Texture)(object)_hueTex); GUILayout.Space(4f); EnsureSVTexture(num); Rect rect2 = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width((float)_svSize), GUILayout.Height((float)_svSize) }); GUI.DrawTexture(rect2, (Texture)(object)_svTex); Event current = Event.current; bool flag = false; if (((int)current.type == 0 || (int)current.type == 3) && ((Rect)(ref rect2)).Contains(current.mousePosition)) { _sats[editTarget] = Mathf.Clamp01((current.mousePosition.x - ((Rect)(ref rect2)).x) / ((Rect)(ref rect2)).width); _vals[editTarget] = 1f - Mathf.Clamp01((current.mousePosition.y - ((Rect)(ref rect2)).y) / ((Rect)(ref rect2)).height); flag = true; current.Use(); } float num2 = ((Rect)(ref rect2)).x + _sats[editTarget] * ((Rect)(ref rect2)).width - 4f; float num3 = ((Rect)(ref rect2)).y + (1f - _vals[editTarget]) * ((Rect)(ref rect2)).height - 4f; GUI.Label(new Rect(num2, num3, 9f, 9f), "◎"); bool flag2 = Mathf.Abs(num - _hues[editTarget]) > 0.001f; _hues[editTarget] = num; if (flag2 || flag) { Color val = Color.HSVToRGB(_hues[editTarget], _sats[editTarget], _vals[editTarget]); SetTargetColor(sc, isDick, val); ApplyTarget(sc, isDick); SyncHexFromColor(val); MarkColorChanged(isDick); } } private static void DrawHSVTab(ShlongController sc, bool isDick) { //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) int editTarget = _editTarget; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("H: " + (_hues[editTarget] * 360f).ToString("F0") + "°", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num = GUILayout.HorizontalSlider(_hues[editTarget], 0f, 1f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("S: " + _sats[editTarget].ToString("F2", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num2 = GUILayout.HorizontalSlider(_sats[editTarget], 0f, 1f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("V: " + _vals[editTarget].ToString("F2", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num3 = GUILayout.HorizontalSlider(_vals[editTarget], 0f, 1f, Array.Empty()); GUILayout.EndHorizontal(); bool flag = Mathf.Abs(num - _hues[editTarget]) > 0.001f || Mathf.Abs(num2 - _sats[editTarget]) > 0.001f || Mathf.Abs(num3 - _vals[editTarget]) > 0.001f; _hues[editTarget] = num; _sats[editTarget] = num2; _vals[editTarget] = num3; if (flag) { Color val = Color.HSVToRGB(_hues[editTarget], _sats[editTarget], _vals[editTarget]); SetTargetColor(sc, isDick, val); ApplyTarget(sc, isDick); SyncHexFromColor(val); MarkColorChanged(isDick); } } private static void DrawPreview(ShlongController sc, bool isDick) { //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_003a: 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_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) EnsurePreviewTexture(); Color targetColor = GetTargetColor(sc, isDick); bool flag = (isDick ? sc.MatchBody : sc.BallMatchBody); int num = (isDick ? sc.ColorMode : sc.BallColorMode); _previewTex.SetPixel(0, 0, targetColor); _previewTex.Apply(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Preview:", Array.Empty()); Rect rect = GUILayoutUtility.GetRect(40f, 20f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); GUI.DrawTexture(rect, (Texture)(object)_previewTex); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } private static void MarkColorChanged(bool isDick) { int num = ((!isDick) ? 1 : 0); _pendingColorSync[num] = true; _lastColorChangeTime[num] = Time.unscaledTime; } private static void FlushColorSyncIfNeeded(ShlongController sc, bool isDick, bool forceNow = false) { int num = ((!isDick) ? 1 : 0); if (_pendingColorSync[num]) { bool flag = GUIUtility.hotControl != 0; bool flag2 = Time.unscaledTime - _lastColorChangeTime[num] >= 0.35f; if (!(!forceNow && flag) || flag2) { _pendingColorSync[num] = false; SyncField forceFields = (isDick ? SyncField.Color : SyncField.BallColor); sc.RequestSyncImmediate(forceSave: true, forceFields); } } } private static void HandleSliderSync(ShlongController sc, bool isDick, float or, float og, float ob, float nr, float ng, float nb) { //IL_004b: 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_0061: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Abs(nr - or) > 0.001f || Mathf.Abs(ng - og) > 0.001f || Mathf.Abs(nb - ob) > 0.001f) { Color val = default(Color); ((Color)(ref val))..ctor(nr, ng, nb); SetTargetColor(sc, isDick, val); ApplyTarget(sc, isDick); SyncHexFromColor(val); SyncHSVFromColor(val); MarkColorChanged(isDick); } } private static void SyncHSVFromColor(Color c) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) int editTarget = _editTarget; Color.RGBToHSV(c, ref _hues[editTarget], ref _sats[editTarget], ref _vals[editTarget]); } private static void SyncHexFromColor(Color c) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) _hexInputs[_editTarget] = "#" + ColorUtility.ToHtmlStringRGB(c); } private static void EnsurePreviewTexture() { //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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (!((Object)(object)_previewTex != (Object)null)) { _previewTex = new Texture2D(1, 1, (TextureFormat)4, false) { filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1 }; } } private static void EnsureHueTexture() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_hueTex != (Object)null)) { int num = 256; _hueTex = new Texture2D(num, 1, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; for (int i = 0; i < num; i++) { float num2 = (float)i / (float)(num - 1); _hueTex.SetPixel(i, 0, Color.HSVToRGB(num2, 1f, 1f)); } _hueTex.Apply(); } } private static void EnsureSVTexture(float hue) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_svTex != (Object)null && Mathf.Abs(hue - _svTexHue) < 0.002f) { return; } _svTexHue = hue; if ((Object)(object)_svTex == (Object)null) { _svTex = new Texture2D(_svSize, _svSize, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; } for (int i = 0; i < _svSize; i++) { float num = (float)i / (float)(_svSize - 1); for (int j = 0; j < _svSize; j++) { float num2 = (float)j / (float)(_svSize - 1); _svTex.SetPixel(j, i, Color.HSVToRGB(hue, num2, num)); } } _svTex.Apply(); } } public class SettingsWindow { private enum ShortcutCapturePart { None, MainKey } private enum ShlongModelCategory { Original, Updated } private static readonly string[] ModifierOptionLabels; private static readonly KeyCode[] ModifierOptionKeys; public static bool IsHovered; internal static Action OnDrawColorUI; private static Texture2D _uvCheckerTexture; private Rect _windowRect = new Rect(20f, 20f, 460f, 700f); private Vector2 _windowScroll; private bool _showGui; private bool _sliderWasActive; private bool _bulgeSliderWasActive; private bool _shaftColorSliderWasActive; private bool _ballColorSliderWasActive; private CursorLockMode _prevCursorLockState = (CursorLockMode)1; private bool _cursorStateChanged; private ConfigEntry _pendingShortcut; private string _pendingShortcutLabel; private bool _pendingShortcutAllowUnbind = true; private ShortcutCapturePart _pendingShortcutPart; private ConfigEntry _openModifierDropdown; private GUIStyle _bindLabelStyle; private GUIStyle _activeBindLabelStyle; private GUIStyle _activeBindButtonStyle; private ShlongModelCategory _selectedModelCategory = ShlongModelCategory.Original; private int _modelCategoryManualSwitchUntilFrame = -1; private static readonly CultureInfo Cult; private string _presetNameInput = ""; private string[] _cachedPresetNames = Array.Empty(); private float _lastPresetRefresh; private Vector2 _presetListScroll; private string _presetStatus; private ShlongController _cachedController; private float _lastControllerLookup; private ConfigEntry _secSliders; private ConfigEntry _secBulge; private ConfigEntry _secColor; private ConfigEntry _secActions; private ConfigEntry _secPresets; private ConfigEntry _secDebug; private ConfigEntry _secDevTools; private ConfigEntry _secModelPresets; private ConfigEntry _secBulgeTest; private ConfigEntry _secJiggleAdvanced; private ConfigEntry _uiBodyOpacity; private GUIStyle _sectionHeaderStyle; private GUIStyle _transparentWindowStyle; private const float HeaderHeight = 22f; private const int ModelPresetColumns = 4; private Texture2D _transparentTex; private static readonly string[] UvCheckerTextureProperties; public static bool IsRebindActive { get; private set; } internal void InitSectionConfig(ConfigFile config) { _secModelPresets = config.Bind("UI.Sections", "ModelPresetsExpanded", true, "Whether the Shlong Model Presets section is expanded"); _secSliders = config.Bind("UI.Sections", "SlidersExpanded", true, "Whether the Sliders section is expanded"); _secBulge = config.Bind("UI.Sections", "BulgeExpanded", true, "Whether the Bulge section is expanded"); _secColor = config.Bind("UI.Sections", "ColorExpanded", true, "Whether the Color Tint section is expanded"); _secActions = config.Bind("UI.Sections", "ActionsExpanded", true, "Whether the Actions & Keybinds section is expanded"); _secPresets = config.Bind("UI.Sections", "PresetsExpanded", true, "Whether the User Presets section is expanded"); _secDebug = config.Bind("UI.Sections", "DebugExpanded", false, "Whether the Debug section is expanded"); _secDevTools = config.Bind("UI.Sections", "DevToolsExpanded", false, "Whether the Developer Tools sub-section is expanded"); _secBulgeTest = config.Bind("UI.Sections", "BulgeTestExpanded", false, "Whether the Updated Model Diagnostics section is expanded"); _secJiggleAdvanced = config.Bind("UI.Sections", "JiggleAdvancedExpanded", false, "Whether the Advanced Remote Jiggle sliders are expanded"); _uiBodyOpacity = config.Bind("UI", "BodyBackgroundOpacity", 0.85f, "Opacity of the window body background. Does not affect the header."); } public void Update() { if (InputManager.IsToggleGuiPressed()) { _showGui = !_showGui; } } public void OnGUI() { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Invalid comparison between Unknown and I4 //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) CursorLockMode lockState = Cursor.lockState; _cursorStateChanged = lockState != _prevCursorLockState; _prevCursorLockState = lockState; if (!_showGui && _pendingShortcut == null) { IsHovered = false; return; } HandleShortcutCapture(Event.current); if (!_showGui) { IsHovered = false; return; } if (((Rect)(ref _windowRect)).width < 250f || ((Rect)(ref _windowRect)).height < 200f || float.IsNaN(((Rect)(ref _windowRect)).x) || float.IsNaN(((Rect)(ref _windowRect)).y) || float.IsNaN(((Rect)(ref _windowRect)).width) || float.IsNaN(((Rect)(ref _windowRect)).height) || ((Rect)(ref _windowRect)).x > (float)Screen.width - 40f || ((Rect)(ref _windowRect)).y > (float)Screen.height - 40f || ((Rect)(ref _windowRect)).x < 0f - ((Rect)(ref _windowRect)).width + 40f || ((Rect)(ref _windowRect)).y < -20f) { _windowRect = new Rect(20f, 20f, 460f, 700f); Plugin.LogWarningLimited("plugin.gui.window_rect_reset", "[GUI] Window rect was invalid/offscreen; reset to default.", 5); } try { _windowRect = GUILayout.Window(947561, _windowRect, new WindowFunction(DrawWindow), "", GetManualChromeWindowStyle(), Array.Empty()); } catch (Exception ex) { Plugin.LogWarningLimited("plugin.gui.draw_exception", "[GUI] SettingsWindow draw failed: " + ex.GetType().Name + ": " + ex.Message, 3); } IsHovered = (int)Cursor.lockState != 1 && ((Rect)(ref _windowRect)).Contains(Event.current.mousePosition); if (IsHovered) { Input.ResetInputAxes(); } } private void DrawWindow(int windowId) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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) DrawWindowBackground(); DrawHeaderControlsLayout(); _windowScroll = GUILayout.BeginScrollView(_windowScroll, false, false, Array.Empty()); ShlongController activeController = GetActiveController(); if (HasUsableUpdatedModels()) { if (DrawSection("Shlong Model Presets", _secModelPresets)) { DrawModelPresetSection(activeController); } GUILayout.Space(4f); } else { ForceOriginalModelCategory(activeController); } if ((Object)(object)activeController != (Object)null) { if (DrawSection("Sliders", _secSliders)) { DrawSliders(activeController); } GUILayout.Space(4f); if (SupportsBulgeControls(activeController)) { if (DrawSection("Bulge", _secBulge)) { DrawBulgeControls(activeController); } GUILayout.Space(4f); } if (DrawSection("Color Tint", _secColor)) { DrawColorSliders(activeController); } GUILayout.Space(4f); } else { GUILayout.Label("No active ShlongController found.", Array.Empty()); GUILayout.Space(8f); } if (DrawSection("Actions & Keybinds", _secActions)) { DrawActionButtons(activeController); } GUILayout.Space(4f); if (DrawSection("User Presets", _secPresets)) { DrawUserPresets(activeController); } GUILayout.Space(4f); if (DrawSection("Debug", _secDebug)) { DrawDebugControls(activeController); } GUILayout.Space(20f); GUILayout.EndScrollView(); GUI.DragWindow(new Rect(0f, 0f, Mathf.Max(1f, ((Rect)(ref _windowRect)).width - 24f), 22f)); } private static bool HasUsableUpdatedModels() { return Plugin.Presets != null && Plugin.Presets.HasUsableTestPresets(); } private void ForceOriginalModelCategory(ShlongController sc) { _selectedModelCategory = ShlongModelCategory.Original; if (!((Object)(object)sc == (Object)null) && Plugin.Presets != null) { int num = Plugin.Presets.ResolvePresetForLocalAssets(sc.PresetIndex); if (num >= 0 && num != sc.PresetIndex) { sc.QueueInteractivePresetChange(num); } } } private void SwitchModelCategoryAndPreset(ShlongController sc, ShlongModelCategory targetCategory) { if (targetCategory == ShlongModelCategory.Updated && !HasUsableUpdatedModels()) { _selectedModelCategory = ShlongModelCategory.Original; return; } _selectedModelCategory = targetCategory; _modelCategoryManualSwitchUntilFrame = Time.frameCount + 120; if ((Object)(object)sc == (Object)null || Plugin.Presets == null) { return; } PresetData preset = Plugin.Presets.GetPreset(sc.PresetIndex); if (preset == null) { return; } int num = -1; if (targetCategory == ShlongModelCategory.Updated) { if (preset.AssetSource == PresetAssetSource.Test && Plugin.Presets.IsTestPresetUsableLocally(sc.PresetIndex)) { return; } num = FindUpdatedCounterpartIndex(preset); } else { if (preset.AssetSource != PresetAssetSource.Test) { return; } num = Plugin.Presets.FindOriginalCounterpartIndex(preset); } if (num >= 0 && num != sc.PresetIndex) { PresetData preset2 = Plugin.Presets.GetPreset(num); if (preset2 != null && (preset2.AssetSource != PresetAssetSource.Test || Plugin.Presets.IsTestPresetUsableLocally(num))) { sc.QueueInteractivePresetChange(num); } } } private static int FindUpdatedCounterpartIndex(PresetData originalPreset) { if (originalPreset == null || Plugin.Presets == null) { return -1; } PresetData[] allPresets = Plugin.Presets.GetAllPresets(); if (allPresets == null) { return -1; } string text = ((!string.IsNullOrEmpty(originalPreset.Id)) ? (originalPreset.Id + "_bulge_test") : null); string text2 = ((!string.IsNullOrEmpty(originalPreset.DisplayName)) ? (originalPreset.DisplayName + " Bulge Test") : null); string friendlyName = originalPreset.FriendlyName; for (int i = 0; i < allPresets.Length; i++) { PresetData presetData = allPresets[i]; if (presetData != null && presetData.AssetSource == PresetAssetSource.Test && Plugin.Presets.IsTestPresetUsableLocally(i)) { if (!string.IsNullOrEmpty(text) && string.Equals(presetData.Id, text, StringComparison.OrdinalIgnoreCase)) { return i; } if (!string.IsNullOrEmpty(text2) && string.Equals(presetData.DisplayName, text2, StringComparison.OrdinalIgnoreCase)) { return i; } if (!string.IsNullOrEmpty(friendlyName) && string.Equals(presetData.FriendlyName, friendlyName, StringComparison.OrdinalIgnoreCase)) { return i; } } } return -1; } private void SyncModelCategoryFromActivePreset(ShlongController sc) { if ((Object)(object)sc == (Object)null || Plugin.Presets == null) { return; } if (!HasUsableUpdatedModels()) { _selectedModelCategory = ShlongModelCategory.Original; _modelCategoryManualSwitchUntilFrame = -1; } else { if (_modelCategoryManualSwitchUntilFrame >= Time.frameCount) { return; } _modelCategoryManualSwitchUntilFrame = -1; int displayedActivePresetIndex = GetDisplayedActivePresetIndex(sc); PresetData preset = Plugin.Presets.GetPreset(displayedActivePresetIndex); if (preset != null) { ShlongModelCategory shlongModelCategory = ((preset.AssetSource == PresetAssetSource.Test && Plugin.Presets.IsTestPresetUsableLocally(displayedActivePresetIndex)) ? ShlongModelCategory.Updated : ShlongModelCategory.Original); if (_selectedModelCategory != shlongModelCategory) { _selectedModelCategory = shlongModelCategory; } } } } private int GetDisplayedActivePresetIndex(ShlongController sc) { if ((Object)(object)sc == (Object)null || Plugin.Presets == null) { return ((Object)(object)sc != (Object)null) ? sc.PresetIndex : (-1); } int presetIndex = sc.PresetIndex; PresetData preset = Plugin.Presets.GetPreset(presetIndex); if (preset == null) { return presetIndex; } if (preset.AssetSource == PresetAssetSource.Test) { if (Plugin.Presets.IsTestPresetUsableLocally(presetIndex)) { return presetIndex; } int num = Plugin.Presets.FindOriginalCounterpartIndex(preset); return (num >= 0) ? num : presetIndex; } int num2 = FindUpdatedCounterpartIndex(preset); if (num2 >= 0) { PresetData preset2 = Plugin.Presets.GetPreset(num2); if (preset2 != null && Plugin.Presets.IsTestPresetUsableLocally(num2) && RuntimeRendererLooksLikePreset(sc.DickMesh, preset, preset2)) { return num2; } } return presetIndex; } private static bool RuntimeRendererLooksLikePreset(SkinnedMeshRenderer renderer, PresetData currentPreset, PresetData candidatePreset) { if ((Object)(object)renderer == (Object)null || candidatePreset == null) { return false; } int materialCount = GetMaterialCount(((Renderer)renderer).sharedMaterials); if (materialCount <= 0) { return false; } int prefabPrimaryMaterialCount = GetPrefabPrimaryMaterialCount(candidatePreset); if (prefabPrimaryMaterialCount <= 0 || materialCount != prefabPrimaryMaterialCount) { return false; } int prefabPrimaryMaterialCount2 = GetPrefabPrimaryMaterialCount(currentPreset); if (prefabPrimaryMaterialCount2 > 0 && prefabPrimaryMaterialCount2 == prefabPrimaryMaterialCount) { return false; } return true; } private static int GetPrefabPrimaryMaterialCount(PresetData preset) { if (preset == null || (Object)(object)preset.LoadedPrefab == (Object)null) { return -1; } SkinnedMeshRenderer[] componentsInChildren = preset.LoadedPrefab.GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return -1; } foreach (SkinnedMeshRenderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(preset.MeshName) && (Object)(object)val.sharedMesh != (Object)null && string.Equals(((Object)val.sharedMesh).name, preset.MeshName, StringComparison.OrdinalIgnoreCase)) { return GetMaterialCount(((Renderer)val).sharedMaterials); } } return GetMaterialCount(((Renderer)componentsInChildren[0]).sharedMaterials); } private static int GetMaterialCount(Material[] materials) { return (materials != null) ? materials.Length : 0; } private void DrawModelPresetSection(ShlongController sc) { SyncModelCategoryFromActivePreset(sc); DrawModelCategoryTabsOnly(sc); if ((Object)(object)sc == (Object)null) { GUILayout.Label("No active ShlongController found.", Array.Empty()); } else { DrawModelPresetGrid(sc); } } private void DrawModelCategoryTabsOnly(ShlongController sc) { //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_003e: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) SyncModelCategoryFromActivePreset(sc); bool flag = HasUsableUpdatedModels(); Color backgroundColor = GUI.backgroundColor; GUILayout.BeginHorizontal(Array.Empty()); GUI.backgroundColor = (Color)((_selectedModelCategory == ShlongModelCategory.Original) ? new Color(0.35f, 0.55f, 1f) : Color.white); if (GUILayout.Button("Original", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) })) { SwitchModelCategoryAndPreset(sc, ShlongModelCategory.Original); } GUI.backgroundColor = (Color)((_selectedModelCategory == ShlongModelCategory.Updated) ? new Color(0.35f, 0.75f, 0.45f) : Color.white); bool enabled = GUI.enabled; GUI.enabled = flag; if (GUILayout.Button("Updated", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) })) { SwitchModelCategoryAndPreset(sc, ShlongModelCategory.Updated); } GUI.enabled = enabled; GUI.backgroundColor = backgroundColor; GUILayout.EndHorizontal(); if (!flag && _selectedModelCategory == ShlongModelCategory.Updated) { _selectedModelCategory = ShlongModelCategory.Original; } if (!flag) { GUILayout.Label("Updated models require ShlongsPackage_test.unity3d next to the plugin DLL.", Array.Empty()); } } private void DrawModelPresetGrid(ShlongController sc) { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: 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) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Presets == null) { return; } PresetData[] all = Plugin.Presets.GetAllPresets(); bool flag = _selectedModelCategory == ShlongModelCategory.Updated; int displayedActivePresetIndex = GetDisplayedActivePresetIndex(sc); List list = new List(); for (int i = 0; i < all.Length; i++) { PresetData presetData = all[i]; if (presetData != null) { bool flag2 = presetData.AssetSource == PresetAssetSource.Test; if (flag == flag2 && (!flag2 || Plugin.Presets.IsTestPresetUsableLocally(i))) { list.Add(i); } } } list.Sort(delegate(int a, int b) { PresetData presetData3 = all[a]; PresetData presetData4 = all[b]; string strA = ((presetData3 != null) ? (presetData3.FriendlyName ?? presetData3.DisplayName ?? presetData3.Id ?? "") : ""); string strB = ((presetData4 != null) ? (presetData4.FriendlyName ?? presetData4.DisplayName ?? presetData4.Id ?? "") : ""); int num5 = string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase); return (num5 != 0) ? num5 : a.CompareTo(b); }); if (list.Count == 0) { GUILayout.Label(flag ? "Updated models are unavailable because ShlongsPackage_test.unity3d was not found." : "No original model presets found.", Array.Empty()); return; } GUILayout.Label(flag ? "Updated model presets:" : "Original model presets:", Array.Empty()); Color backgroundColor = GUI.backgroundColor; bool enabled = GUI.enabled; for (int num = 0; num < list.Count; num += 4) { GUILayout.BeginHorizontal(Array.Empty()); for (int num2 = 0; num2 < 4; num2++) { int num3 = num + num2; if (num3 >= list.Count) { GUILayout.Label("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(24f) }); continue; } int num4 = list[num3]; PresetData presetData2 = all[num4]; bool flag3 = num4 == displayedActivePresetIndex; bool flag4 = (Object)(object)presetData2.LoadedPrefab != (Object)null; GUI.backgroundColor = (Color)(flag3 ? new Color(0.4f, 0.85f, 0.5f) : (flag4 ? Color.white : new Color(0.45f, 0.45f, 0.45f))); GUI.enabled = flag4 && !flag3; string text = presetData2.FriendlyName + (flag4 ? "" : " (unavail)"); if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(24f), GUILayout.ExpandWidth(true) })) { sc.QueueInteractivePresetChange(num4); } } GUILayout.EndHorizontal(); } GUI.backgroundColor = backgroundColor; GUI.enabled = enabled; GUILayout.Label("Each model keeps its own saved size, position, color, and Match Body settings.", Array.Empty()); } private Texture2D GetTransparentTexture() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_transparentTex == (Object)null) { _transparentTex = new Texture2D(1, 1, (TextureFormat)4, false); _transparentTex.SetPixel(0, 0, new Color(0f, 0f, 0f, 0f)); _transparentTex.Apply(); ((Object)_transparentTex).hideFlags = (HideFlags)61; } return _transparentTex; } private GUIStyle GetManualChromeWindowStyle() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown if (_transparentWindowStyle == null) { _transparentWindowStyle = new GUIStyle(GUI.skin.window); Texture2D transparentTexture = GetTransparentTexture(); _transparentWindowStyle.normal.background = transparentTexture; _transparentWindowStyle.onNormal.background = transparentTexture; _transparentWindowStyle.hover.background = transparentTexture; _transparentWindowStyle.active.background = transparentTexture; _transparentWindowStyle.focused.background = transparentTexture; _transparentWindowStyle.border = new RectOffset(0, 0, 0, 0); _transparentWindowStyle.padding = new RectOffset(0, 0, 0, 0); _transparentWindowStyle.margin = GUI.skin.window.margin; } return _transparentWindowStyle; } private void DrawWindowBackground() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00d1: Unknown result type (might be due to invalid IL or missing references) float num = ((_uiBodyOpacity != null) ? Mathf.Clamp01(_uiBodyOpacity.Value) : 0.85f); Rect val = default(Rect); ((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref _windowRect)).width, 22f); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(0f, 22f, ((Rect)(ref _windowRect)).width, Mathf.Max(0f, ((Rect)(ref _windowRect)).height - 22f)); Color color = GUI.color; GUI.color = new Color(0.08f, 0.08f, 0.08f, 1f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = new Color(0.04f, 0.04f, 0.04f, num); GUI.DrawTexture(val2, (Texture)(object)Texture2D.whiteTexture); GUI.color = color; } private void DrawHeaderControlsLayout() { //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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }); Color color = GUI.color; GUI.color = Color.white; GUILayout.Label("AtlyssShlongs v3", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) }); GUILayout.FlexibleSpace(); GUILayout.Label("BG", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(22f) }); float num = ((_uiBodyOpacity != null) ? Mathf.Clamp01(_uiBodyOpacity.Value) : 0.85f); float num2 = GUILayout.HorizontalSlider(num, 0f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); if (_uiBodyOpacity != null && Mathf.Abs(num2 - num) > 0.001f) { _uiBodyOpacity.Value = Mathf.Clamp01(num2); } if (GUILayout.Button("X", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(24f), GUILayout.Height(18f) })) { _showGui = false; } GUI.color = color; GUILayout.EndHorizontal(); } private bool DrawSection(string title, ConfigEntry state) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (_sectionHeaderStyle == null) { _sectionHeaderStyle = new GUIStyle(GUI.skin.box); _sectionHeaderStyle.alignment = (TextAnchor)3; _sectionHeaderStyle.fontStyle = (FontStyle)1; _sectionHeaderStyle.normal.textColor = Color.white; } bool flag = state?.Value ?? false; string text = (flag ? "▼ " : "▶ "); if (GUILayout.Button(text + title, _sectionHeaderStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }) && state != null) { state.Value = !state.Value; } return flag; } private void DrawSliders(ShlongController sc) { //IL_002f: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_06c2: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Unknown result type (might be due to invalid IL or missing references) //IL_06f0: Unknown result type (might be due to invalid IL or missing references) //IL_06f5: Unknown result type (might be due to invalid IL or missing references) //IL_070f: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) PresetData preset = Plugin.Presets.GetPreset(sc.PresetIndex); Vector3 val = preset?.Rotation ?? Vector3.zero; Vector3 defPos = preset?.Position ?? Vector3.zero; if (GUILayout.Button("Reset All to Preset Default", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { sc.ArousalTarget = 0f; sc.ScaleOffset = Vector3.zero; sc.BallsSizeOffset = 0f; sc.ErectAngleOffset = 0f; sc.PositionOffset = new Vector2(defPos.z, defPos.y); sc.BaseRotation = new Vector3(Mathf.Repeat(val.x, 360f), Mathf.Repeat(val.y, 360f), Mathf.Repeat(val.z, 360f)); sc.RefreshTransform(); sc.RequestSyncImmediate(forceSave: true, SyncField.Position | SyncField.Scale | SyncField.BallsSize | SyncField.Arousal | SyncField.Rotation | SyncField.ErectAngle); } DrawResetRow("Arousal: " + Mathf.RoundToInt(sc.ArousalTarget), delegate { sc.ArousalTarget = 0f; sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num = GUILayout.HorizontalSlider(sc.ArousalTarget, 0f, 100f, Array.Empty()); GUILayout.Space(6f); DrawResetRow("Length (Y): " + sc.ScaleOffset.y.ToString("0.000", Cult), delegate { sc.ScaleOffset.y = 0f; sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num2 = GUILayout.HorizontalSlider(sc.ScaleOffset.y, -1f, 10f, Array.Empty()); GUILayout.Space(6f); float x = sc.ScaleOffset.x; DrawResetRow("Girth (XZ): " + x.ToString("0.000", Cult), delegate { sc.ScaleOffset.x = 0f; sc.ScaleOffset.z = 0f; sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num3 = GUILayout.HorizontalSlider(x, -1f, 10f, Array.Empty()); GUILayout.Space(6f); DrawResetRow("Balls Size: " + sc.BallsSizeOffset.ToString("0.000", Cult), delegate { sc.BallsSizeOffset = 0f; sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num4 = GUILayout.HorizontalSlider(sc.BallsSizeOffset, -1f, 10f, Array.Empty()); GUILayout.Space(6f); string text = ((sc.ErectAngleOffset > 0.5f) ? " (down)" : ((sc.ErectAngleOffset < -0.5f) ? " (up)" : "")); DrawResetRow("Erect Direction: " + sc.ErectAngleOffset.ToString("0.0", Cult) + text, delegate { sc.ErectAngleOffset = 0f; sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num5 = GUILayout.HorizontalSlider(sc.ErectAngleOffset, -90f, 90f, Array.Empty()); GUILayout.Space(6f); DrawResetRow("Offset X: " + sc.PositionOffset.x.ToString("0.00000", Cult), delegate { //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) sc.PositionOffset = new Vector2(defPos.z, sc.PositionOffset.y); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num6 = GUILayout.HorizontalSlider(sc.PositionOffset.x, -0.05f, 0.05f, Array.Empty()); GUILayout.Space(6f); DrawResetRow("Offset Y: " + sc.PositionOffset.y.ToString("0.00000", Cult), delegate { //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) sc.PositionOffset = new Vector2(sc.PositionOffset.x, defPos.y); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num7 = GUILayout.HorizontalSlider(sc.PositionOffset.y, -0.05f, 0.05f, Array.Empty()); GUILayout.Space(6f); Vector3 rot = new Vector3(Mathf.Repeat(sc.BaseRotation.x, 360f), Mathf.Repeat(sc.BaseRotation.y, 360f), Mathf.Repeat(sc.BaseRotation.z, 360f)); Vector3 defRotW = new Vector3(Mathf.Repeat(val.x, 360f), Mathf.Repeat(val.y, 360f), Mathf.Repeat(val.z, 360f)); DrawResetRow("Base Yaw: " + rot.y.ToString("0.0", Cult), delegate { //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) sc.BaseRotation = new Vector3(rot.x, defRotW.y, rot.z); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num8 = GUILayout.HorizontalSlider(rot.y, 0f, 360f, Array.Empty()); GUILayout.Space(6f); DrawResetRow("Base Roll: " + rot.z.ToString("0.0", Cult), delegate { //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) sc.BaseRotation = new Vector3(rot.x, rot.y, defRotW.z); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num9 = GUILayout.HorizontalSlider(rot.z, 0f, 360f, Array.Empty()); bool flag = !_cursorStateChanged && (Mathf.Abs(num - sc.ArousalTarget) > 0.001f || Mathf.Abs(num2 - sc.ScaleOffset.y) > 0.0001f || Mathf.Abs(num3 - x) > 0.0001f || Mathf.Abs(num4 - sc.BallsSizeOffset) > 0.0001f || Mathf.Abs(num5 - sc.ErectAngleOffset) > 0.01f || Mathf.Abs(num6 - sc.PositionOffset.x) > 1E-05f || Mathf.Abs(num7 - sc.PositionOffset.y) > 1E-05f || Mathf.Abs(num8 - rot.y) > 0.01f || Mathf.Abs(num9 - rot.z) > 0.01f); bool flag2 = GUIUtility.hotControl != 0; if (flag) { sc.ArousalTarget = num; sc.ScaleOffset = new Vector3(num3, num2, num3); sc.BallsSizeOffset = num4; sc.ErectAngleOffset = num5; sc.PositionOffset = new Vector2(num6, num7); sc.BaseRotation = new Vector3(rot.x, num8, num9); sc.RefreshTransform(); } else if (_sliderWasActive && !flag2) { sc.RequestSyncImmediate(); } _sliderWasActive = flag2; } private static bool SupportsSeparateBallsSheathColor(ShlongController sc) { if ((Object)(object)sc == (Object)null) { return false; } if (Plugin.Presets != null) { PresetData preset = Plugin.Presets.GetPreset(sc.PresetIndex); if (preset != null && preset.AssetSource == PresetAssetSource.Test) { return true; } } if (sc.HasBallsSheathSlots) { return true; } return sc.BallMeshes != null && sc.BallMeshes.Length != 0; } internal static void DrawCharacterHbcToggle(ShlongController sc) { if (PluginConfig.ApplyCharacterHbcToMatchedShlongs != null && !PluginConfig.ApplyCharacterHbcToMatchedShlongs.Value) { PluginConfig.ApplyCharacterHbcToMatchedShlongs.Value = true; } } private void DrawTextureSourceToolbar(ShlongController sc, bool isDick) { int num = ShlongController.NormalizeTextureSourceMode(isDick ? sc.TextureSourceMode : sc.BallTextureSourceMode); bool flag = num == 0; bool flag2 = GUILayout.Toggle(flag, " Use Body Texture", Array.Empty()); if (flag2 != flag) { int num2 = ((!flag2) ? 1 : 0); if (isDick) { sc.TextureSourceMode = num2; } else { sc.BallTextureSourceMode = num2; } sc.InvalidateColorMaterialCache(isDick, !isDick); if (isDick) { sc.ApplyColorTint(); } else { sc.ApplyBallColorTint(); } CosmeticDisplayManager.ForceRefreshColorsFor(sc, isDick, !isDick); sc.RequestSyncImmediate(forceSave: true, isDick ? SyncField.Color : SyncField.BallColor); } } private void DrawColorSliders(ShlongController sc) { //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: 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_0291: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04eb: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_0574: Unknown result type (might be due to invalid IL or missing references) if (OnDrawColorUI != null) { OnDrawColorUI(sc); return; } bool flag = SupportsSeparateBallsSheathColor(sc); GUILayout.Label("Shlong / Shaft Color", GUI.skin.box, Array.Empty()); DrawCharacterHbcToggle(sc); DrawTextureSourceToolbar(sc, isDick: true); float r = sc.ColorTint.r; float g = sc.ColorTint.g; float b = sc.ColorTint.b; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("R: " + (r - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num = GUILayout.HorizontalSlider(r, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("G: " + (g - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num2 = GUILayout.HorizontalSlider(g, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("B: " + (b - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num3 = GUILayout.HorizontalSlider(b, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); if (GUILayout.Button("Match Body (Reset)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { sc.InvalidateColorMaterialCache(dick: true, balls: false); sc.ColorTint = Color.white; sc.MatchBody = true; sc.TextureSourceMode = 0; sc.ApplyColorTint(); CosmeticDisplayManager.ForceRefreshColorsFor(sc, dick: true, balls: false); if (Plugin.IsDebug) { Plugin.LogDebug("[ColorReset] group=shaft color=" + ((object)Color.white/*cast due to .constrained prefix*/).ToString() + " matchBody=true forceFields=Color"); } sc.RequestSyncImmediate(forceSave: true, SyncField.Color); } bool flag2 = Mathf.Abs(num - r) > 0.001f || Mathf.Abs(num2 - g) > 0.001f || Mathf.Abs(num3 - b) > 0.001f; bool flag3 = GUIUtility.hotControl != 0; if (flag2) { sc.ColorTint = new Color(num, num2, num3); sc.ApplyColorTint(); } else if (_shaftColorSliderWasActive && !flag3) { sc.RequestSyncImmediate(forceSave: true, SyncField.Color); } _shaftColorSliderWasActive = flag3; GUILayout.Space(6f); GUILayout.Label("Balls & Sheath Color", GUI.skin.box, Array.Empty()); if (!flag) { GUI.enabled = false; GUILayout.Label(" (This preset has no separate Balls & Sheath material group.)", Array.Empty()); GUI.enabled = true; return; } DrawTextureSourceToolbar(sc, isDick: false); float r2 = sc.BallColorTint.r; float g2 = sc.BallColorTint.g; float b2 = sc.BallColorTint.b; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("R: " + (r2 - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num4 = GUILayout.HorizontalSlider(r2, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("G: " + (g2 - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num5 = GUILayout.HorizontalSlider(g2, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("B: " + (b2 - 1f).ToString("+0.00;-0.00", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); float num6 = GUILayout.HorizontalSlider(b2, 0f, 2f, Array.Empty()); GUILayout.EndHorizontal(); if (GUILayout.Button("Match Body (Reset)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { sc.InvalidateColorMaterialCache(dick: false, balls: true); sc.BallColorTint = Color.white; sc.BallMatchBody = true; sc.BallTextureSourceMode = 0; sc.ApplyBallColorTint(); CosmeticDisplayManager.ForceRefreshColorsFor(sc, dick: false, balls: true); if (Plugin.IsDebug) { Plugin.LogDebug("[ColorReset] group=balls color=" + ((object)Color.white/*cast due to .constrained prefix*/).ToString() + " matchBody=true forceFields=BallColor"); } sc.RequestSyncImmediate(forceSave: true, SyncField.BallColor); } bool flag4 = Mathf.Abs(num4 - r2) > 0.001f || Mathf.Abs(num5 - g2) > 0.001f || Mathf.Abs(num6 - b2) > 0.001f; bool flag5 = GUIUtility.hotControl != 0; if (flag4) { sc.BallColorTint = new Color(num4, num5, num6); sc.ApplyBallColorTint(); } else if (_ballColorSliderWasActive && !flag5) { sc.RequestSyncImmediate(forceSave: true, SyncField.BallColor); } _ballColorSliderWasActive = flag5; } private void DrawActionButtons(ShlongController sc) { //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_066a: Unknown result type (might be due to invalid IL or missing references) //IL_067b: Unknown result type (might be due to invalid IL or missing references) //IL_06a6: Unknown result type (might be due to invalid IL or missing references) if (PluginConfig.HotkeysEnabled != null) { bool flag = GUILayout.Toggle(PluginConfig.HotkeysEnabled.Value, "Enable Hotkeys", Array.Empty()); if (flag != PluginConfig.HotkeysEnabled.Value) { PluginConfig.HotkeysEnabled.Value = flag; } GUILayout.Space(4f); } if (PluginConfig.ShowShlongInCharacterSelect != null) { bool flag2 = GUILayout.Toggle(PluginConfig.ShowShlongInCharacterSelect.Value, "Show Shlong In Character Select Default", Array.Empty()); if (flag2 != PluginConfig.ShowShlongInCharacterSelect.Value) { PluginConfig.ShowShlongInCharacterSelect.Value = flag2; RaceModelPatch.RefreshCharacterPreviewControllers(); } GUILayout.Space(2f); } if (PluginConfig.HideOtherPlayersShlongs != null) { bool flag3 = GUILayout.Toggle(PluginConfig.HideOtherPlayersShlongs.Value, "Hide Multiplayer Shlongs", Array.Empty()); if (flag3 != PluginConfig.HideOtherPlayersShlongs.Value) { PluginConfig.HideOtherPlayersShlongs.Value = flag3; } GUILayout.Space(2f); } DrawCharacterSelectPreviewModeControls(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.FlexibleSpace(); if (GUILayout.Button("Reset All Keybinds", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(140f), GUILayout.Height(22f) })) { ResetAllShortcutsToDefault(); } GUILayout.EndHorizontal(); GUILayout.Space(4f); if ((Object)(object)sc != (Object)null) { int displayedActivePresetIndex = GetDisplayedActivePresetIndex(sc); PresetData preset = Plugin.Presets.GetPreset(displayedActivePresetIndex); string text = ((preset != null && preset.AssetSource == PresetAssetSource.Test) ? "Updated" : "Original"); GUILayout.Label("Active: [" + text + "] " + ((preset != null) ? preset.FriendlyName : sc.PresetIndex.ToString()), Array.Empty()); GUILayout.Space(2f); GUILayout.Label("Prev/Next cycles through all model categories.", Array.Empty()); DrawBindRow("Prev Dick", InputManager.GetPrevDick()); DrawBindRow("Next Dick", InputManager.GetNextDick()); GUILayout.Space(4f); DrawToggleActionRow("Hide Shlong", sc.HideToggle, InputManager.GetToggleHide(), delegate { sc.HideToggle = !sc.HideToggle; sc.RequestSyncImmediate(); }); DrawToggleActionRow("Futa Toggle", sc.FutaToggle, InputManager.GetToggleFuta(), delegate { sc.FutaToggle = !sc.FutaToggle; sc.RequestSyncImmediate(); }); DrawToggleActionRow("Clothing Override", sc.ClothingOverride, InputManager.GetToggleClothing(), delegate { sc.ClothingOverride = !sc.ClothingOverride; sc.RequestSyncImmediate(forceSave: true, SyncField.Clothing); }); DrawButtonActionRow("Arousal ◆ " + Mathf.RoundToInt(sc.ArousalTarget) + " → Cycle", InputManager.GetCycleArousal(), delegate { sc.CycleArousal(); }); DrawButtonActionRow("Toggle Arousal 0/100", InputManager.GetToggleArousal(), delegate { sc.ArousalTarget = ((sc.ArousalTarget == 0f) ? 100f : 0f); sc.RequestSyncImmediate(); }); GUILayout.Space(4f); GUILayout.Label("Bulge Position Hotkeys", Array.Empty()); DrawBulgePositionBindRow("Bulge Pos 0 (Balls)", InputManager.GetBulgePosition0(), sc, 0f); DrawBulgePositionBindRow("Bulge Pos 1 (Sheath)", InputManager.GetBulgePosition1(), sc, 1f); DrawBulgePositionBindRow("Bulge Pos 2 (Root)", InputManager.GetBulgePosition2(), sc, 2f); DrawBulgePositionBindRow("Bulge Pos 3 (Base)", InputManager.GetBulgePosition3(), sc, 3f); DrawBulgePositionBindRow("Bulge Pos 4 (Mid)", InputManager.GetBulgePosition4(), sc, 4f); DrawBulgePositionBindRow("Bulge Pos 5 (Upper)", InputManager.GetBulgePosition5(), sc, 5f); DrawBulgePositionBindRow("Bulge Pos 6 (Tip)", InputManager.GetBulgePosition6(), sc, 6f); GUILayout.Space(4f); DrawButtonActionRow("Dick Size +", InputManager.GetIncreaseDick(), delegate { //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) float num = 0.06f + Mathf.Max(Mathf.Max(sc.ScaleOffset.x, sc.ScaleOffset.y), 0f) * 0.1f; float num2 = Mathf.Clamp(sc.ScaleOffset.x + num, -1f, 10f); float num3 = Mathf.Clamp(sc.ScaleOffset.y + num, -1f, 10f); sc.ScaleOffset = new Vector3(num2, num3, num2); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); DrawButtonActionRow("Dick Size -", InputManager.GetDecreaseDick(), delegate { //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) float num = 0.06f + Mathf.Max(Mathf.Max(sc.ScaleOffset.x, sc.ScaleOffset.y), 0f) * 0.1f; float num2 = Mathf.Clamp(sc.ScaleOffset.x - num, -1f, 10f); float num3 = Mathf.Clamp(sc.ScaleOffset.y - num, -1f, 10f); sc.ScaleOffset = new Vector3(num2, num3, num2); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); DrawButtonActionRow("Balls Size +", InputManager.GetIncreaseBalls(), delegate { sc.BallsSizeOffset = Mathf.Clamp(sc.BallsSizeOffset + 0.1f, -1f, 10f); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); DrawButtonActionRow("Balls Size -", InputManager.GetDecreaseBalls(), delegate { sc.BallsSizeOffset = Mathf.Clamp(sc.BallsSizeOffset - 0.1f, -1f, 10f); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); GUILayout.Space(4f); DrawButtonActionRow("Sync Now", InputManager.GetManualSync(), delegate { sc.RequestSyncImmediate(); }); } else { GUILayout.Label("(No controller — keybinds only)", Array.Empty()); DrawBindRow("Prev Dick", InputManager.GetPrevDick()); DrawBindRow("Next Dick", InputManager.GetNextDick()); DrawBindRow("Toggle Futa", InputManager.GetToggleFuta()); DrawBindRow("Hide Shlong", InputManager.GetToggleHide()); DrawBindRow("Clothing Override", InputManager.GetToggleClothing()); DrawBindRow("Toggle Arousal", InputManager.GetToggleArousal()); DrawBindRow("Cycle Arousal", InputManager.GetCycleArousal()); DrawBindRow("Bulge Pos 0 (Balls)", InputManager.GetBulgePosition0()); DrawBindRow("Bulge Pos 1 (Sheath)", InputManager.GetBulgePosition1()); DrawBindRow("Bulge Pos 2 (Root)", InputManager.GetBulgePosition2()); DrawBindRow("Bulge Pos 3 (Base)", InputManager.GetBulgePosition3()); DrawBindRow("Bulge Pos 4 (Mid)", InputManager.GetBulgePosition4()); DrawBindRow("Bulge Pos 5 (Upper)", InputManager.GetBulgePosition5()); DrawBindRow("Bulge Pos 6 (Tip)", InputManager.GetBulgePosition6()); DrawBindRow("Dick Size +", InputManager.GetIncreaseDick()); DrawBindRow("Dick Size -", InputManager.GetDecreaseDick()); DrawBindRow("Balls Size +", InputManager.GetIncreaseBalls()); DrawBindRow("Balls Size -", InputManager.GetDecreaseBalls()); DrawBindRow("Sync Now", InputManager.GetManualSync()); } GUILayout.Space(2f); DrawBindRow("Adjust Offset (hold)", InputManager.GetAdjustOffset()); DrawBindRow("Open GUI", InputManager.GetToggleGui(), allowUnbind: false); if (_pendingShortcut != null) { GUILayout.Space(4f); Color contentColor = GUI.contentColor; GUI.contentColor = new Color(1f, 0.9f, 0.35f); GUILayout.Label(">> Press main key for: " + _pendingShortcutLabel + " (Backspace=cancel)", Array.Empty()); GUI.contentColor = contentColor; } } private void DrawUserPresets(ShlongController sc) { //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) if (Plugin.UserPresets == null) { GUILayout.Label("(Preset system unavailable)", Array.Empty()); return; } if (Time.unscaledTime - _lastPresetRefresh > 2f) { _cachedPresetNames = Plugin.UserPresets.GetPresetNames(); _lastPresetRefresh = Time.unscaledTime; } GUILayout.BeginHorizontal(Array.Empty()); _presetNameInput = GUILayout.TextField(_presetNameInput, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }); bool enabled = (Object)(object)sc != (Object)null && !string.IsNullOrWhiteSpace(_presetNameInput); GUI.enabled = enabled; if (GUILayout.Button("Save", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(60f), GUILayout.Height(22f) })) { string text = _presetNameInput.Trim(); Plugin.UserPresets.SavePreset(text, UserPresetManager.CaptureFromController(sc)); _presetStatus = "Saved: " + text; _cachedPresetNames = Plugin.UserPresets.GetPresetNames(); _lastPresetRefresh = Time.unscaledTime; } GUI.enabled = true; GUILayout.EndHorizontal(); if (!string.IsNullOrEmpty(_presetStatus)) { GUILayout.Label(_presetStatus, Array.Empty()); } if (_cachedPresetNames.Length == 0) { GUILayout.Label(" (no saved presets)", Array.Empty()); return; } float num = Mathf.Min((float)_cachedPresetNames.Length * 28f, 140f); _presetListScroll = GUILayout.BeginScrollView(_presetListScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num + 4f) }); for (int i = 0; i < _cachedPresetNames.Length; i++) { string text2 = _cachedPresetNames[i]; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }); GUILayout.FlexibleSpace(); bool enabled2 = (Object)(object)sc != (Object)null; GUI.enabled = enabled2; if (GUILayout.Button("Load", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(50f), GUILayout.Height(22f) })) { ProfileSaveData profileSaveData = Plugin.UserPresets.LoadPreset(text2); if (profileSaveData != null && (Object)(object)sc != (Object)null) { if (profileSaveData.DickNumber != sc.PresetIndex) { sc.SetPendingUserProfile(profileSaveData); sc.QueueInteractivePresetChange(profileSaveData.DickNumber); } else { ApplyPresetDataToController(sc, profileSaveData); } _presetStatus = "Loaded: " + text2; } } GUI.enabled = true; if (GUILayout.Button("X", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(24f), GUILayout.Height(22f) })) { Plugin.UserPresets.DeletePreset(text2); _presetStatus = "Deleted: " + text2; _cachedPresetNames = Plugin.UserPresets.GetPresetNames(); _lastPresetRefresh = Time.unscaledTime; } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); } private static void ApplyPresetDataToController(ShlongController sc, ProfileSaveData data) { //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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) sc.FutaToggle = data.FutaToggle; sc.ClothingOverride = data.ClothingOverride; sc.HideToggle = data.HideToggle; sc.BallsSizeOffset = data.BallsSizeOffset; sc.PositionOffset = new Vector2(data.DickOffsetX, data.DickOffsetY); sc.BaseRotation = data.AngleOffset; sc.ErectAngleOffset = data.ErectAngle; sc.ScaleOffset = data.ScaleOffset; sc.ColorTint = new Color(data.ColorR, data.ColorG, data.ColorB); sc.ColorMode = data.ColorMode; sc.MatchBody = data.MatchBody; bool flag = data.TextureSourceContractVersion >= 1; sc.TextureSourceMode = (flag ? ShlongController.NormalizeTextureSourceMode(data.TextureSourceMode) : 0); sc.ArousalLerpSpeed = ((data.ArousalLerpSpeed > 0.001f) ? data.ArousalLerpSpeed : 2f); sc.BulgeAmount = Mathf.Clamp(data.BulgeAmount, 0f, 100f); sc.BulgePosition = Mathf.Clamp(data.BulgePosition, 0f, 6f); sc.BulgeWidth = ((data.BulgeWidth > 0.001f) ? data.BulgeWidth : 1f); sc.BulgeSharpness = ((data.BulgeSharpness > 0.001f) ? data.BulgeSharpness : 1f); sc.BulgeLerpSpeed = ((data.BulgeLerpSpeed > 0.001f) ? data.BulgeLerpSpeed : 2f); sc.BallColorTint = new Color(data.BallColorR, data.BallColorG, data.BallColorB); sc.BallColorMode = data.BallColorMode; sc.BallMatchBody = data.BallMatchBody; sc.BallTextureSourceMode = (flag ? ShlongController.NormalizeTextureSourceMode(data.BallTextureSourceMode) : 0); sc.InvalidateColorMaterialCache(dick: true, balls: true); sc.ApplyColorTint(); sc.ApplyBallColorTint(); sc.RefreshTransform(); sc.RequestSyncImmediate(forceSave: true, SyncField.Position | SyncField.Scale | SyncField.BallsSize | SyncField.Futa | SyncField.Clothing | SyncField.Rotation | SyncField.ErectAngle | SyncField.Color | SyncField.BallColor | SyncField.Hide | SyncField.Bulge); } private static bool SupportsBulgeControls(ShlongController sc) { if ((Object)(object)sc == (Object)null) { return false; } PresetData presetData = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(sc.PresetIndex) : null); if (presetData != null && presetData.AssetSource == PresetAssetSource.Test) { return true; } if ((Object)(object)sc.DickMesh != (Object)null) { sc.BlendShapes.EnsureCached(sc.DickMesh); return sc.BlendShapes.HasAnyBulge; } return false; } private void DrawBulgeControls(ShlongController sc) { if (!((Object)(object)sc == (Object)null)) { GUILayout.Label("Note: Bulges only work on Updated models", Array.Empty()); GUILayout.Label("Position: 0 Balls · 1 Sheath · 2 Root · 3 Base · 4 Mid · 5 Upper · 6 Tip", Array.Empty()); DrawResetRow("Bulge Amount: " + sc.BulgeAmount.ToString("0.0", Cult), delegate { sc.BulgeAmount = 0f; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); }); float num = GUILayout.HorizontalSlider(sc.BulgeAmount, 0f, 100f, Array.Empty()); GUILayout.Space(4f); DrawResetRow("Bulge Position: " + sc.BulgePosition.ToString("0.00", Cult), delegate { sc.BulgePosition = 0f; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); }); float num2 = GUILayout.HorizontalSlider(sc.BulgePosition, 0f, 6f, Array.Empty()); GUILayout.Space(4f); DrawResetRow("Bulge Width: " + sc.BulgeWidth.ToString("0.00", Cult), delegate { sc.BulgeWidth = 1f; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); }); float num3 = GUILayout.HorizontalSlider(sc.BulgeWidth, 0.05f, 6f, Array.Empty()); GUILayout.Space(4f); DrawResetRow("Bulge Sharpness: " + sc.BulgeSharpness.ToString("0.00", Cult), delegate { sc.BulgeSharpness = 1f; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); }); float num4 = GUILayout.HorizontalSlider(sc.BulgeSharpness, 0.25f, 4f, Array.Empty()); GUILayout.Space(4f); DrawResetRow("Bulge Velocity: " + sc.BulgeLerpSpeed.ToString("0.00", Cult), delegate { sc.BulgeLerpSpeed = 2f; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); }); float num5 = GUILayout.HorizontalSlider(sc.BulgeLerpSpeed, 0.1f, 10f, Array.Empty()); GUILayout.Label("Higher values make the bulge BlendShapes catch up faster.", Array.Empty()); GUILayout.Space(4f); bool num6 = !_cursorStateChanged && (Mathf.Abs(num - sc.BulgeAmount) > 0.001f || Mathf.Abs(num2 - sc.BulgePosition) > 0.001f || Mathf.Abs(num3 - sc.BulgeWidth) > 0.001f || Mathf.Abs(num4 - sc.BulgeSharpness) > 0.001f || Mathf.Abs(num5 - sc.BulgeLerpSpeed) > 0.001f); bool flag = GUIUtility.hotControl != 0; if (num6) { sc.BulgeAmount = num; sc.BulgePosition = num2; sc.BulgeWidth = num3; sc.BulgeSharpness = num4; sc.BulgeLerpSpeed = num5; } else if (_bulgeSliderWasActive && !flag) { sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); } _bulgeSliderWasActive = flag; if (GUILayout.Button("Reset Bulge Sliders", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { sc.BulgeAmount = 0f; sc.BulgePosition = 0f; sc.BulgeWidth = 1f; sc.BulgeSharpness = 1f; sc.BulgeLerpSpeed = 2f; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); } } } private unsafe void DrawDebugControls(ShlongController sc) { //IL_051b: 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_0576: Unknown result type (might be due to invalid IL or missing references) //IL_05e7: Unknown result type (might be due to invalid IL or missing references) //IL_0658: Unknown result type (might be due to invalid IL or missing references) //IL_06ad: Unknown result type (might be due to invalid IL or missing references) //IL_06af: Unknown result type (might be due to invalid IL or missing references) //IL_06b1: Unknown result type (might be due to invalid IL or missing references) //IL_06b6: Unknown result type (might be due to invalid IL or missing references) //IL_06cd: Unknown result type (might be due to invalid IL or missing references) //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_0740: Unknown result type (might be due to invalid IL or missing references) //IL_0745: Unknown result type (might be due to invalid IL or missing references) //IL_070e: Unknown result type (might be due to invalid IL or missing references) //IL_0713: Unknown result type (might be due to invalid IL or missing references) //IL_080b: Unknown result type (might be due to invalid IL or missing references) //IL_0810: Unknown result type (might be due to invalid IL or missing references) //IL_0824: Unknown result type (might be due to invalid IL or missing references) //IL_0829: Unknown result type (might be due to invalid IL or missing references) //IL_0849: Unknown result type (might be due to invalid IL or missing references) //IL_084e: Unknown result type (might be due to invalid IL or missing references) //IL_088c: Unknown result type (might be due to invalid IL or missing references) //IL_0891: Unknown result type (might be due to invalid IL or missing references) //IL_08b1: Unknown result type (might be due to invalid IL or missing references) //IL_08b6: Unknown result type (might be due to invalid IL or missing references) //IL_08f4: Unknown result type (might be due to invalid IL or missing references) //IL_08f9: Unknown result type (might be due to invalid IL or missing references) //IL_0919: Unknown result type (might be due to invalid IL or missing references) //IL_091e: Unknown result type (might be due to invalid IL or missing references) //IL_0a75: Unknown result type (might be due to invalid IL or missing references) //IL_0a7a: Unknown result type (might be due to invalid IL or missing references) if (Plugin.DebugMode != null) { bool flag = GUILayout.Toggle(Plugin.DebugMode.Value, "Enable Debug Logging", Array.Empty()); if (flag != Plugin.DebugMode.Value) { Plugin.DebugMode.Value = flag; } } GUILayout.Space(2f); if (!DrawSection("Developer Tools", _secDevTools)) { return; } GUILayout.Label("Bundle: " + ((Plugin.Assets != null) ? "loaded" : "NULL"), Array.Empty()); GUILayout.Label("CharMenuON: " + Plugin.CharMenuON, Array.Empty()); GUILayout.Label("OurDick: " + (((Object)(object)ShlongController.OurDick != (Object)null) ? ((Object)ShlongController.OurDick).name : "null"), Array.Empty()); GUILayout.Label("Controllers: " + ((Plugin.Controllers != null) ? Plugin.Controllers.Count.ToString() : "null"), Array.Empty()); GUILayout.Space(4f); GUILayout.Label("--- Color Diagnostics ---", GUI.skin.box, Array.Empty()); if (GUILayout.Button("Log Current Shlong Color State Once", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { LogCurrentShlongColorStateOnce(sc); } if (GUILayout.Button("Log Current Shlong Mesh/UV State Once", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { LogCurrentShlongUvStateOnce(sc); } if (GUILayout.Button("Apply UV Checker Texture Once", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { ApplyUvCheckerTextureOnce(sc); } if (GUILayout.Button("Apply Body Atlas Texture Probe Once", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { ApplyBodyAtlasTextureProbeOnce(sc); } if (GUILayout.Button("Body Atlas ColorAdjust Probe", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { ApplyBodyAtlasColorAdjustProbeOnce(sc, flipU: false, flipV: false); } if (GUILayout.Button("Body Atlas ColorAdjust Probe V Flip", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { ApplyBodyAtlasColorAdjustProbeOnce(sc, flipU: false, flipV: true); } if (GUILayout.Button("Body Atlas ColorAdjust Probe U Flip", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { ApplyBodyAtlasColorAdjustProbeOnce(sc, flipU: true, flipV: false); } if (GUILayout.Button("Body Atlas ColorAdjust Probe U+V Flip", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { ApplyBodyAtlasColorAdjustProbeOnce(sc, flipU: true, flipV: true); } if (GUILayout.Button("Restore Materials After UV Checker", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { RestoreMaterialsAfterUvChecker(sc); } GUILayout.Label("Prints one copy-paste block to the BepInEx log. UV Checker / Body Atlas probes are temporary visual tests and are not saved.", Array.Empty()); GUILayout.Space(4f); GUILayout.Label("--- Clip Debug ---", GUI.skin.box, Array.Empty()); bool flag2 = GUILayout.Toggle(ModelAttacher.ClipEnabled, "Clip Enabled", Array.Empty()); if (flag2 != ModelAttacher.ClipEnabled) { ModelAttacher.ClipEnabled = flag2; if ((Object)(object)sc != (Object)null) { sc.Spawn(sc.PresetIndex); } } GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Mode:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); string[] array = new string[4] { "3D", "X", "Y", "Z" }; int[] array2 = new int[4] { -1, 0, 1, 2 }; for (int i = 0; i < array.Length; i++) { bool flag3 = ModelAttacher.ClipAxis == array2[i]; if (GUILayout.Toggle(flag3, array[i], GUI.skin.button, Array.Empty()) && !flag3) { ModelAttacher.ClipAxis = array2[i]; if ((Object)(object)sc != (Object)null) { sc.Spawn(sc.PresetIndex); } } } GUILayout.EndHorizontal(); bool flag4 = GUILayout.Toggle(ModelAttacher.ClipFlipDirection, "Flip Direction", Array.Empty()); if (flag4 != ModelAttacher.ClipFlipDirection) { ModelAttacher.ClipFlipDirection = flag4; if ((Object)(object)sc != (Object)null) { sc.Spawn(sc.PresetIndex); } } GUILayout.Label("Clip Amount: " + (ModelAttacher.ClipMarginRatio * 100f).ToString("F0") + "%", Array.Empty()); float num = GUILayout.HorizontalSlider(ModelAttacher.ClipMarginRatio, 0f, 1f, Array.Empty()); if (Mathf.Abs(num - ModelAttacher.ClipMarginRatio) > 0.001f) { ModelAttacher.ClipMarginRatio = num; if ((Object)(object)sc != (Object)null) { sc.Spawn(sc.PresetIndex); } } GUILayout.Space(4f); Vector3 clipDirOverride = ModelAttacher.ClipDirOverride; bool flag5 = ((Vector3)(ref clipDirOverride)).sqrMagnitude > 0.0001f; GUILayout.Label(flag5 ? "Clip Dir: MANUAL" : "Clip Dir: Auto (geometry)", Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("X:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(16f) }); float num2 = GUILayout.HorizontalSlider(clipDirOverride.x, -1f, 1f, Array.Empty()); GUILayout.Label(num2.ToString("F2"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) }); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Y:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(16f) }); float num3 = GUILayout.HorizontalSlider(clipDirOverride.y, -1f, 1f, Array.Empty()); GUILayout.Label(num3.ToString("F2"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) }); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Z:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(16f) }); float num4 = GUILayout.HorizontalSlider(clipDirOverride.z, -1f, 1f, Array.Empty()); GUILayout.Label(num4.ToString("F2"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) }); GUILayout.EndHorizontal(); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(num2, num3, num4); Vector3 val2 = val - clipDirOverride; if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f) { ModelAttacher.ClipDirOverride = val; if ((Object)(object)sc != (Object)null) { sc.Spawn(sc.PresetIndex); } } if (flag5 && GUILayout.Button("Reset to Auto", Array.Empty())) { ModelAttacher.ClipDirOverride = Vector3.zero; if ((Object)(object)sc != (Object)null) { sc.Spawn(sc.PresetIndex); } } GUILayout.Space(4f); Vector3 lastClipDir = ModelAttacher.LastClipDir; GUILayout.Label("Effective ClipDir: (" + lastClipDir.x.ToString("F3") + ", " + lastClipDir.y.ToString("F3") + ", " + lastClipDir.z.ToString("F3") + ") maxProj=" + ModelAttacher.LastClipMaxProj.ToString("F4"), Array.Empty()); if ((Object)(object)sc != (Object)null && (Object)(object)sc.DickMesh != (Object)null && (Object)(object)sc.DickMesh.sharedMesh != (Object)null) { Bounds bounds = sc.DickMesh.sharedMesh.bounds; string[] obj = new string[5] { "Bounds X:[", null, null, null, null }; val2 = ((Bounds)(ref bounds)).min; obj[1] = val2.x.ToString("F4"); obj[2] = ", "; val2 = ((Bounds)(ref bounds)).max; obj[3] = val2.x.ToString("F4"); obj[4] = "]"; GUILayout.Label(string.Concat(obj), Array.Empty()); string[] obj2 = new string[5] { "Bounds Y:[", null, null, null, null }; val2 = ((Bounds)(ref bounds)).min; obj2[1] = val2.y.ToString("F4"); obj2[2] = ", "; val2 = ((Bounds)(ref bounds)).max; obj2[3] = val2.y.ToString("F4"); obj2[4] = "]"; GUILayout.Label(string.Concat(obj2), Array.Empty()); string[] obj3 = new string[5] { "Bounds Z:[", null, null, null, null }; val2 = ((Bounds)(ref bounds)).min; obj3[1] = val2.z.ToString("F4"); obj3[2] = ", "; val2 = ((Bounds)(ref bounds)).max; obj3[3] = val2.z.ToString("F4"); obj3[4] = "]"; GUILayout.Label(string.Concat(obj3), Array.Empty()); } if ((Object)(object)sc != (Object)null) { GUILayout.Label("--- Active Controller ---", Array.Empty()); GUILayout.Label("GO: " + ((Object)((Component)sc).gameObject).name + " active=" + ((Component)sc).gameObject.activeInHierarchy, Array.Empty()); GUILayout.Label("SizeBone: " + (((Object)(object)sc.SizeBone != (Object)null) ? ((Object)sc.SizeBone).name : "NULL"), Array.Empty()); GUILayout.Label("DickMesh: " + (((Object)(object)sc.DickMesh != (Object)null) ? ("enabled=" + ((Renderer)sc.DickMesh).enabled) : "NULL"), Array.Empty()); GUILayout.Label("Race=" + sc.RaceIndex + " Preset=" + sc.PresetIndex, Array.Empty()); string text = ((Vector3)(ref sc.ScaleOffset)).ToString("F3"); Color colorTint = sc.ColorTint; GUILayout.Label("Scale=" + text + " Color=" + ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(), Array.Empty()); GUILayout.Label("Futa=" + sc.FutaToggle + " Clothing=" + sc.ClothingOverride, Array.Empty()); } GUILayout.Space(4f); GUILayout.Label("--- Remote Jiggle ---", GUI.skin.box, Array.Empty()); if (PluginConfig.EnableRemoteJiggleExperimental != null) { bool flag6 = GUILayout.Toggle(PluginConfig.EnableRemoteJiggleExperimental.Value, "Enable Remote Jiggle", Array.Empty()); if (flag6 != PluginConfig.EnableRemoteJiggleExperimental.Value) { PluginConfig.EnableRemoteJiggleExperimental.Value = flag6; } } if (PluginConfig.EnableLocalCosmeticJiggleExperimental != null) { bool flag7 = GUILayout.Toggle(PluginConfig.EnableLocalCosmeticJiggleExperimental.Value, "Enable Local Cosmetic Jiggle", Array.Empty()); if (flag7 != PluginConfig.EnableLocalCosmeticJiggleExperimental.Value) { PluginConfig.EnableLocalCosmeticJiggleExperimental.Value = flag7; } } if (PluginConfig.RemoteJiggleMode != null) { GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Remote Jiggle Mode:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(135f) }); bool flag8 = PluginConfig.RemoteJiggleMode.Value == "Procedural"; bool flag9 = PluginConfig.RemoteJiggleMode.Value == "NativeDynamicBoneExperimental"; bool enabled = GUI.enabled; GUI.enabled = enabled && !flag8; if (GUILayout.Button("Procedural", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(110f), GUILayout.Height(22f) })) { PluginConfig.RemoteJiggleMode.Value = "Procedural"; CosmeticDisplayManager.RecreateAllDisplayRigsForConfigChange("RemoteJiggleMode=Procedural"); } GUI.enabled = enabled && !flag9; if (GUILayout.Button("Native DB Test", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(125f), GUILayout.Height(22f) })) { PluginConfig.RemoteJiggleMode.Value = "NativeDynamicBoneExperimental"; if (PluginConfig.EnableRemoteJiggleExperimental != null) { PluginConfig.EnableRemoteJiggleExperimental.Value = true; } CosmeticDisplayManager.RecreateAllDisplayRigsForConfigChange("RemoteJiggleMode=NativeDynamicBoneExperimental"); } GUI.enabled = enabled; GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Space(139f); GUILayout.Label(flag9 ? "Experimental: real DynamicBone on display rigs." : "Current custom simulation.", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); GUILayout.EndHorizontal(); } GUILayout.Space(4f); GUILayout.Label("Feel Preset:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(72f) }); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Subtle", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { if (PluginConfig.RemoteJiggleStrength != null) { PluginConfig.RemoteJiggleStrength.Value = 0.25f; } if (PluginConfig.RemoteJiggleStiffness != null) { PluginConfig.RemoteJiggleStiffness.Value = 10f; } if (PluginConfig.RemoteJiggleDamping != null) { PluginConfig.RemoteJiggleDamping.Value = 0.92f; } if (PluginConfig.RemoteJiggleMaxDegrees != null) { PluginConfig.RemoteJiggleMaxDegrees.Value = 3.5f; } if (PluginConfig.RemoteJiggleVelocityToDegrees != null) { PluginConfig.RemoteJiggleVelocityToDegrees.Value = 0.25f; } if (PluginConfig.RemoteJiggleAngularToDegrees != null) { PluginConfig.RemoteJiggleAngularToDegrees.Value = 0.08f; } if (PluginConfig.RemoteJiggleMinimumKick != null) { PluginConfig.RemoteJiggleMinimumKick.Value = 0.03f; } } if (GUILayout.Button("Normal", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { if (PluginConfig.RemoteJiggleStrength != null) { PluginConfig.RemoteJiggleStrength.Value = 0.35f; } if (PluginConfig.RemoteJiggleStiffness != null) { PluginConfig.RemoteJiggleStiffness.Value = 10f; } if (PluginConfig.RemoteJiggleDamping != null) { PluginConfig.RemoteJiggleDamping.Value = 0.9f; } if (PluginConfig.RemoteJiggleMaxDegrees != null) { PluginConfig.RemoteJiggleMaxDegrees.Value = 5f; } if (PluginConfig.RemoteJiggleVelocityToDegrees != null) { PluginConfig.RemoteJiggleVelocityToDegrees.Value = 0.35f; } if (PluginConfig.RemoteJiggleAngularToDegrees != null) { PluginConfig.RemoteJiggleAngularToDegrees.Value = 0.1f; } if (PluginConfig.RemoteJiggleMinimumKick != null) { PluginConfig.RemoteJiggleMinimumKick.Value = 0.04f; } } if (GUILayout.Button("Soft/Strong", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { if (PluginConfig.RemoteJiggleStrength != null) { PluginConfig.RemoteJiggleStrength.Value = 0.55f; } if (PluginConfig.RemoteJiggleStiffness != null) { PluginConfig.RemoteJiggleStiffness.Value = 8f; } if (PluginConfig.RemoteJiggleDamping != null) { PluginConfig.RemoteJiggleDamping.Value = 0.88f; } if (PluginConfig.RemoteJiggleMaxDegrees != null) { PluginConfig.RemoteJiggleMaxDegrees.Value = 7f; } if (PluginConfig.RemoteJiggleVelocityToDegrees != null) { PluginConfig.RemoteJiggleVelocityToDegrees.Value = 0.5f; } if (PluginConfig.RemoteJiggleAngularToDegrees != null) { PluginConfig.RemoteJiggleAngularToDegrees.Value = 0.16f; } if (PluginConfig.RemoteJiggleMinimumKick != null) { PluginConfig.RemoteJiggleMinimumKick.Value = 0.06f; } } if (GUILayout.Button("Solo Physics", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { if (PluginConfig.RemoteJiggleStrength != null) { PluginConfig.RemoteJiggleStrength.Value = 1.8f; } if (PluginConfig.RemoteJiggleStiffness != null) { PluginConfig.RemoteJiggleStiffness.Value = 6f; } if (PluginConfig.RemoteJiggleDamping != null) { PluginConfig.RemoteJiggleDamping.Value = 0.96f; } if (PluginConfig.RemoteJiggleMaxDegrees != null) { PluginConfig.RemoteJiggleMaxDegrees.Value = 24f; } if (PluginConfig.RemoteJiggleVelocityToDegrees != null) { PluginConfig.RemoteJiggleVelocityToDegrees.Value = 3f; } if (PluginConfig.RemoteJiggleAngularToDegrees != null) { PluginConfig.RemoteJiggleAngularToDegrees.Value = 0.55f; } if (PluginConfig.RemoteJiggleMinimumKick != null) { PluginConfig.RemoteJiggleMinimumKick.Value = 0.03f; } } if (GUILayout.Button("Test Soft", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { if (PluginConfig.RemoteJiggleStrength != null) { PluginConfig.RemoteJiggleStrength.Value = 4.53f; } if (PluginConfig.RemoteJiggleStiffness != null) { PluginConfig.RemoteJiggleStiffness.Value = 30.7f; } if (PluginConfig.RemoteJiggleDamping != null) { PluginConfig.RemoteJiggleDamping.Value = 0.92f; } if (PluginConfig.RemoteJiggleMaxDegrees != null) { PluginConfig.RemoteJiggleMaxDegrees.Value = 25.6f; } if (PluginConfig.RemoteJiggleVelocityToDegrees != null) { PluginConfig.RemoteJiggleVelocityToDegrees.Value = 7.72f; } if (PluginConfig.RemoteJiggleAngularToDegrees != null) { PluginConfig.RemoteJiggleAngularToDegrees.Value = 3.47f; } if (PluginConfig.RemoteJiggleMinimumKick != null) { PluginConfig.RemoteJiggleMinimumKick.Value = 2.6f; } } GUILayout.EndHorizontal(); GUILayout.Space(2f); if (DrawSection("Advanced Remote Jiggle Settings", _secJiggleAdvanced)) { if (PluginConfig.RemoteJiggleDebugPulse != null) { bool flag10 = GUILayout.Toggle(PluginConfig.RemoteJiggleDebugPulse.Value, "Debug Pulse (prove chain binding)", Array.Empty()); if (flag10 != PluginConfig.RemoteJiggleDebugPulse.Value) { PluginConfig.RemoteJiggleDebugPulse.Value = flag10; } } if (PluginConfig.RemoteJiggleDebugPulseRoot != null) { bool flag11 = GUILayout.Toggle(PluginConfig.RemoteJiggleDebugPulseRoot.Value, "Debug Pulse Root (prove loop running)", Array.Empty()); if (flag11 != PluginConfig.RemoteJiggleDebugPulseRoot.Value) { PluginConfig.RemoteJiggleDebugPulseRoot.Value = flag11; } } string[] obj4 = new string[6] { "Remote Jiggle Enabled: ", null, null, null, null, null }; ConfigEntry enableRemoteJiggleExperimental = PluginConfig.EnableRemoteJiggleExperimental; obj4[1] = ((enableRemoteJiggleExperimental != null && enableRemoteJiggleExperimental.Value) ? "true" : "false"); obj4[2] = " Debug Pulse: "; ConfigEntry remoteJiggleDebugPulse = PluginConfig.RemoteJiggleDebugPulse; obj4[3] = ((remoteJiggleDebugPulse != null && remoteJiggleDebugPulse.Value) ? "true" : "false"); obj4[4] = " Pulse Root: "; ConfigEntry remoteJiggleDebugPulseRoot = PluginConfig.RemoteJiggleDebugPulseRoot; obj4[5] = ((remoteJiggleDebugPulseRoot != null && remoteJiggleDebugPulseRoot.Value) ? "true" : "false"); GUILayout.Label(string.Concat(obj4), Array.Empty()); GUILayout.Label("Active Rigs: " + CosmeticDisplayManager.ActiveCount + " Visible Rigs: " + CosmeticDisplayManager.VisibleRigCount + " Rigs w/Chains: " + CosmeticDisplayManager.RigsWithJiggleChains + " Total Chains: " + CosmeticDisplayManager.TotalJiggleChains + " Total Bones: " + CosmeticDisplayManager.TotalJiggleBones, Array.Empty()); GUILayout.Label("Last Jiggle Tick Frame: " + CosmeticDisplayManager.LastJiggleTickFrame + " NoChains Count: " + CosmeticDisplayManager.LastNoChainsCount, Array.Empty()); GUILayout.Label("Last Jiggle Target Magnitude: " + CosmeticDisplayManager.LastJiggleTargetMagnitude.ToString("F3"), Array.Empty()); if (PluginConfig.RemoteJiggleStrength != null) { GUILayout.Label("Strength: " + PluginConfig.RemoteJiggleStrength.Value.ToString("F2") + " [0..6]", Array.Empty()); float num5 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleStrength.Value, 0f, 6f, Array.Empty()); if (Mathf.Abs(num5 - PluginConfig.RemoteJiggleStrength.Value) > 0.001f) { PluginConfig.RemoteJiggleStrength.Value = num5; } } if (PluginConfig.RemoteJiggleStiffness != null) { GUILayout.Label("Stiffness: " + PluginConfig.RemoteJiggleStiffness.Value.ToString("F1") + " [0.1..40]", Array.Empty()); float num6 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleStiffness.Value, 0.1f, 40f, Array.Empty()); if (Mathf.Abs(num6 - PluginConfig.RemoteJiggleStiffness.Value) > 0.05f) { PluginConfig.RemoteJiggleStiffness.Value = num6; } } if (PluginConfig.RemoteJiggleDamping != null) { GUILayout.Label("Damping: " + PluginConfig.RemoteJiggleDamping.Value.ToString("F2") + " [0..1]", Array.Empty()); float num7 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleDamping.Value, 0f, 1f, Array.Empty()); if (Mathf.Abs(num7 - PluginConfig.RemoteJiggleDamping.Value) > 0.001f) { PluginConfig.RemoteJiggleDamping.Value = num7; } } if (PluginConfig.RemoteJiggleMaxDegrees != null) { GUILayout.Label("Max Degrees: " + PluginConfig.RemoteJiggleMaxDegrees.Value.ToString("F1") + " [0..45]", Array.Empty()); float num8 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleMaxDegrees.Value, 0f, 45f, Array.Empty()); if (Mathf.Abs(num8 - PluginConfig.RemoteJiggleMaxDegrees.Value) > 0.05f) { PluginConfig.RemoteJiggleMaxDegrees.Value = num8; } } if (PluginConfig.RemoteJiggleVelocityToDegrees != null) { GUILayout.Label("Vel→Deg: " + PluginConfig.RemoteJiggleVelocityToDegrees.Value.ToString("F2") + " [0..8]", Array.Empty()); float num9 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleVelocityToDegrees.Value, 0f, 8f, Array.Empty()); if (Mathf.Abs(num9 - PluginConfig.RemoteJiggleVelocityToDegrees.Value) > 0.01f) { PluginConfig.RemoteJiggleVelocityToDegrees.Value = num9; } } if (PluginConfig.RemoteJiggleAngularToDegrees != null) { GUILayout.Label("Angular→Deg: " + PluginConfig.RemoteJiggleAngularToDegrees.Value.ToString("F2") + " [0..4]", Array.Empty()); float num10 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleAngularToDegrees.Value, 0f, 4f, Array.Empty()); if (Mathf.Abs(num10 - PluginConfig.RemoteJiggleAngularToDegrees.Value) > 0.005f) { PluginConfig.RemoteJiggleAngularToDegrees.Value = num10; } } if (PluginConfig.RemoteJiggleMinimumKick != null) { GUILayout.Label("Min Kick: " + PluginConfig.RemoteJiggleMinimumKick.Value.ToString("F2") + " [0..3]", Array.Empty()); float num11 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleMinimumKick.Value, 0f, 3f, Array.Empty()); if (Mathf.Abs(num11 - PluginConfig.RemoteJiggleMinimumKick.Value) > 0.005f) { PluginConfig.RemoteJiggleMinimumKick.Value = num11; } } } GUILayout.Space(4f); if (DrawSection("Updated Model Diagnostics", _secBulgeTest)) { DrawBulgeTestLab(sc); } } private static void DrawResetRow(string label, Action onReset) { GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("R", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(22f), GUILayout.Height(18f) })) { onReset(); } GUILayout.Label(label, Array.Empty()); GUILayout.EndHorizontal(); } private void DrawBulgeTestLab(ShlongController scIn) { bool flag = HasUsableUpdatedModels(); GUILayout.Label("Updated Model Bundle: " + (flag ? "loaded" : "missing"), Array.Empty()); GUILayout.Label("Expected file: ShlongsPackage_test.unity3d", Array.Empty()); GUILayout.Label("Expected mesh: SK_Deer.male.001", Array.Empty()); if (!flag) { GUILayout.Label("Updated model bundle not found.", Array.Empty()); GUILayout.Label("Place ShlongsPackage_test.unity3d next to the plugin DLL.", Array.Empty()); } bool retargeted; ShlongController shlongController = ResolveBulgeTestController(scIn, out retargeted); if ((Object)(object)scIn != (Object)null && retargeted && (Object)(object)shlongController != (Object)null && shlongController != scIn) { GUILayout.Label("Updated-model diagnostics targeting local player controller: " + ((Object)((Component)shlongController).gameObject).name, Array.Empty()); } if (GUILayout.Button("Log Controllers (updated-model diag)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { LogBulgeTestControllerInventory(scIn); } int num = ((Plugin.Presets != null) ? Plugin.Presets.FindPresetIndexById("equine_bulge_test") : (-1)); int num2 = ((Plugin.Presets != null) ? Plugin.Presets.FindPresetIndexById("equine") : (-1)); if ((Object)(object)shlongController != (Object)null) { PresetData presetData = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(shlongController.PresetIndex) : null); bool flag2 = presetData != null && presetData.Id == "equine_bulge_test"; GUILayout.Label("Active preset: " + ((presetData != null) ? presetData.DisplayName : "?") + (flag2 ? " (test)" : ""), Array.Empty()); bool flag3 = ((Object)((Component)shlongController).gameObject).name.Contains("(Clone)") && !((Object)((Component)shlongController).gameObject).name.Contains("equipDisplay"); bool flag4 = PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value; GUILayout.Label("Controller: " + ((Object)((Component)shlongController).gameObject).name + " clone=" + flag3 + " cloneSpawnBlock=" + flag4, Array.Empty()); if ((Object)(object)shlongController.DickMesh == (Object)null) { GUILayout.Label("No active mesh bound. Cannot inspect BlendShapes.", Array.Empty()); } else { shlongController.BlendShapes.EnsureCached(shlongController.DickMesh); if (shlongController.BlendShapes.BulgeKeysFound == 0) { GUILayout.Label("Active mesh has no Bulge_* BlendShapes.", Array.Empty()); } else { GUILayout.Label("BlendShapes: Aroused=" + ((!shlongController.BlendShapes.HasAroused) ? "no" : (shlongController.BlendShapes.ArousedIsLegacyFallback ? "legacy(Erect)" : "yes")) + ", Bulge keys " + shlongController.BlendShapes.BulgeKeysFound + "/" + shlongController.BlendShapes.BulgeKeyTotal, Array.Empty()); } } } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); GUI.enabled = (Object)(object)shlongController != (Object)null && num >= 0 && flag; if (GUILayout.Button("Switch to Equine Bulge Test", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { LogBulgeTestSwitchRequest(shlongController, num, "equine_bulge_test"); shlongController.QueueInteractivePresetChange(num); } GUI.enabled = (Object)(object)shlongController != (Object)null && num2 >= 0; if (GUILayout.Button("Return to Equine", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { LogBulgeTestSwitchRequest(shlongController, num2, "equine"); shlongController.QueueInteractivePresetChange(num2); } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.Space(6f); GUILayout.Label("Bulge controls are in the main Bulge section. This panel only verifies the updated-model contract and test preset routing.", Array.Empty()); } private static ShlongController ResolveBulgeTestController(ShlongController current, out bool retargeted) { retargeted = false; ShlongController shlongController = ShlongController.OurDick; if ((Object)(object)shlongController == (Object)null && (Object)(object)Player._mainPlayer != (Object)null) { shlongController = ((Component)Player._mainPlayer).GetComponentInChildren(true); } if ((Object)(object)shlongController != (Object)null && ((Object)((Component)shlongController).gameObject).name.Contains("equipDisplay")) { shlongController = null; } if ((Object)(object)shlongController != (Object)null) { if ((Object)(object)current == (Object)null || current != shlongController) { retargeted = true; } return shlongController; } if ((Object)(object)current != (Object)null && ((Object)((Component)current).gameObject).name.Contains("equipDisplay")) { return null; } return current; } private static void LogBulgeTestControllerInventory(ShlongController current) { try { bool value = PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("[BulgeTest] Controller inventory:"); stringBuilder.Append(" cloneSpawnBlock=").Append(value); stringBuilder.Append(" current="); if ((Object)(object)current != (Object)null) { stringBuilder.Append(((Object)((Component)current).gameObject).name); stringBuilder.Append(" (clone=").Append(((Object)((Component)current).gameObject).name.Contains("(Clone)") && !((Object)((Component)current).gameObject).name.Contains("equipDisplay")).Append(")"); } else { stringBuilder.Append(""); } int value2 = ((Plugin.Controllers != null) ? Plugin.Controllers.Count : (-1)); stringBuilder.Append(" Plugin.Controllers.Count=").Append(value2); Plugin.LogDebug(stringBuilder.ToString()); if (Plugin.Controllers != null) { int num = 0; foreach (KeyValuePair controller in Plugin.Controllers) { ShlongController value3 = controller.Value; AppendControllerLog("[BulgeTest] dict[" + num + "] key=" + controller.Key, value3, "Plugin.Controllers"); num++; } } ShlongController[] array = Object.FindObjectsOfType(); Plugin.LogDebug("[BulgeTest] FindObjectsOfType count=" + array.Length); for (int i = 0; i < array.Length; i++) { AppendControllerLog("[BulgeTest] scan[" + i + "]", array[i], "FindObjectsOfType"); } ShlongController shlongController = null; if ((Object)(object)Player._mainPlayer != (Object)null) { shlongController = ((Component)Player._mainPlayer).GetComponentInChildren(true); } Plugin.LogDebug("[BulgeTest] Player._mainPlayer=" + (((Object)(object)Player._mainPlayer != (Object)null) ? ((Object)((Component)Player._mainPlayer).gameObject).name : "") + " mainPlayerShlongController=" + (((Object)(object)shlongController != (Object)null) ? ((Object)((Component)shlongController).gameObject).name : "")); if ((Object)(object)shlongController != (Object)null) { AppendControllerLog("[BulgeTest] mainPlayerSc", shlongController, "Player._mainPlayer"); } Plugin.LogDebug("[BulgeTest] OurDick=" + (((Object)(object)ShlongController.OurDick != (Object)null) ? ((Object)((Component)ShlongController.OurDick).gameObject).name : "")); } catch (Exception ex) { Plugin.LogWarningLimited("bulge.inventory", "[BulgeTest] LogBulgeTestControllerInventory: " + ex.Message); } } private static void AppendControllerLog(string prefix, ShlongController c, string source) { if ((Object)(object)c == (Object)null) { Plugin.LogDebug(prefix + " source=" + source); return; } string name = ((Object)((Component)c).gameObject).name; bool flag = name.Contains("(Clone)") && !name.Contains("equipDisplay"); Plugin.LogDebug(prefix + " name=" + name + " source=" + source + " clone=" + flag + " activeInHierarchy=" + ((Component)c).gameObject.activeInHierarchy + " activeSelf=" + ((Component)c).gameObject.activeSelf + " enabled=" + ((Behaviour)c).enabled + " instanceRoot=" + (((Object)(object)c.InstanceRoot != (Object)null) ? ((Object)c.InstanceRoot).name : "") + " dickMesh=" + (((Object)(object)c.DickMesh != (Object)null) ? ((Object)c.DickMesh).name : "") + " preset=" + c.PresetIndex); } private static void LogBulgeTestSwitchRequest(ShlongController sc, int presetIndex, string expectedId) { try { PresetData presetData = Plugin.Presets?.GetPreset(presetIndex); Plugin.LogDebug("[BulgeTest] Switch requested: expectedId=" + expectedId + " presetIndex=" + presetIndex + " id=" + ((presetData != null) ? presetData.Id : "") + " prefabName=" + ((presetData != null) ? presetData.PrefabName : "") + " meshName=" + ((presetData != null) ? presetData.MeshName : "") + " assetSource=" + ((presetData != null) ? presetData.AssetSource.ToString() : "") + " loadedPrefab=" + ((presetData != null && (Object)(object)presetData.LoadedPrefab != (Object)null) ? ((Object)presetData.LoadedPrefab).name : "")); if ((Object)(object)sc != (Object)null) { ((MonoBehaviour)sc).StartCoroutine(LogBulgeTestSpawnResult(sc, presetIndex, expectedId)); } } catch (Exception ex) { Plugin.LogWarningLimited("bulge.switch_request", "[BulgeTest] LogBulgeTestSwitchRequest: " + ex.Message); } } private static IEnumerator LogBulgeTestSpawnResult(ShlongController sc, int presetIndex, string expectedId) { for (int i = 0; i < 30; i++) { if ((Object)(object)sc == (Object)null) { yield break; } if (sc.PresetIndex == presetIndex && (Object)(object)sc.InstanceRoot != (Object)null) { break; } yield return null; } if ((Object)(object)sc == (Object)null) { yield break; } try { PresetData preset = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(presetIndex) : null); string expectedMesh = ((preset != null) ? preset.MeshName : ""); string rootName = (((Object)(object)sc.InstanceRoot != (Object)null) ? ((Object)sc.InstanceRoot).name : ""); StringBuilder sb = new StringBuilder(); sb.Append("[BulgeTest] Spawn result:"); sb.Append(" expectedId=").Append(expectedId); sb.Append(" presetIndex=").Append(sc.PresetIndex); sb.Append(" controller=").Append(((Object)((Component)sc).gameObject).name); bool isClone = ((Object)((Component)sc).gameObject).name.Contains("(Clone)") && !((Object)((Component)sc).gameObject).name.Contains("equipDisplay"); bool blockEnabled = PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value; sb.Append(" clone=").Append(isClone); sb.Append(" cloneSpawnBlock=").Append(blockEnabled); sb.Append(" instanceRoot=").Append(rootName); sb.Append(" expectedMesh=").Append(expectedMesh); sb.Append(" dickMesh="); if ((Object)(object)sc.DickMesh != (Object)null) { sb.Append(((Object)sc.DickMesh).name); sb.Append(" sharedMesh="); sb.Append(((Object)(object)sc.DickMesh.sharedMesh != (Object)null) ? ((Object)sc.DickMesh.sharedMesh).name : ""); } else { sb.Append(""); } if ((Object)(object)sc.InstanceRoot != (Object)null) { SkinnedMeshRenderer[] renderers = sc.InstanceRoot.GetComponentsInChildren(true); sb.Append(" renderers=").Append(renderers.Length); for (int j = 0; j < renderers.Length; j++) { SkinnedMeshRenderer r = renderers[j]; sb.Append(" ["); sb.Append(j); sb.Append("] name="); sb.Append(((Object)(object)r != (Object)null) ? ((Object)r).name : ""); sb.Append(" mesh="); sb.Append(((Object)(object)r != (Object)null && (Object)(object)r.sharedMesh != (Object)null) ? ((Object)r.sharedMesh).name : ""); } } Plugin.LogDebug(sb.ToString()); } catch (Exception ex) { Plugin.LogWarningLimited("bulge.spawn_result", "[BulgeTest] LogBulgeTestSpawnResult: " + ex.Message); } } private void ApplyUvCheckerTextureOnce(ShlongController sc) { if ((Object)(object)sc == (Object)null) { Plugin.LogWarningLimited("settings.uvchecker.no_controller", "[UVChecker] No active local ShlongController to test."); return; } int changed = 0; ApplyUvCheckerToRenderer(sc.DickMesh, ref changed); if (sc.BallMeshes != null) { for (int i = 0; i < sc.BallMeshes.Length; i++) { ApplyUvCheckerToRenderer(sc.BallMeshes[i], ref changed); } } if (Plugin.Log != null) { Plugin.Log.LogInfo((object)("[UVChecker] Applied forced diagnostic material to " + changed + " material slot(s). It uses a high-contrast rainbow UV probe texture and tries Unlit/Texture first, so it bypasses the normal ColorAdjust/body-atlas shader as much as possible. If the shlong shows a multicolor/grid pattern, UVs are alive. If it remains a flat single color, the mesh UVs are likely collapsed or mapped into a tiny atlas area. If it remains white, the diagnostic material/shader assignment is still being overridden or not sampled. Use 'Restore Materials After UV Checker' or change any color/preset to rebuild normal materials.")); } } private void RestoreMaterialsAfterUvChecker(ShlongController sc) { if ((Object)(object)sc == (Object)null) { Plugin.LogWarningLimited("settings.uvchecker.restore.no_controller", "[UVChecker] No active local ShlongController to restore."); return; } try { sc.InvalidateColorMaterialCache(dick: true, balls: true); sc.ApplyColorTint(); sc.ApplyBallColorTint(); CosmeticDisplayManager.ForceRefreshColorsFor(sc, dick: true, balls: true); if (Plugin.Log != null) { Plugin.Log.LogInfo((object)"[UVChecker] Restored current shlong materials from active color settings."); } } catch (Exception ex) { Plugin.LogWarningLimited("settings.uvchecker.restore", "[UVChecker] Restore failed: " + ex.GetType().Name + ": " + ex.Message); } } private void ApplyBodyAtlasTextureProbeOnce(ShlongController sc) { //IL_00a7: 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_00d5: 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) if ((Object)(object)sc == (Object)null) { Plugin.LogWarningLimited("settings.bodyatlasprobe.no_controller", "[BodyAtlasProbe] No active local ShlongController to test."); return; } Material bodyMaterialForDiagnostics = GetBodyMaterialForDiagnostics(sc); if ((Object)(object)bodyMaterialForDiagnostics == (Object)null) { Plugin.LogWarningLimited("settings.bodyatlasprobe.no_bodymat", "[BodyAtlasProbe] Could not find the current race/body material."); return; } if (!MaterialSkinUtility.TryGetBestVisualTexture(bodyMaterialForDiagnostics, out var texture, out var scale, out var offset, out var propertyName) || (Object)(object)texture == (Object)null) { Plugin.LogWarningLimited("settings.bodyatlasprobe.no_texture", "[BodyAtlasProbe] Current body material has no usable visual texture. bodyMat=" + SafeName((Object)(object)bodyMaterialForDiagnostics) + " shader=" + SafeShaderName(bodyMaterialForDiagnostics)); return; } int changed = 0; ApplyForcedTextureProbeToRenderer(sc.DickMesh, texture, scale, offset, "BodyAtlasProbe", ref changed); if (sc.BallMeshes != null) { for (int i = 0; i < sc.BallMeshes.Length; i++) { ApplyForcedTextureProbeToRenderer(sc.BallMeshes[i], texture, scale, offset, "BodyAtlasProbe", ref changed); } } if (Plugin.Log != null) { Plugin.Log.LogInfo((object)("[BodyAtlasProbe] Applied forced Unlit/Texture body atlas probe to " + changed + " material slot(s). sourceBodyMat=" + SafeName((Object)(object)bodyMaterialForDiagnostics) + " texture=" + SafeTextureName(texture) + " prop=" + propertyName + " scale=" + ((Vector2)(ref scale)).ToString("F3") + " offset=" + ((Vector2)(ref offset)).ToString("F3") + ". If this still appears as one flat color, the shlong UVs are likely mapped to a mostly-uniform body atlas area. If this shows markings/details, then the normal ColorAdjust/manual color layer is flattening the visible texture.")); } } private void ApplyBodyAtlasColorAdjustProbeOnce(ShlongController sc, bool flipU, bool flipV) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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) if ((Object)(object)sc == (Object)null) { Plugin.LogWarningLimited("settings.bodyatlascolorprobe.no_controller", "[BodyAtlasColorProbe] No active local ShlongController to test."); return; } Material bodyMaterialForDiagnostics = GetBodyMaterialForDiagnostics(sc); if ((Object)(object)bodyMaterialForDiagnostics == (Object)null) { Plugin.LogWarningLimited("settings.bodyatlascolorprobe.no_bodymat", "[BodyAtlasColorProbe] Could not find the current race/body material."); return; } if (!MaterialSkinUtility.TryGetBestVisualTexture(bodyMaterialForDiagnostics, out var texture, out var scale, out var offset, out var propertyName) || (Object)(object)texture == (Object)null) { Plugin.LogWarningLimited("settings.bodyatlascolorprobe.no_texture", "[BodyAtlasColorProbe] Current body material has no usable visual texture. bodyMat=" + SafeName((Object)(object)bodyMaterialForDiagnostics) + " shader=" + SafeShaderName(bodyMaterialForDiagnostics)); return; } Vector2 scale2 = scale; Vector2 offset2 = offset; ApplyProbeFlip(ref scale2, ref offset2, flipU, flipV); int changed = 0; ApplyColorAdjustTextureProbeToRenderer(sc.DickMesh, bodyMaterialForDiagnostics, texture, scale2, offset2, "BodyAtlasColorProbe", ref changed); if (sc.BallMeshes != null) { for (int i = 0; i < sc.BallMeshes.Length; i++) { ApplyColorAdjustTextureProbeToRenderer(sc.BallMeshes[i], bodyMaterialForDiagnostics, texture, scale2, offset2, "BodyAtlasColorProbe", ref changed); } } if (Plugin.Log != null) { Plugin.Log.LogInfo((object)("[BodyAtlasColorProbe] Applied body-material ColorAdjust atlas probe to " + changed + " material slot(s). sourceBodyMat=" + SafeName((Object)(object)bodyMaterialForDiagnostics) + " shader=" + SafeShaderName(bodyMaterialForDiagnostics) + " texture=" + SafeTextureName(texture) + " prop=" + propertyName + " flipU=" + flipU + " flipV=" + flipV + " sourceScale=" + ((Vector2)(ref scale)).ToString("F3") + " sourceOffset=" + ((Vector2)(ref offset)).ToString("F3") + " probeScale=" + ((Vector2)(ref scale2)).ToString("F3") + " probeOffset=" + ((Vector2)(ref offset2)).ToString("F3") + ". This keeps the character ColorAdjust/HBC shader values, unlike the Unlit/Texture probe.")); } } private static void ApplyColorAdjustTextureProbeToRenderer(SkinnedMeshRenderer renderer, Material bodyMat, Texture texture, Vector2 scale, Vector2 offset, string suffix, ref int changed) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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) if ((Object)(object)renderer == (Object)null || (Object)(object)bodyMat == (Object)null || (Object)(object)texture == (Object)null) { return; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return; } for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if (!((Object)(object)val == (Object)null)) { Material val2 = new Material(bodyMat); string text = ((((Object)val).name != null) ? ((Object)val).name : "Material"); ((Object)val2).name = text.Replace(" (Instance)", "").Replace("_UVChecker", "").Replace("_BodyAtlasProbe", "") .Replace("_BodyAtlasColorProbe", "") + "_" + suffix + ((scale.x < 0f) ? "_UFlip" : "") + ((scale.y < 0f) ? "_VFlip" : ""); ApplyTextureToMaterial(val2, texture, scale, offset); sharedMaterials[i] = val2; changed++; } } ((Renderer)renderer).sharedMaterials = sharedMaterials; } private static void ApplyProbeFlip(ref Vector2 scale, ref Vector2 offset, bool flipU, bool flipV) { if (flipU) { float x = scale.x; scale.x = 0f - x; offset.x += x; } if (flipV) { float y = scale.y; scale.y = 0f - y; offset.y += y; } } private static void ApplyUvCheckerToRenderer(SkinnedMeshRenderer renderer, ref int changed) { //IL_00a4: 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_00ab: Expected O, but got Unknown if ((Object)(object)renderer == (Object)null) { return; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return; } Texture2D uvCheckerTexture = GetUvCheckerTexture(); Shader val = Shader.Find("Unlit/Texture"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Transparent"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Standard"); } for (int i = 0; i < sharedMaterials.Length; i++) { Material val2 = sharedMaterials[i]; if (!((Object)(object)val2 == (Object)null)) { Material val3 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(val2)); string text = ((((Object)val2).name != null) ? ((Object)val2).name : "Material"); ((Object)val3).name = text.Replace(" (Instance)", "").Replace("_UVChecker", "") + "_UVCheckerForced"; ApplyCheckerTextureToMaterial(val3, (Texture)(object)uvCheckerTexture); NeutralizeColorForUvChecker(val3); sharedMaterials[i] = val3; changed++; } } ((Renderer)renderer).sharedMaterials = sharedMaterials; } private static void ApplyForcedTextureProbeToRenderer(SkinnedMeshRenderer renderer, Texture texture, Vector2 scale, Vector2 offset, string suffix, ref int changed) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)renderer == (Object)null || (Object)(object)texture == (Object)null) { return; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return; } Shader val = Shader.Find("Unlit/Texture"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Transparent"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Standard"); } for (int i = 0; i < sharedMaterials.Length; i++) { Material val2 = sharedMaterials[i]; if (!((Object)(object)val2 == (Object)null)) { Material val3 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(val2)); string text = ((((Object)val2).name != null) ? ((Object)val2).name : "Material"); ((Object)val3).name = text.Replace(" (Instance)", "").Replace("_UVChecker", "").Replace("_BodyAtlasProbe", "") + "_" + suffix; ApplyTextureToMaterial(val3, texture, scale, offset); NeutralizeColorForUvChecker(val3); sharedMaterials[i] = val3; changed++; } } ((Renderer)renderer).sharedMaterials = sharedMaterials; } private static Texture2D GetUvCheckerTexture() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_uvCheckerTexture != (Object)null) { return _uvCheckerTexture; } Texture2D val = new Texture2D(256, 256, (TextureFormat)4, false) { name = "AtlyssShlongs_UV_RainbowProbe", filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)0 }; Color black = default(Color); for (int i = 0; i < 256; i++) { for (int j = 0; j < 256; j++) { float num = (float)j / 255f; float num2 = (float)i / 255f; float num3 = 0.1f + 0.75f * num; float num4 = 0.1f + 0.75f * num2; float num5 = 0.1f + 0.75f * ((float)((j * 37 + i * 17) & 0xFF) / 255f); bool flag = j % 16 == 0 || i % 16 == 0 || j % 16 == 15 || i % 16 == 15; bool flag2 = (j / 16 + i / 16) % 5 == 0 && j % 16 > 5 && j % 16 < 10 && i % 16 > 5 && i % 16 < 10; ((Color)(ref black))..ctor(num3, num4, num5, 1f); if (flag) { black = Color.black; } else if (flag2) { ((Color)(ref black))..ctor(1f, 0f, 0f, 1f); } val.SetPixel(j, i, black); } } val.Apply(false, false); _uvCheckerTexture = val; return _uvCheckerTexture; } private static void ApplyCheckerTextureToMaterial(Material mat, Texture tex) { //IL_0003: 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) ApplyTextureToMaterial(mat, tex, Vector2.one, Vector2.zero); } private static void ApplyTextureToMaterial(Material mat, Texture tex, Vector2 scale, Vector2 offset) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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) if ((Object)(object)mat == (Object)null || (Object)(object)tex == (Object)null) { return; } for (int i = 0; i < UvCheckerTextureProperties.Length; i++) { string text = UvCheckerTextureProperties[i]; try { if (mat.HasProperty(text)) { mat.SetTexture(text, tex); mat.SetTextureScale(text, scale); mat.SetTextureOffset(text, offset); } } catch { } } try { mat.mainTexture = tex; mat.mainTextureScale = scale; mat.mainTextureOffset = offset; } catch { } } private static void NeutralizeColorForUvChecker(Material mat) { //IL_0028: 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_007c: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mat == (Object)null) { return; } try { if (mat.HasProperty("_ColorTint")) { mat.SetColor("_ColorTint", Color.white); } } catch { } try { if (mat.HasProperty("_Tint")) { mat.SetColor("_Tint", Color.white); } } catch { } try { if (mat.HasProperty("_TintColor")) { mat.SetColor("_TintColor", Color.white); } } catch { } try { if (mat.HasProperty("_Color")) { mat.SetColor("_Color", Color.white); } } catch { } try { if (mat.HasProperty("_BaseColor")) { mat.SetColor("_BaseColor", Color.white); } } catch { } try { if (mat.HasProperty("_EmissionColor")) { mat.SetColor("_EmissionColor", Color.black); } } catch { } try { if (mat.HasProperty("_Hue")) { mat.SetFloat("_Hue", 0f); } } catch { } try { if (mat.HasProperty("_Brightness")) { mat.SetFloat("_Brightness", 1f); } } catch { } try { if (mat.HasProperty("_Contrast")) { mat.SetFloat("_Contrast", 1f); } } catch { } try { if (mat.HasProperty("_Saturation")) { mat.SetFloat("_Saturation", 1f); } } catch { } } private void LogCurrentShlongColorStateOnce(ShlongController sc) { StringBuilder stringBuilder = new StringBuilder(8192); stringBuilder.AppendLine("========== AtlyssShlongs Color Diagnostic =========="); stringBuilder.AppendLine("Copy this whole block when reporting color/material issues."); stringBuilder.AppendLine("Frame=" + Time.frameCount + " Time=" + Time.realtimeSinceStartup.ToString("F2", Cult)); stringBuilder.AppendLine("DebugMode=" + (Plugin.DebugMode != null && Plugin.DebugMode.Value)); stringBuilder.AppendLine("ApplyCharacterHBC=hidden/merged-into-MatchBody legacyConfig=" + (PluginConfig.ApplyCharacterHbcToMatchedShlongs != null && PluginConfig.ApplyCharacterHbcToMatchedShlongs.Value)); stringBuilder.AppendLine("HasUsableUpdatedModels=" + HasUsableUpdatedModels()); stringBuilder.AppendLine("SelectedModelCategory=" + _selectedModelCategory); stringBuilder.AppendLine("Bundle=" + ((Plugin.Assets != null) ? "loaded" : "NULL")); stringBuilder.AppendLine("ControllersCount=" + ((Plugin.Controllers != null) ? Plugin.Controllers.Count.ToString(Cult) : "null")); stringBuilder.AppendLine("OurDick=" + SafeName((Object)(object)ShlongController.OurDick)); stringBuilder.AppendLine("ActiveController=" + SafeName((Object)(object)sc)); AppendControllerColorDiagnostics(stringBuilder, "ActiveController", sc); if ((Object)(object)ShlongController.OurDick != (Object)null && ShlongController.OurDick != sc) { AppendControllerColorDiagnostics(stringBuilder, "OurDick", ShlongController.OurDick); } stringBuilder.AppendLine("===================================================="); if (Plugin.Log != null) { Plugin.Log.LogInfo((object)stringBuilder.ToString()); } else { Debug.Log((object)stringBuilder.ToString()); } } private void LogCurrentShlongUvStateOnce(ShlongController sc) { StringBuilder stringBuilder = new StringBuilder(8192); stringBuilder.AppendLine("========== AtlyssShlongs Mesh/UV Diagnostic =========="); stringBuilder.AppendLine("Copy this whole block when reporting UV/material-slot issues."); stringBuilder.AppendLine("Frame=" + Time.frameCount + " Time=" + Time.realtimeSinceStartup.ToString("F2", Cult)); stringBuilder.AppendLine("SelectedModelCategory=" + _selectedModelCategory); stringBuilder.AppendLine("HasUsableUpdatedModels=" + HasUsableUpdatedModels()); stringBuilder.AppendLine("ActiveController=" + SafeName((Object)(object)sc)); AppendControllerUvDiagnostics(stringBuilder, "ActiveController", sc); if ((Object)(object)ShlongController.OurDick != (Object)null && ShlongController.OurDick != sc) { AppendControllerUvDiagnostics(stringBuilder, "OurDick", ShlongController.OurDick); } stringBuilder.AppendLine("===================================================="); if (Plugin.Log != null) { Plugin.Log.LogInfo((object)stringBuilder.ToString()); } else { Debug.Log((object)stringBuilder.ToString()); } } private static void AppendControllerUvDiagnostics(StringBuilder sb, string label, ShlongController sc) { sb.AppendLine("---- " + label + " UV ----"); if ((Object)(object)sc == (Object)null) { sb.AppendLine(""); return; } sb.AppendLine("GO=" + SafeName((Object)(object)((Component)sc).gameObject) + " RaceIndex=" + sc.RaceIndex + " PresetIndex=" + sc.PresetIndex + " MatchBody=" + sc.MatchBody + " BallMatchBody=" + sc.BallMatchBody); PresetData presetData = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(sc.PresetIndex) : null); if (presetData != null) { sb.AppendLine("Preset id=" + presetData.Id + " source=" + presetData.AssetSource.ToString() + " prefab=" + presetData.PrefabName + " meshName=" + presetData.MeshName + " prefabLoaded=" + ((Object)(object)presetData.LoadedPrefab != (Object)null)); } else { sb.AppendLine("Preset="); } RaceData raceData = ((Plugin.Presets != null) ? Plugin.Presets.GetRace(sc.RaceIndex) : null); if (raceData != null) { sb.AppendLine("Race name=" + raceData.RaceName + " bodyMesh=" + raceData.BodyMesh + " materialSlot=" + raceData.MaterialSlot); } AppendRendererUvDiagnostics(sb, "Runtime DickMesh", sc.DickMesh); if (sc.BallMeshes == null) { sb.AppendLine("Runtime BallMeshes="); } else { sb.AppendLine("Runtime BallMeshes count=" + sc.BallMeshes.Length); for (int i = 0; i < sc.BallMeshes.Length; i++) { AppendRendererUvDiagnostics(sb, "Runtime BallMesh[" + i + "]", sc.BallMeshes[i]); } } if (presetData == null || !((Object)(object)presetData.LoadedPrefab != (Object)null)) { return; } sb.AppendLine("-- Prefab UV Renderers --"); try { SkinnedMeshRenderer[] componentsInChildren = presetData.LoadedPrefab.GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { sb.AppendLine("prefabRenderers="); return; } for (int j = 0; j < componentsInChildren.Length; j++) { AppendRendererUvDiagnostics(sb, "PrefabRenderer[" + j + "]", componentsInChildren[j]); } } catch (Exception ex) { sb.AppendLine("prefabUvDiagnostics="); } } private static void AppendRendererUvDiagnostics(StringBuilder sb, string label, SkinnedMeshRenderer renderer) { //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_049a: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_0633: Unknown result type (might be due to invalid IL or missing references) //IL_0638: Unknown result type (might be due to invalid IL or missing references) //IL_063d: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04b7: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Unknown result type (might be due to invalid IL or missing references) //IL_04db: Unknown result type (might be due to invalid IL or missing references) //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_04ff: Unknown result type (might be due to invalid IL or missing references) //IL_06b1: Unknown result type (might be due to invalid IL or missing references) //IL_06c3: Unknown result type (might be due to invalid IL or missing references) //IL_06d6: Unknown result type (might be due to invalid IL or missing references) //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_0531: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("-- " + label + " --"); if ((Object)(object)renderer == (Object)null) { sb.AppendLine("renderer="); return; } Mesh sharedMesh = renderer.sharedMesh; Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; sb.AppendLine("renderer=" + SafeName((Object)(object)renderer) + " enabled=" + ((Renderer)renderer).enabled + " active=" + ((Object)(object)((Component)renderer).gameObject != (Object)null && ((Component)renderer).gameObject.activeInHierarchy) + " mesh=" + (((Object)(object)sharedMesh != (Object)null) ? ((Object)sharedMesh).name : "") + " materialCount=" + ((sharedMaterials != null) ? sharedMaterials.Length : 0)); if (sharedMaterials != null) { for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; sb.Append(" material[").Append(i).Append("]="); if ((Object)(object)val == (Object)null) { sb.AppendLine(""); } else { sb.Append(((Object)val).name).Append(" shader=").Append(((Object)(object)val.shader != (Object)null) ? ((Object)val.shader).name : "") .Append(" mainTex=") .Append(FormatTextureForUvDiag(GetMaterialMainTextureSafe(val))) .AppendLine(); } } } if ((Object)(object)sharedMesh == (Object)null) { return; } bool flag = false; try { flag = sharedMesh.isReadable; } catch { flag = false; } sb.AppendLine("mesh vertexCount=" + sharedMesh.vertexCount + " subMeshCount=" + sharedMesh.subMeshCount + " isReadable=" + flag); if (!flag) { sb.AppendLine("uv0="); sb.AppendLine("uv2="); return; } Vector2[] array = null; Vector2[] array2 = null; try { array = sharedMesh.uv; } catch (Exception ex) { sb.AppendLine("uv0="); } try { array2 = sharedMesh.uv2; } catch (Exception ex2) { sb.AppendLine("uv2="); } sb.AppendLine("uv0Count=" + ((array != null) ? array.Length : 0) + " uv2Count=" + ((array2 != null) ? array2.Length : 0)); if (array == null || array.Length == 0) { sb.AppendLine("uv0="); return; } int subMeshCount = sharedMesh.subMeshCount; Vector2 val2 = default(Vector2); Vector2 val3 = default(Vector2); for (int j = 0; j < subMeshCount; j++) { int[] array3 = null; try { array3 = sharedMesh.GetTriangles(j); } catch (Exception ex3) { sb.AppendLine("submesh[" + j + "] triangles="); continue; } if (array3 == null || array3.Length == 0) { sb.AppendLine("submesh[" + j + "] triangles=0"); continue; } bool flag2 = false; ((Vector2)(ref val2))..ctor(float.PositiveInfinity, float.PositiveInfinity); ((Vector2)(ref val3))..ctor(float.NegativeInfinity, float.NegativeInfinity); Vector2 val4 = Vector2.zero; int num = 0; StringBuilder stringBuilder = new StringBuilder(); int num2 = 0; foreach (int num3 in array3) { if (num3 < 0 || num3 >= array.Length) { continue; } Vector2 val5 = array[num3]; flag2 = true; if (val5.x < val2.x) { val2.x = val5.x; } if (val5.y < val2.y) { val2.y = val5.y; } if (val5.x > val3.x) { val3.x = val5.x; } if (val5.y > val3.y) { val3.y = val5.y; } val4 += val5; num++; if (num2 < 12) { if (num2 > 0) { stringBuilder.Append(" "); } stringBuilder.Append("#").Append(num3).Append("(") .Append(val5.x.ToString("F3", Cult)) .Append(",") .Append(val5.y.ToString("F3", Cult)) .Append(")"); num2++; } } if (!flag2 || num == 0) { sb.AppendLine("submesh[" + j + "] validUv=0 triangles=" + array3.Length / 3); continue; } Vector2 v = val4 / (float)num; string text = ""; if (sharedMaterials != null && j >= 0 && j < sharedMaterials.Length && (Object)(object)sharedMaterials[j] != (Object)null) { text = ((Object)sharedMaterials[j]).name; } sb.AppendLine("submesh[" + j + "] triangles=" + array3.Length / 3 + " uvMin=" + FormatVector2(val2) + " uvMax=" + FormatVector2(val3) + " uvAvg=" + FormatVector2(v) + " material=" + text); sb.AppendLine(" uvSamples=" + stringBuilder.ToString()); } } private static Texture GetMaterialMainTextureSafe(Material mat) { if ((Object)(object)mat == (Object)null) { return null; } try { if ((Object)(object)mat.mainTexture != (Object)null) { return mat.mainTexture; } } catch { } string[] array = new string[4] { "_MainTex", "_BaseMap", "_BodyTex", "_SkinTex" }; for (int i = 0; i < array.Length; i++) { try { if (mat.HasProperty(array[i])) { Texture texture = mat.GetTexture(array[i]); if ((Object)(object)texture != (Object)null) { return texture; } } } catch { } } return null; } private static string FormatTextureForUvDiag(Texture tex) { if ((Object)(object)tex == (Object)null) { return ""; } return ((Object)tex).name + " " + tex.width + "x" + tex.height + " type=" + ((object)tex).GetType().Name; } private static string FormatVector2(Vector2 v) { return "(" + v.x.ToString("F3", Cult) + ", " + v.y.ToString("F3", Cult) + ")"; } private static void AppendControllerColorDiagnostics(StringBuilder sb, string label, ShlongController sc) { //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_05a6: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("---- " + label + " ----"); if ((Object)(object)sc == (Object)null) { sb.AppendLine(""); return; } sb.AppendLine("GO=" + SafeName((Object)(object)((Component)sc).gameObject) + " active=" + ((Object)(object)((Component)sc).gameObject != (Object)null && ((Component)sc).gameObject.activeInHierarchy) + " local=" + sc.IsLocal + " hasPlayerParent=" + sc.HasPlayerParent + " hasRuntimeRig=" + sc.HasRuntimeRig + " remoteReady=" + sc.HasReceivedRemoteVisualState); sb.AppendLine("SteamId=" + sc.GetKnownSteamId()); sb.AppendLine("PlayerObj=" + SafeName((Object)(object)sc.PlayerObj)); sb.AppendLine("RaceIndex=" + sc.RaceIndex + " PresetIndex=" + sc.PresetIndex); PresetData presetData = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(sc.PresetIndex) : null); if (presetData != null) { bool flag = presetData.AssetSource == PresetAssetSource.Test; sb.AppendLine("Preset id=" + presetData.Id + " name=" + presetData.FriendlyName + " source=" + presetData.AssetSource.ToString() + " actualCategory=" + (flag ? "Updated/Test" : "Original/Main") + " isActuallyUpdatedPreset=" + flag + " prefab=" + presetData.PrefabName + " prefabLoaded=" + ((Object)(object)presetData.LoadedPrefab != (Object)null)); if (Plugin.Presets != null) { if (flag) { int index = Plugin.Presets.FindOriginalCounterpartIndex(presetData); PresetData preset = Plugin.Presets.GetPreset(index); sb.AppendLine("OriginalCounterpart index=" + index + " id=" + ((preset != null) ? preset.Id : "") + " source=" + ((preset != null) ? preset.AssetSource.ToString() : "") + " prefab=" + ((preset != null) ? preset.PrefabName : "") + " prefabLoaded=" + (preset != null && (Object)(object)preset.LoadedPrefab != (Object)null)); } else { int num = FindUpdatedCounterpartIndex(presetData); PresetData preset2 = Plugin.Presets.GetPreset(num); sb.AppendLine("UpdatedCounterpart index=" + num + " id=" + ((preset2 != null) ? preset2.Id : "") + " source=" + ((preset2 != null) ? preset2.AssetSource.ToString() : "") + " prefab=" + ((preset2 != null) ? preset2.PrefabName : "") + " prefabLoaded=" + (preset2 != null && (Object)(object)preset2.LoadedPrefab != (Object)null) + " usable=" + (num >= 0 && Plugin.Presets.IsTestPresetUsableLocally(num))); } } } else { sb.AppendLine("Preset="); } if (presetData != null && presetData.AssetSource == PresetAssetSource.Test) { string text = ((Plugin.Assets != null) ? Plugin.Assets.DescribeBestTextureForPreset(presetData) : ""); sb.AppendLine("TestBundleTextureCandidate=" + text); if (Plugin.Assets != null) { sb.AppendLine(Plugin.Assets.DescribeTextureCandidatesForPreset(presetData)); } AppendPresetPrefabMaterialDiagnostics(sb, "TestPresetPrefabMaterials", presetData); } RaceData raceData = ((Plugin.Presets != null) ? Plugin.Presets.GetRace(sc.RaceIndex) : null); if (raceData != null) { sb.AppendLine("Race name=" + raceData.RaceName + " bodyMesh=" + raceData.BodyMesh + " materialSlot=" + raceData.MaterialSlot); } else { sb.AppendLine("Race="); } sb.AppendLine("Shaft: MatchBody=" + sc.MatchBody + " ColorTint=" + FormatColor(sc.ColorTint) + " ColorMode=" + sc.ColorMode); sb.AppendLine("Balls: MatchBody=" + sc.BallMatchBody + " ColorTint=" + FormatColor(sc.BallColorTint) + " ColorMode=" + sc.BallColorMode); sb.AppendLine("HasBallsSheathSlots=" + sc.HasBallsSheathSlots); sb.AppendLine("ScaleOffset=" + ((Vector3)(ref sc.ScaleOffset)).ToString("F3") + " PositionOffset=" + ((Vector2)(ref sc.PositionOffset)).ToString("F3") + " BaseRotation=" + ((Vector3)(ref sc.BaseRotation)).ToString("F3") + " ErectAngleOffset=" + sc.ErectAngleOffset.ToString("F3", Cult)); Material bodyMaterialForDiagnostics = GetBodyMaterialForDiagnostics(sc); AppendMaterialDiagnostics(sb, "BodyMaterial", bodyMaterialForDiagnostics); AppendRendererDiagnostics(sb, "DickMesh", sc.DickMesh); if (sc.BallMeshes == null) { sb.AppendLine("BallMeshes="); return; } sb.AppendLine("BallMeshes count=" + sc.BallMeshes.Length); for (int i = 0; i < sc.BallMeshes.Length; i++) { AppendRendererDiagnostics(sb, "BallMesh[" + i + "]", sc.BallMeshes[i]); } } private static void AppendPresetPrefabMaterialDiagnostics(StringBuilder sb, string label, PresetData preset) { sb.AppendLine("-- " + label + " --"); if (preset == null) { sb.AppendLine("preset="); return; } if ((Object)(object)preset.LoadedPrefab == (Object)null) { sb.AppendLine("prefab="); return; } try { SkinnedMeshRenderer[] componentsInChildren = preset.LoadedPrefab.GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { sb.AppendLine("renderers="); return; } sb.AppendLine("prefab=" + preset.PrefabName + " rendererCount=" + componentsInChildren.Length); for (int i = 0; i < componentsInChildren.Length; i++) { SkinnedMeshRenderer val = componentsInChildren[i]; if (!((Object)(object)val == (Object)null)) { sb.AppendLine("PrefabRenderer[" + i + "] name=" + SafeName((Object)(object)val) + " mesh=" + (((Object)(object)val.sharedMesh != (Object)null) ? ((Object)val.sharedMesh).name : "") + " materialCount=" + ((((Renderer)val).sharedMaterials != null) ? ((Renderer)val).sharedMaterials.Length : 0)); AppendMaterialArrayDiagnostics(sb, "PrefabRenderer[" + i + "].sharedMaterials", ((Renderer)val).sharedMaterials); } } } catch (Exception ex) { sb.AppendLine("prefabMaterialDiagnostics="); } } private static Material GetBodyMaterialForDiagnostics(ShlongController sc) { if ((Object)(object)sc == (Object)null || Plugin.Presets == null) { return null; } try { RaceData race = Plugin.Presets.GetRace(sc.RaceIndex); if (race == null) { return null; } SkinnedMeshRenderer val = null; if ((Object)(object)sc.CachedPlayerRaceModel != (Object)null && (Object)(object)sc.CachedPlayerRaceModel._baseBodyMesh != (Object)null) { val = sc.CachedPlayerRaceModel._baseBodyMesh; } if ((Object)(object)val == (Object)null && !string.IsNullOrEmpty(race.BodyMesh)) { Transform val2 = FindChildRecursive(((Component)sc).transform, race.BodyMesh); if ((Object)(object)val2 != (Object)null) { val = ((Component)val2).GetComponent(); } } if ((Object)(object)val == (Object)null || ((Renderer)val).sharedMaterials == null) { return null; } int num = race.MaterialSlot; if (num < 0 || num >= ((Renderer)val).sharedMaterials.Length) { num = 0; } if (num >= 0 && num < ((Renderer)val).sharedMaterials.Length) { return ((Renderer)val).sharedMaterials[num]; } } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogInfo((object)("[ColorDiag] Body material lookup failed: " + ex.GetType().Name + ": " + ex.Message)); } } return null; } private static Transform FindChildRecursive(Transform root, string childName) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(childName)) { return null; } if (((Object)root).name == childName) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindChildRecursive(root.GetChild(i), childName); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static void AppendRendererDiagnostics(StringBuilder sb, string label, SkinnedMeshRenderer renderer) { sb.AppendLine("-- " + label + " --"); if ((Object)(object)renderer == (Object)null) { sb.AppendLine("renderer="); return; } sb.AppendLine("renderer=" + SafeName((Object)(object)renderer) + " enabled=" + ((Renderer)renderer).enabled + " active=" + ((Object)(object)((Component)renderer).gameObject != (Object)null && ((Component)renderer).gameObject.activeInHierarchy) + " mesh=" + (((Object)(object)renderer.sharedMesh != (Object)null) ? ((Object)renderer.sharedMesh).name : "")); AppendMaterialArrayDiagnostics(sb, label + ".sharedMaterials", ((Renderer)renderer).sharedMaterials); } private static void AppendMaterialArrayDiagnostics(StringBuilder sb, string label, Material[] materials) { if (materials == null) { sb.AppendLine(label + "="); return; } sb.AppendLine(label + " count=" + materials.Length); for (int i = 0; i < materials.Length; i++) { AppendMaterialDiagnostics(sb, label + "[" + i + "]", materials[i]); } } private static void AppendMaterialDiagnostics(StringBuilder sb, string label, Material mat) { sb.AppendLine(label + ":"); if ((Object)(object)mat == (Object)null) { sb.AppendLine(" material="); return; } sb.AppendLine(" name=" + ((Object)mat).name + " shader=" + (((Object)(object)mat.shader != (Object)null) ? ((Object)mat.shader).name : "") + " renderQueue=" + mat.renderQueue); AppendColorProperty(sb, mat, "_Color"); AppendColorProperty(sb, mat, "_BaseColor"); AppendColorProperty(sb, mat, "_TintColor"); AppendColorProperty(sb, mat, "_ColorTint"); AppendColorProperty(sb, mat, "_EmissionColor"); AppendVectorProperty(sb, mat, "_HBC"); AppendVectorProperty(sb, mat, "_ColorAdjust"); AppendFloatProperty(sb, mat, "_Hue"); AppendFloatProperty(sb, mat, "_Brightness"); AppendFloatProperty(sb, mat, "_Contrast"); AppendFloatProperty(sb, mat, "_Saturation"); AppendTextureProperty(sb, mat, "_MainTex"); AppendTextureProperty(sb, mat, "_BaseMap"); AppendTextureProperty(sb, mat, "_BodyTex"); AppendTextureProperty(sb, mat, "_SkinTex"); AppendTextureProperty(sb, mat, "_EmissionMap"); AppendTextureProperty(sb, mat, "_BumpMap"); AppendAllTextureProperties(sb, mat); } private static void AppendAllTextureProperties(StringBuilder sb, Material mat) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Invalid comparison between Unknown and I4 //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mat == (Object)null) { return; } try { sb.AppendLine(" mainTexture=" + FormatTexture(mat.mainTexture)); } catch { } try { Shader shader = mat.shader; if ((Object)(object)shader == (Object)null) { return; } int propertyCount = shader.GetPropertyCount(); sb.AppendLine(" AllTextureProperties count=" + propertyCount); for (int i = 0; i < propertyCount; i++) { if ((int)shader.GetPropertyType(i) != 4) { continue; } string propertyName = shader.GetPropertyName(i); Texture tex = null; Vector2 val = Vector2.one; Vector2 val2 = Vector2.zero; try { if (mat.HasProperty(propertyName)) { tex = mat.GetTexture(propertyName); val = mat.GetTextureScale(propertyName); val2 = mat.GetTextureOffset(propertyName); } } catch { } sb.AppendLine(" [" + i + "] " + propertyName + "=" + FormatTexture(tex) + " scale=" + ((Vector2)(ref val)).ToString("F3") + " offset=" + ((Vector2)(ref val2)).ToString("F3")); } } catch (Exception ex) { sb.AppendLine(" AllTextureProperties="); } } private static string FormatTexture(Texture tex) { if ((Object)(object)tex == (Object)null) { return ""; } return ((Object)tex).name + " " + tex.width + "x" + tex.height + " type=" + ((object)tex).GetType().Name; } private static void AppendColorProperty(StringBuilder sb, Material mat, string prop) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)mat != (Object)null && mat.HasProperty(prop)) { sb.AppendLine(" " + prop + "=" + FormatColor(mat.GetColor(prop))); } } catch { } } private static void AppendVectorProperty(StringBuilder sb, Material mat, string prop) { //IL_0027: 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) try { if ((Object)(object)mat != (Object)null && mat.HasProperty(prop)) { Vector4 vector = mat.GetVector(prop); sb.AppendLine(" " + prop + "=" + ((Vector4)(ref vector)).ToString("F3")); } } catch { } } private static void AppendFloatProperty(StringBuilder sb, Material mat, string prop) { try { if ((Object)(object)mat != (Object)null && mat.HasProperty(prop)) { sb.AppendLine(" " + prop + "=" + mat.GetFloat(prop).ToString("F4", Cult)); } } catch { } } private static void AppendTextureProperty(StringBuilder sb, Material mat, string prop) { try { if (!((Object)(object)mat == (Object)null) && mat.HasProperty(prop)) { Texture texture = mat.GetTexture(prop); if ((Object)(object)texture == (Object)null) { sb.AppendLine(" " + prop + "="); return; } sb.AppendLine(" " + prop + "=" + ((Object)texture).name + " " + texture.width + "x" + texture.height); } } catch { } } private static string FormatColor(Color c) { return "(" + c.r.ToString("F3", Cult) + ", " + c.g.ToString("F3", Cult) + ", " + c.b.ToString("F3", Cult) + ", " + c.a.ToString("F3", Cult) + ")"; } private static string SafeName(Object obj) { return (obj != (Object)null) ? obj.name : ""; } private static string SafeShaderName(Material mat) { try { return ((Object)(object)mat != (Object)null && (Object)(object)mat.shader != (Object)null) ? ((Object)mat.shader).name : ""; } catch { return ""; } } private static string SafeTextureName(Texture tex) { try { if ((Object)(object)tex == (Object)null) { return ""; } return ((Object)tex).name + " " + tex.width + "x" + tex.height + " type=" + ((object)tex).GetType().Name; } catch { return ""; } } private void DrawCharacterSelectPreviewModeControls() { if (Plugin.UserPresets != null) { int currentProfileIndex = RaceModelPatch.GetCurrentProfileIndex(); if (currentProfileIndex < 0) { GUILayout.Label("Character Select Preview: Unavailable outside a character slot.", Array.Empty()); GUILayout.Space(4f); return; } int mode = Plugin.UserPresets.LoadCharacterSelectPreviewMode(currentProfileIndex); mode = UserPresetManager.NormalizeCharacterSelectPreviewMode(mode); GUILayout.Label("Character Select Preview: " + UserPresetManager.FormatCharacterSelectPreviewMode(mode), Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); DrawCharacterPreviewModeButton("Use Global", 0, mode, currentProfileIndex); DrawCharacterPreviewModeButton("Show", 1, mode, currentProfileIndex); DrawCharacterPreviewModeButton("Hide", 2, mode, currentProfileIndex); GUILayout.EndHorizontal(); GUILayout.Space(4f); } } private void DrawCharacterPreviewModeButton(string label, int mode, int currentMode, int slotIndex) { bool flag = currentMode == mode; if (GUILayout.Toggle(flag, label, GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }) && !flag) { Plugin.UserPresets.SaveCharacterSelectPreviewMode(slotIndex, GetCurrentCharacterName(), GetCurrentCharacterRaceTag(), mode); if ((Object)(object)_cachedController != (Object)null && _cachedController.IsLocal && _cachedController.IsCharacterPreviewController()) { _cachedController.CharacterSelectPreviewMode = mode; } RaceModelPatch.RefreshCharacterPreviewControllers(); } } private static string GetCurrentCharacterName() { try { if ((Object)(object)ProfileDataManager._current != (Object)null && ProfileDataManager._current._characterFile != null) { return ProfileDataManager._current._characterFile._nickName ?? string.Empty; } } catch { } return string.Empty; } private static string GetCurrentCharacterRaceTag() { try { if ((Object)(object)ProfileDataManager._current != (Object)null && ProfileDataManager._current._characterFile != null && ProfileDataManager._current._characterFile._appearanceProfile != null) { return ProfileDataManager._current._characterFile._appearanceProfile._setRaceTag ?? string.Empty; } } catch { } return string.Empty; } private void DrawToggleActionRow(string label, bool value, ConfigEntry shortcut, Action onClick) { GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button((value ? "● " : "○ ") + label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { onClick(); } GUILayout.EndHorizontal(); if (shortcut != null) { DrawBindRow(null, shortcut); } } private void DrawButtonActionRow(string label, ConfigEntry shortcut, Action onClick) { GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { onClick(); } GUILayout.EndHorizontal(); DrawBindRow(null, shortcut); } private void DrawBulgePositionBindRow(string label, ConfigEntry shortcut, ShlongController sc, float position) { GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button(label + " → " + position.ToString("0", Cult), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }) && (Object)(object)sc != (Object)null) { sc.BulgePosition = position; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); } GUILayout.EndHorizontal(); DrawBindRow(null, shortcut); } private void DrawBindRow(string label, ConfigEntry shortcut, bool allowUnbind = true) { //IL_00af: 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_00df: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_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_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) if (shortcut == null) { return; } bool flag = _openModifierDropdown == shortcut; bool flag2 = _pendingShortcut == shortcut && _pendingShortcutPart == ShortcutCapturePart.MainKey; bool flag3 = flag || flag2; EnsureBindStyles(); GUILayout.BeginHorizontal(Array.Empty()); if (label != null) { string text = (allowUnbind ? (" " + label) : (" " + label + " (required)")); GUILayout.Label(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) }); } else { GUILayout.Space(20f); } if (_bindLabelStyle == null || _bindLabelStyle.normal.textColor.a < 0.01f) { _bindLabelStyle = new GUIStyle(GUI.skin.label); _bindLabelStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f); } GUIStyle val = (flag3 ? _activeBindLabelStyle : _bindLabelStyle); GUILayout.Label(InputManager.FormatShortcut(shortcut.Value), val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Space(20f); GUIStyle val2 = (flag ? _activeBindButtonStyle : GUI.skin.button); GUIStyle val3 = (flag2 ? _activeBindButtonStyle : GUI.skin.button); if (GUILayout.Button("Mod: " + FormatModifierLabel(GetSelectedModifier(shortcut.Value)), val2, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(110f), GUILayout.Height(18f) })) { ToggleModifierDropdown(shortcut); } if (GUILayout.Button("Key", val3, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(48f), GUILayout.Height(18f) })) { BeginShortcutCapture(shortcut, label, allowUnbind, ShortcutCapturePart.MainKey); } if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(52f), GUILayout.Height(18f) })) { ResetShortcutToDefault(shortcut); } if (allowUnbind && GUILayout.Button("Clear", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(48f), GUILayout.Height(18f) })) { shortcut.Value = new KeyboardShortcut((KeyCode)0, Array.Empty()); ResetPendingShortcutCapture(); if (flag) { _openModifierDropdown = null; } } GUILayout.EndHorizontal(); if (!flag) { return; } GUILayout.BeginHorizontal(GUI.skin.box, Array.Empty()); GUILayout.Space(20f); for (int i = 0; i < ModifierOptionLabels.Length; i++) { KeyCode val4 = ModifierOptionKeys[i]; bool flag4 = GetSelectedModifier(shortcut.Value) == val4; if (GUILayout.Toggle(flag4, ModifierOptionLabels[i], GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(54f) }) && !flag4) { SetShortcutModifier(shortcut, val4); _openModifierDropdown = null; } } GUILayout.EndHorizontal(); } private void HandleShortcutCapture(Event evt) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Invalid comparison between Unknown and I4 //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Invalid comparison between Unknown and I4 //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00ad: 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_00bd: Unknown result type (might be due to invalid IL or missing references) if (_pendingShortcut == null || evt == null || _pendingShortcutPart != ShortcutCapturePart.MainKey || (int)evt.type != 4) { return; } if ((int)evt.keyCode == 8) { ResetPendingShortcutCapture(); evt.Use(); } else { if ((int)evt.keyCode == 0) { return; } KeyCode val = NormalizeModifierKey(evt.keyCode); if (IsModifierKey(val)) { evt.Use(); return; } KeyCode selectedModifier = GetSelectedModifier(_pendingShortcut.Value); List list = new List(); if ((int)selectedModifier != 0 && selectedModifier != val) { AddShortcutModifier(list, selectedModifier); } _pendingShortcut.Value = new KeyboardShortcut(val, list.ToArray()); ResetPendingShortcutCapture(); evt.Use(); } } private void BeginShortcutCapture(ConfigEntry shortcut, string label, bool allowUnbind, ShortcutCapturePart part) { ResetPendingShortcutCapture(); _pendingShortcut = shortcut; _pendingShortcutLabel = label ?? ((ConfigEntryBase)shortcut).Definition.Key; _pendingShortcutAllowUnbind = allowUnbind; _pendingShortcutPart = part; _openModifierDropdown = null; IsRebindActive = true; } private void ResetShortcutToDefault(ConfigEntry shortcut) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (shortcut != null) { shortcut.Value = (KeyboardShortcut)((ConfigEntryBase)shortcut).DefaultValue; if (_pendingShortcut == shortcut) { ResetPendingShortcutCapture(); } } } private void ResetPendingShortcutCapture() { _pendingShortcut = null; _pendingShortcutLabel = null; _pendingShortcutAllowUnbind = true; _pendingShortcutPart = ShortcutCapturePart.None; IsRebindActive = false; } private void ResetAllShortcutsToDefault() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) foreach (ConfigEntry shortcutEntry in GetShortcutEntries()) { if (shortcutEntry != null) { shortcutEntry.Value = (KeyboardShortcut)((ConfigEntryBase)shortcutEntry).DefaultValue; } } ResetPendingShortcutCapture(); _openModifierDropdown = null; } private IEnumerable> GetShortcutEntries() { yield return InputManager.GetPrevDick(); yield return InputManager.GetNextDick(); yield return InputManager.GetToggleHide(); yield return InputManager.GetToggleFuta(); yield return InputManager.GetToggleClothing(); yield return InputManager.GetCycleArousal(); yield return InputManager.GetToggleArousal(); yield return InputManager.GetIncreaseDick(); yield return InputManager.GetDecreaseDick(); yield return InputManager.GetIncreaseBalls(); yield return InputManager.GetDecreaseBalls(); yield return InputManager.GetManualSync(); yield return InputManager.GetAdjustOffset(); yield return InputManager.GetBulgePosition0(); yield return InputManager.GetBulgePosition1(); yield return InputManager.GetBulgePosition2(); yield return InputManager.GetBulgePosition3(); yield return InputManager.GetBulgePosition4(); yield return InputManager.GetBulgePosition5(); yield return InputManager.GetBulgePosition6(); yield return InputManager.GetToggleGui(); } private void EnsureBindStyles() { //IL_0014: 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_0042: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00bf: 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_00fe: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) if (_bindLabelStyle == null || _bindLabelStyle.normal.textColor.a < 0.01f) { _bindLabelStyle = new GUIStyle(GUI.skin.label); _bindLabelStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f); } if (_activeBindLabelStyle == null || _activeBindLabelStyle.normal.textColor.a < 0.01f) { _activeBindLabelStyle = new GUIStyle(_bindLabelStyle); _activeBindLabelStyle.normal.textColor = new Color(1f, 0.9f, 0.35f); _activeBindLabelStyle.fontStyle = (FontStyle)1; } if (_activeBindButtonStyle == null) { _activeBindButtonStyle = new GUIStyle(GUI.skin.button); _activeBindButtonStyle.fontStyle = (FontStyle)1; _activeBindButtonStyle.normal.textColor = new Color(1f, 0.95f, 0.45f); _activeBindButtonStyle.hover.textColor = new Color(1f, 0.95f, 0.6f); _activeBindButtonStyle.active.textColor = Color.white; } } private void ToggleModifierDropdown(ConfigEntry shortcut) { if (_openModifierDropdown == shortcut) { _openModifierDropdown = null; } else { _openModifierDropdown = shortcut; } if (_pendingShortcut == shortcut) { ResetPendingShortcutCapture(); } } private static bool IsModifierKey(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 return (int)key == 306 || (int)key == 305 || (int)key == 308 || (int)key == 307 || (int)key == 304 || (int)key == 303; } private static KeyCode NormalizeModifierKey(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_001d: 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_002e: Invalid comparison between Unknown and I4 //IL_0062: 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_0045: Invalid comparison between Unknown and I4 //IL_003c: 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_004d: Invalid comparison between Unknown and I4 //IL_005e: 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_005b: Unknown result type (might be due to invalid IL or missing references) if ((int)key == 306 || (int)key == 305) { return (KeyCode)306; } if ((int)key == 308 || (int)key == 307) { return (KeyCode)308; } if ((int)key == 304 || (int)key == 303) { return (KeyCode)304; } return key; } private static void AddShortcutModifier(List mods, KeyCode modifier) { //IL_0002: 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) if (!mods.Contains(modifier)) { mods.Add(modifier); } } private static KeyCode GetSelectedModifier(KeyboardShortcut shortcut) { //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_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) //IL_001f: 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_0026: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_005f: 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_0040: Unknown result type (might be due to invalid IL or missing references) foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { KeyCode val = NormalizeModifierKey(modifier); if ((int)val == 306 || (int)val == 308 || (int)val == 304) { return val; } } return (KeyCode)0; } private void SetShortcutModifier(ConfigEntry shortcut, KeyCode modifier) { //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_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_0025: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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 (shortcut != null) { KeyboardShortcut value = shortcut.Value; KeyCode val = NormalizeModifierKey(((KeyboardShortcut)(ref value)).MainKey); List list = new List(); if ((int)modifier != 0 && modifier != val) { AddShortcutModifier(list, modifier); } shortcut.Value = new KeyboardShortcut(val, list.ToArray()); if (_pendingShortcut == shortcut) { ResetPendingShortcutCapture(); } } } private static string FormatModifierLabel(KeyCode modifier) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 if ((int)modifier == 306) { return "Ctrl"; } if ((int)modifier == 308) { return "Alt"; } if ((int)modifier == 304) { return "Shift"; } return "None"; } private static string FormatPendingShortcutModifiers(KeyboardShortcut shortcut) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0028: 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_002f: Invalid comparison between Unknown and I4 //IL_0037: 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_007d: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_00c8: Invalid comparison between Unknown and I4 //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { KeyCode val = NormalizeModifierKey(modifier); if ((int)val == 306 && !list.Contains(((object)(KeyCode)306/*cast due to .constrained prefix*/).ToString())) { list.Add(((object)(KeyCode)306/*cast due to .constrained prefix*/).ToString()); } else if ((int)val == 308 && !list.Contains(((object)(KeyCode)308/*cast due to .constrained prefix*/).ToString())) { list.Add(((object)(KeyCode)308/*cast due to .constrained prefix*/).ToString()); } else if ((int)val == 304 && !list.Contains(((object)(KeyCode)304/*cast due to .constrained prefix*/).ToString())) { list.Add(((object)(KeyCode)304/*cast due to .constrained prefix*/).ToString()); } } return (list.Count == 0) ? "None" : string.Join(" + ", list.ToArray()); } private string FormatPendingShortcutModifiers() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) return (_pendingShortcut != null) ? FormatPendingShortcutModifiers(_pendingShortcut.Value) : "None"; } private static bool IsCharacterPreviewContext() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 if (Plugin.CharMenuON) { return true; } try { if ((Object)(object)MainMenuManager._current != (Object)null) { MainMenuCondition mainMenuCondition = MainMenuManager._current._mainMenuCondition; return (int)mainMenuCondition == 1 || (int)mainMenuCondition == 2; } } catch { } return false; } private ShlongController GetActiveController() { ShlongController shlongController = ShlongController.ResolveLocalAuthoritative(); if ((Object)(object)shlongController != (Object)null) { _cachedController = shlongController; return shlongController; } bool flag = IsCharacterPreviewContext(); if ((Object)(object)_cachedController != (Object)null && _cachedController.IsLocal && (_cachedController.HasPlayerParent || (flag && _cachedController.IsCharacterPreviewController()))) { return _cachedController; } if (Time.unscaledTime - _lastControllerLookup < 1f) { return null; } _lastControllerLookup = Time.unscaledTime; _cachedController = null; ShlongController[] array = Object.FindObjectsOfType(); foreach (ShlongController shlongController2 in array) { if (!((Object)(object)shlongController2 == (Object)null) && shlongController2.IsLocal && (shlongController2.HasPlayerParent || (flag && shlongController2.IsCharacterPreviewController()))) { _cachedController = shlongController2; return shlongController2; } } return null; } static SettingsWindow() { ModifierOptionLabels = new string[4] { "None", "Ctrl", "Alt", "Shift" }; KeyCode[] array = new KeyCode[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); ModifierOptionKeys = (KeyCode[])(object)array; Cult = new CultureInfo("en-US"); UvCheckerTextureProperties = new string[7] { "_MainTex", "_BaseMap", "_BaseColorMap", "_Albedo", "_AlbedoMap", "_Diffuse", "_DiffuseMap" }; } } } namespace AtlyssShlongs.Patches { internal static class LifecycleDiagnostics { private static int _attachTotal; private static int _attachEquipDisplay; private static int _attachClone; private static int _queueInitialSpawn; private static int _spawnCalls; private static int _deferredSpawnSuccess; private static int _spawnBlockedForDiagnostics; private static int _registerTotal; private static int _registerOverwrite; private static int _unregisterTotal; private static int _transitionTeardown; private static int _transitionRespawn; private static int _presetQueued; private static int _presetApplied; private static int _sizeAdjustments; private static int _registerRejected; private static int _orphanCleanup; private static int _cosmeticSpawns; private static int _cosmeticNoOpEntries; private static int _cosmeticInstantiateOnly; private static int _cosmeticWithBones; private static int _cosmeticBoneFindOnly; private static int _cosmeticWithFollow; private static int _cosmeticWithSizeBone; private static int _cosmeticSizeBoneStoredOnly; private static int _cosmeticWithDickMesh; private static int _cosmeticFullSpawn; private static int _loadingAttachBuffered; private static int _loadingStartCalls; private static int _loadingOnDestroyCalls; private static int _loadingDestroySkipped; internal static void OnAttach(bool isEquipDisplay, bool isClone) { _attachTotal++; if (isEquipDisplay) { _attachEquipDisplay++; } if (isClone) { _attachClone++; } } internal static void OnQueueInitialSpawn() { _queueInitialSpawn++; } internal static void OnSpawnCall() { _spawnCalls++; } internal static void OnDeferredSpawnSuccess() { _deferredSpawnSuccess++; } internal static void OnSpawnBlockedForDiagnostics() { _spawnBlockedForDiagnostics++; } internal static void OnRegister(bool overwrite) { _registerTotal++; if (overwrite) { _registerOverwrite++; } } internal static void OnUnregister() { _unregisterTotal++; } internal static void OnTransitionTeardown() { _transitionTeardown++; } internal static void OnTransitionRespawn() { _transitionRespawn++; } internal static void OnPresetQueued() { _presetQueued++; } internal static void OnPresetApplied() { _presetApplied++; } internal static void OnSizeAdjustment() { _sizeAdjustments++; } internal static void OnRegisterRejected() { _registerRejected++; } internal static void OnOrphanCleanup() { _orphanCleanup++; } internal static void OnCosmeticSpawn() { _cosmeticSpawns++; } internal static void OnCosmeticNoOpEntry() { _cosmeticNoOpEntries++; } internal static void OnCosmeticInstantiateOnly() { _cosmeticInstantiateOnly++; } internal static void OnCosmeticWithBones() { _cosmeticWithBones++; } internal static void OnCosmeticBoneFindOnly() { _cosmeticBoneFindOnly++; } internal static void OnCosmeticWithFollow() { _cosmeticWithFollow++; } internal static void OnCosmeticWithSizeBone() { _cosmeticWithSizeBone++; } internal static void OnCosmeticSizeBoneStoredOnly() { _cosmeticSizeBoneStoredOnly++; } internal static void OnCosmeticWithDickMesh() { _cosmeticWithDickMesh++; } internal static void OnCosmeticFullSpawn() { _cosmeticFullSpawn++; } internal static void OnLoadingAttachBuffered() { _loadingAttachBuffered++; } internal static void OnLoadingStartCall() { _loadingStartCalls++; } internal static void OnLoadingOnDestroy() { _loadingOnDestroyCalls++; } internal static void OnLoadingDestroySkipped() { _loadingDestroySkipped++; } internal static string BuildHeartbeatSnapshot() { if (PluginConfig.EnableLifecycleDiagnostics == null || !PluginConfig.EnableLifecycleDiagnostics.Value) { return string.Empty; } int num = 0; int num2 = 0; int num3 = 0; foreach (ShlongController allInstance in ShlongController.AllInstances) { if (!((Object)(object)allInstance == (Object)null)) { if (allInstance.HasDeferredSpawn) { num++; } if (allInstance.HasPlayerParent) { num2++; } if (allInstance.HasRuntimeRig) { num3++; } } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(" lifecycle={"); stringBuilder.Append("attach=").Append(_attachTotal); stringBuilder.Append(",equipAttach=").Append(_attachEquipDisplay); stringBuilder.Append(",cloneAttach=").Append(_attachClone); stringBuilder.Append(",queued=").Append(_queueInitialSpawn); stringBuilder.Append(",spawnCalls=").Append(_spawnCalls); stringBuilder.Append(",deferredOk=").Append(_deferredSpawnSuccess); stringBuilder.Append(",spawnBlocked=").Append(_spawnBlockedForDiagnostics); stringBuilder.Append(",register=").Append(_registerTotal); stringBuilder.Append(",overwrite=").Append(_registerOverwrite); stringBuilder.Append(",unregister=").Append(_unregisterTotal); stringBuilder.Append(",teardown=").Append(_transitionTeardown); stringBuilder.Append(",respawn=").Append(_transitionRespawn); stringBuilder.Append(",presetQueued=").Append(_presetQueued); stringBuilder.Append(",presetApplied=").Append(_presetApplied); stringBuilder.Append(",sizeAdjust=").Append(_sizeAdjustments); stringBuilder.Append(",registerRejected=").Append(_registerRejected); stringBuilder.Append(",orphanCleanup=").Append(_orphanCleanup); stringBuilder.Append(",cosmeticSpawns=").Append(_cosmeticSpawns); stringBuilder.Append(",cosmeticNoOp=").Append(_cosmeticNoOpEntries); stringBuilder.Append(",cosmeticInstOnly=").Append(_cosmeticInstantiateOnly); stringBuilder.Append(",cosmeticWithBones=").Append(_cosmeticWithBones); stringBuilder.Append(",cosmeticBoneFindOnly=").Append(_cosmeticBoneFindOnly); stringBuilder.Append(",cosmeticWithFollow=").Append(_cosmeticWithFollow); stringBuilder.Append(",cosmeticWithSizeBone=").Append(_cosmeticWithSizeBone); stringBuilder.Append(",cosmeticSzBoneStoreOnly=").Append(_cosmeticSizeBoneStoredOnly); stringBuilder.Append(",cosmeticWithDickMesh=").Append(_cosmeticWithDickMesh); stringBuilder.Append(",cosmeticFullSpawn=").Append(_cosmeticFullSpawn); stringBuilder.Append(",loadingAttachBuf=").Append(_loadingAttachBuffered); stringBuilder.Append(",loadingStart=").Append(_loadingStartCalls); stringBuilder.Append(",loadingOnDestroy=").Append(_loadingOnDestroyCalls); stringBuilder.Append(",loadingDestroySkip=").Append(_loadingDestroySkipped); stringBuilder.Append(",deferredLive=").Append(num); stringBuilder.Append(",playerParent=").Append(num2); stringBuilder.Append(",runtimeRigs=").Append(num3); stringBuilder.Append(",blockCloneSpawn=").Append(PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value); stringBuilder.Append('}'); return stringBuilder.ToString(); } } internal static class LoadingDiagnostics { internal static int TotalPrefixSkips; internal static int TotalPrefixAllows; internal static int TotalUpdateNREs; internal static int TotalEmitNREs; internal static int TotalEmitNREsPropagated; internal static int TotalSuppressCalls; internal static int SpawnCallCount; private static int _lastDumpFrame = -1; private const int DumpIntervalFrames = 300; private static bool _sceneHookInstalled; internal static void EnsureSceneHook() { if (!_sceneHookInstalled) { _sceneHookInstalled = true; SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneUnloaded += OnSceneUnloaded; if (Plugin.IsDebug) { Plugin.LogDebug("[LoadingDiag] Scene hooks installed"); } } } private unsafe static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (Plugin.DebugMode != null && Plugin.DebugMode.Value) { Plugin.LogDebug("[LoadingDiag] === SCENE LOADED: " + ((Scene)(ref scene)).name + " mode=" + ((object)(*(LoadSceneMode*)(&mode))/*cast due to .constrained prefix*/).ToString() + " frame=" + Time.frameCount + " ==="); DumpStatus("SceneLoaded"); } ResetCounters(); } private static void OnSceneUnloaded(Scene scene) { if (Plugin.DebugMode != null && Plugin.DebugMode.Value) { Plugin.LogDebug("[LoadingDiag] === SCENE UNLOADED: " + ((Scene)(ref scene)).name + " frame=" + Time.frameCount + " ==="); DumpStatus("SceneUnloaded"); } } internal static void ResetCounters() { TotalPrefixSkips = 0; TotalPrefixAllows = 0; TotalUpdateNREs = 0; TotalEmitNREs = 0; TotalEmitNREsPropagated = 0; TotalSuppressCalls = 0; SpawnCallCount = 0; _lastDumpFrame = Time.frameCount; } internal static void PeriodicDump() { //IL_0087: 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) if (Plugin.DebugMode == null || !Plugin.DebugMode.Value) { return; } int frameCount = Time.frameCount; if (frameCount - _lastDumpFrame >= 300) { _lastDumpFrame = frameCount; if (frameCount % 900 == 0) { string[] obj = new string[6] { "[LoadingDiag] Alive frame=", frameCount.ToString(), " allows=", TotalPrefixAllows.ToString(), " scene=", null }; Scene activeScene = SceneManager.GetActiveScene(); obj[5] = ((Scene)(ref activeScene)).name; Plugin.LogDebug(string.Concat(obj)); } DumpStatus("Periodic"); } } internal static void DumpStatus(string trigger) { //IL_0128: 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) if (Plugin.DebugMode != null && Plugin.DebugMode.Value) { int suppressUntilFrame = PlayerVisualEmitPatch.GetSuppressUntilFrame(); int feedbackLoopCount = PlayerVisualEmitPatch.GetFeedbackLoopCount(); string[] obj = new string[24] { "[LoadingDiag] [", trigger, "] frame=", Time.frameCount.ToString(), " | PrefixSkips=", TotalPrefixSkips.ToString(), " PrefixAllows=", TotalPrefixAllows.ToString(), " | UpdateNREs=", TotalUpdateNREs.ToString(), " EmitNREs=", TotalEmitNREs.ToString(), " EmitPropagated=", TotalEmitNREsPropagated.ToString(), " | SuppressCalls=", TotalSuppressCalls.ToString(), " SuppressUntil=", suppressUntilFrame.ToString(), " FeedbackLoop=", feedbackLoopCount.ToString(), " | Spawns=", SpawnCallCount.ToString(), " | activeScene=", null }; Scene activeScene = SceneManager.GetActiveScene(); obj[23] = ((Scene)(ref activeScene)).name; Plugin.LogDebug(string.Concat(obj)); } } } public static class PlayerVisualUpdatePatch { internal static int _nreLogCount; internal static void ScheduleCleanup() { } } public static class PlayerVisualEmitPatch { private static int _suppressUntilFrame = -1; internal static int GetSuppressUntilFrame() { return _suppressUntilFrame; } internal static int GetFeedbackLoopCount() { return 0; } internal static bool ShouldSkipRenderDisplayWork() { return false; } internal static void SuppressForFrames(int frames = 2) { } } [HarmonyPatch(typeof(ProfileDataManager), "Load_ProfileData")] public static class ProfileLoadPatch { [HarmonyPostfix] public static void ShlongLoading(ProfileDataManager __instance, string _filePath, int _index) { if (Plugin.LoadedProfiles == null || _index < 0 || _index >= Plugin.LoadedProfiles.Length) { return; } Plugin.LoadedProfiles[_index] = null; if (string.IsNullOrWhiteSpace(_filePath)) { return; } string path = _filePath + "_dick"; if (!File.Exists(path)) { return; } try { string text = File.ReadAllText(path); if (!string.IsNullOrWhiteSpace(text)) { ProfileSaveData profileSaveData = JsonUtility.FromJson(text); if (profileSaveData != null) { Plugin.LoadedProfiles[_index] = profileSaveData; } } } catch (Exception ex) { Plugin.LogWarningLimited("profile.load." + _index, "Failed to load shlong profile slot " + _index + ": " + ex.Message); } } } [HarmonyPatch(typeof(ProfileDataManager), "Save_ProfileData")] public static class ProfileSavePatch { private static readonly FieldInfo DataPathField = typeof(ProfileDataManager).GetField("_dataPath", BindingFlags.Instance | BindingFlags.NonPublic); private static bool _dataPathUnavailableLogged; private static bool _profileIndexUnavailableLogged; [HarmonyPostfix] public static void ShlongSaving(ProfileDataManager __instance) { ShlongController shlongController; try { shlongController = ResolveControllerForSave(); } catch (Exception ex) { Plugin.LogWarningLimited("profile.save.resolve", "Failed to resolve the local shlong controller while saving: " + ex.Message, 1); return; } if ((Object)(object)shlongController == (Object)null) { return; } if (shlongController.PresetIndex < 0) { Plugin.LogDebug("[ProfileSave] skipped: invalid preset"); return; } if (Plugin.UserPresets != null) { try { shlongController.ForceSaveSettings(); } catch (Exception ex2) { Plugin.LogWarningLimited("profile.save.character", "Failed to save character shlong settings: " + ex2.Message, 1); } } ProfileSaveData profileSaveData = UserPresetManager.CaptureFromController(shlongController); if (profileSaveData == null) { return; } string profileSavePath = GetProfileSavePath(__instance); if (string.IsNullOrEmpty(profileSavePath)) { return; } try { File.WriteAllText(profileSavePath, JsonUtility.ToJson((object)profileSaveData, true)); } catch (Exception ex3) { Plugin.LogWarningLimited("profile.save.sidecar", "Failed to save the legacy shlong profile sidecar: " + ex3.Message, 1); } } private static ShlongController ResolveControllerForSave() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 if ((Object)(object)Player._mainPlayer == (Object)null) { if ((Object)(object)MainMenuManager._current == (Object)null || (int)MainMenuManager._current._mainMenuCondition != 2) { return null; } return Object.FindObjectOfType(false); } if (Player._mainPlayer._bufferingStatus) { return null; } ShlongController shlongController = ShlongController.ResolveLocalAuthoritative(); if ((Object)(object)shlongController == (Object)null) { Plugin.LogDebug("[ProfileSave] skipped: no local authoritative controller"); } return shlongController; } private static string GetProfileSavePath(ProfileDataManager pdm) { if ((Object)(object)pdm == (Object)null) { return null; } if (DataPathField == null) { LogDataPathUnavailableOnce("ProfileDataManager._dataPath was not found; legacy shlong sidecar saving is disabled."); return null; } string text; try { text = DataPathField.GetValue(pdm) as string; } catch (Exception ex) { LogDataPathUnavailableOnce("ProfileDataManager._dataPath could not be read; legacy shlong sidecar saving is disabled. " + ex.GetType().Name + ": " + ex.Message); return null; } if (string.IsNullOrWhiteSpace(text)) { LogDataPathUnavailableOnce("ProfileDataManager._dataPath was empty; legacy shlong sidecar saving is disabled."); return null; } int selectedFileIndex; try { selectedFileIndex = pdm.SelectedFileIndex; } catch (Exception ex2) { if (!_profileIndexUnavailableLogged) { _profileIndexUnavailableLogged = true; Plugin.LogWarningLimited("profile.save.index_unavailable", "Profile slot index could not be read; legacy shlong sidecar saving is disabled. " + ex2.GetType().Name + ": " + ex2.Message, 1); } return null; } if (selectedFileIndex < 0) { return null; } return Path.Combine(text, $"atl_characterProfile_{selectedFileIndex}_dick"); } private static void LogDataPathUnavailableOnce(string message) { if (!_dataPathUnavailableLogged) { _dataPathUnavailableLogged = true; Plugin.LogWarningLimited("profile.save.data_path_unavailable", message, 1); } } } public static class RaceModelPatch { private class CharacterPreviewState { internal int PresetIndex; internal ProfileSaveData Profile; internal Dictionary PerPresetSettings; internal int CharacterSelectPreviewMode; } private static Hook _awakeHook; private static readonly List _pendingAttachments = new List(); internal static int LoadingAttachBuffered; private static bool _loggedProfileWarning; internal static int PendingAttachmentCount => _pendingAttachments.Count; public static void Install() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown MethodInfo method = typeof(PlayerRaceModel).GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { _awakeHook = new Hook((MethodBase)method, (Delegate)new Action, PlayerRaceModel>(PlayerAwakeHook)); } } private static void PlayerAwakeHook(Action orig, PlayerRaceModel self) { orig(self); AttachToRaceModel(self); } public static void AttachToRaceModel(PlayerRaceModel self) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Invalid comparison between Unknown and I4 if ((Object)(object)((Component)self).GetComponent() != (Object)null) { return; } int num = DetectRaceIndex(self); if (num == -1) { return; } bool flag = IsKnownCharacterPreviewRaceModel(self) && IsCharacterPreviewContext(); bool flag2 = flag || ((Object)self).name.IndexOf("equipDisplay", StringComparison.OrdinalIgnoreCase) >= 0; bool flag3 = (Object)(object)((Component)self).GetComponentInParent() != (Object)null || ((Object)self).name.Contains("(Clone)"); if (!flag && !flag2 && !flag3) { if (Plugin.IsDebug) { Plugin.LogDebug("Skipping template model: " + ((Object)self).name); } return; } if (!flag2 && (Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 0) { LoadingAttachBuffered++; LifecycleDiagnostics.OnLoadingAttachBuffered(); if (!_pendingAttachments.Contains(self)) { _pendingAttachments.Add(self); } return; } LifecycleDiagnostics.OnAttach(flag2, flag3); if (Plugin.IsDebug) { Plugin.LogDebug("AttachToRaceModel: race=" + num + " name=" + ((Object)self).name + " transition=" + ShlongController.TransitionCount + " frame=" + Time.frameCount + " stage=" + (flag2 ? "immediate" : "deferred")); } ShlongController shlongController = ((Component)self).gameObject.AddComponent(); shlongController.RaceIndex = num; if (flag || flag2) { shlongController.InitializeOwnershipFromHierarchy(); CharacterPreviewState characterPreviewState = LoadCurrentCharacterPreviewState(num); shlongController.CharacterSelectPreviewMode = characterPreviewState.CharacterSelectPreviewMode; if (characterPreviewState.PerPresetSettings != null && characterPreviewState.PerPresetSettings.Count > 0) { shlongController.RememberPresetSettings(characterPreviewState.PerPresetSettings); } shlongController.Spawn(characterPreviewState.PresetIndex, resetNetworkDelta: false, saveBeforeSwitch: false); if (characterPreviewState.Profile != null) { shlongController.ApplyLoadedProfile(characterPreviewState.Profile, sync: false); } if ((Object)(object)shlongController.SizeBone != (Object)null) { if (Plugin.IsDebug) { Plugin.LogDebug("Spawned on " + ((Object)self).name + " preset=" + characterPreviewState.PresetIndex + " profile=" + (characterPreviewState.Profile != null)); } } else { Plugin.LogWarningLimited("race.spawn_failed", "SpawnShlong failed — AssetBundle may be missing."); } } else { shlongController.QueueInitialSpawn(num); if (Plugin.IsDebug) { Plugin.LogDebug("[Fix72] Deferred spawn for clone: " + ((Object)self).name); } } } internal static int FlushPendingAttachments(int maxPerFrame = 0) { if (_pendingAttachments.Count == 0) { return 0; } int count = _pendingAttachments.Count; int count2 = ((maxPerFrame <= 0) ? count : Math.Min(count, maxPerFrame)); List range = _pendingAttachments.GetRange(0, count2); _pendingAttachments.RemoveRange(0, count2); int num = 0; foreach (PlayerRaceModel item in range) { if (!((Object)(object)item == (Object)null)) { AttachToRaceModel(item); num++; } } int count3 = _pendingAttachments.Count; if (Plugin.IsDebug) { Plugin.LogDebug("[Fix119] FlushPending: batch=" + num + " remaining=" + count3 + " frame=" + Time.frameCount); } return count3; } private static CharacterCreationManager GetCharacterCreationManager() { try { if ((Object)(object)MainMenuManager._current != (Object)null) { CharacterCreationManager component = ((Component)MainMenuManager._current).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } } } catch { } try { return Object.FindObjectOfType(); } catch { } return null; } internal static bool IsKnownCharacterPreviewRaceModel(PlayerRaceModel model) { if ((Object)(object)model == (Object)null) { return false; } try { if (((Object)model).name.IndexOf("equipDisplay", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } catch { } try { CharacterCreationManager characterCreationManager = GetCharacterCreationManager(); if ((Object)(object)characterCreationManager != (Object)null && characterCreationManager._raceDisplayModels != null) { for (int i = 0; i < characterCreationManager._raceDisplayModels.Length; i++) { if ((Object)(object)characterCreationManager._raceDisplayModels[i] == (Object)(object)model) { return true; } } } } catch { } return false; } private static int DetectRaceIndex(PlayerRaceModel model) { if ((Object)(object)model == (Object)null) { return -1; } int num = Defaults.DetectRace(((Object)model).name); if (num >= 0) { return num; } try { if ((Object)(object)model._scriptablePlayerRace != (Object)null) { int num2 = Defaults.DetectRace(model._scriptablePlayerRace._raceName); if (num2 >= 0) { return num2; } } } catch { } try { CharacterCreationManager characterCreationManager = GetCharacterCreationManager(); if ((Object)(object)characterCreationManager != (Object)null && characterCreationManager._raceDisplayModels != null) { for (int i = 0; i < characterCreationManager._raceDisplayModels.Length; i++) { if ((Object)(object)characterCreationManager._raceDisplayModels[i] == (Object)(object)model) { return i; } } } } catch { } return -1; } private static void EnsureCharacterPreviewControllers() { if (!IsCharacterPreviewContext()) { return; } try { CharacterCreationManager characterCreationManager = GetCharacterCreationManager(); if ((Object)(object)characterCreationManager == (Object)null || characterCreationManager._raceDisplayModels == null) { return; } for (int i = 0; i < characterCreationManager._raceDisplayModels.Length; i++) { PlayerRaceModel val = characterCreationManager._raceDisplayModels[i]; if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !((Object)(object)((Component)val).GetComponent() != (Object)null)) { AttachToRaceModel(val); } } } catch (Exception ex) { Plugin.LogWarningLimited("race.equipdisplay_attach_refresh", "Failed to attach character preview shlong controller: " + ex.Message); } } internal static bool IsCharacterPreviewContext() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 if (Plugin.CharMenuON) { return true; } try { if ((Object)(object)MainMenuManager._current != (Object)null) { MainMenuCondition mainMenuCondition = MainMenuManager._current._mainMenuCondition; return (int)mainMenuCondition == 1 || (int)mainMenuCondition == 2; } } catch { } return false; } private static CharacterPreviewState LoadCurrentCharacterPreviewState(int fallbackPreset) { CharacterPreviewState characterPreviewState = new CharacterPreviewState { PresetIndex = fallbackPreset, Profile = null, PerPresetSettings = null, CharacterSelectPreviewMode = 0 }; try { int currentProfileIndex = GetCurrentProfileIndex(); if (Plugin.UserPresets != null && currentProfileIndex >= 0) { characterPreviewState.CharacterSelectPreviewMode = Plugin.UserPresets.LoadCharacterSelectPreviewMode(currentProfileIndex); CharacterSettingsEntry characterSettingsEntry = Plugin.UserPresets.LoadCharacterSettings(currentProfileIndex); if (characterSettingsEntry != null) { characterPreviewState.Profile = characterSettingsEntry.LastUsed; characterPreviewState.PerPresetSettings = Plugin.UserPresets.ExtractPerPresetSettings(characterSettingsEntry); } } if (characterPreviewState.Profile == null && currentProfileIndex >= 0 && Plugin.LoadedProfiles != null && currentProfileIndex < Plugin.LoadedProfiles.Length) { characterPreviewState.Profile = Plugin.LoadedProfiles[currentProfileIndex]; } if (characterPreviewState.Profile != null) { characterPreviewState.PresetIndex = characterPreviewState.Profile.DickNumber; } } catch (Exception ex) { Plugin.LogWarningLimited("race.equipdisplay_character_load", "Failed to load character shlong preview settings: " + ex.Message); } return characterPreviewState; } internal static void RefreshCharacterPreviewControllers() { if (!IsCharacterPreviewContext()) { return; } EnsureCharacterPreviewControllers(); try { ShlongController[] array = Object.FindObjectsOfType(); foreach (ShlongController shlongController in array) { if (!((Object)(object)shlongController == (Object)null) && shlongController.IsLocal && shlongController.IsCharacterPreviewController()) { int num = ((shlongController.PresetIndex >= 0) ? shlongController.PresetIndex : shlongController.RaceIndex); if (num < 0) { num = Defaults.DetectRace(((Object)((Component)shlongController).gameObject).name); } if (num < 0) { num = 0; } CharacterPreviewState characterPreviewState = LoadCurrentCharacterPreviewState(num); shlongController.CharacterSelectPreviewMode = characterPreviewState.CharacterSelectPreviewMode; if (characterPreviewState.PerPresetSettings != null && characterPreviewState.PerPresetSettings.Count > 0) { shlongController.RememberPresetSettings(characterPreviewState.PerPresetSettings); } if (!shlongController.HasRuntimeRig || shlongController.PresetIndex != characterPreviewState.PresetIndex) { shlongController.Spawn(characterPreviewState.PresetIndex, resetNetworkDelta: false, saveBeforeSwitch: false); } if (characterPreviewState.Profile != null) { shlongController.ApplyLoadedProfile(characterPreviewState.Profile, sync: false); } else { shlongController.RefreshTransform(); } if (Plugin.IsDebug) { Plugin.LogDebug("[CharacterPreviewRefresh] controller=" + ((Object)((Component)shlongController).gameObject).name + " preset=" + characterPreviewState.PresetIndex + " profile=" + (characterPreviewState.Profile != null) + " previewMode=" + UserPresetManager.FormatCharacterSelectPreviewMode(characterPreviewState.CharacterSelectPreviewMode) + " memory=" + ((characterPreviewState.PerPresetSettings != null) ? characterPreviewState.PerPresetSettings.Count : 0) + " frame=" + Time.frameCount); } } } } catch (Exception ex) { Plugin.LogWarningLimited("race.equipdisplay_refresh", "Failed to refresh character shlong preview settings: " + ex.Message); } } internal static int GetCurrentProfileIndex() { if ((Object)(object)ProfileDataManager._current == (Object)null) { return -1; } try { return ProfileDataManager._current.SelectedFileIndex; } catch (Exception ex) { if (!_loggedProfileWarning) { Plugin.LogWarningLimited("race.profile_index", "Profile index unavailable: " + ex.Message); _loggedProfileWarning = true; } return -1; } } } [HarmonyPatch(typeof(ProfileDataManager), "Set_FileIndex")] public static class ProfileDataManagerSetFileIndexPatch { [HarmonyPostfix] public static void Postfix() { RaceModelPatch.RefreshCharacterPreviewControllers(); } } [HarmonyPatch(typeof(CharacterSelectManager), "Apply_CharacterSelectDisplay")] public static class CharacterSelectDisplayPatch { [HarmonyPostfix] public static void Postfix() { RaceModelPatch.RefreshCharacterPreviewControllers(); } } [HarmonyPatch(typeof(CharacterCreationManager), "SelectRace")] public static class CharacterCreationSelectRacePatch { [HarmonyPostfix] public static void Postfix() { RaceModelPatch.RefreshCharacterPreviewControllers(); } } internal static class TransitionWatchdog { private static Timer _timer; private static volatile int _mainThreadFrame; private static int _lastCheckedFrame; private static int _stallCount; private const int WatchdogInitialDelayMs = 15000; private const int WatchdogCheckIntervalMs = 20000; private const double WatchdogCheckIntervalSeconds = 20.0; private const int MainThreadStallWarningMaxReports = 1; private const int LoadingDelayWarningMaxReports = 1; private const double LoadingDelayWarningThresholdSeconds = 30.0; private static volatile bool _isInLoading; private static long _loadingEntryTicks; private static int _loadingReportCount; private static volatile bool _isInMultiplayerSession; private static GameCondition _lastLocalCondition = (GameCondition)1; private static string _pendingConditionLog; private static bool _teardownPending; private static bool _recoveryFlushPending; internal static void Start() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) _mainThreadFrame = 0; _lastCheckedFrame = 0; _stallCount = 0; _lastLocalCondition = (GameCondition)1; _teardownPending = false; _recoveryFlushPending = false; _isInLoading = false; _loadingEntryTicks = 0L; _loadingReportCount = 0; _isInMultiplayerSession = false; _timer = new Timer(Check, null, 15000, 20000); } internal unsafe static void Tick() { //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0208: 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_0047: 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_004a: Invalid comparison between Unknown and I4 //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Invalid comparison between Unknown and I4 //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Invalid comparison between Unknown and I4 //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) _mainThreadFrame = Time.frameCount; Player mainPlayer = Player._mainPlayer; _isInMultiplayerSession = (Object)(object)mainPlayer != (Object)null && (Object)(object)SteamLobby._current != (Object)null; if ((Object)(object)mainPlayer == (Object)null) { return; } GameCondition currentGameCondition = mainPlayer._currentGameCondition; if ((int)currentGameCondition == 0) { if (currentGameCondition == _lastLocalCondition) { return; } _pendingConditionLog = "[TransDiag] GameCondition: " + ((object)Unsafe.As(ref _lastLocalCondition)/*cast due to .constrained prefix*/).ToString() + " -> " + ((object)(*(GameCondition*)(¤tGameCondition))/*cast due to .constrained prefix*/).ToString() + " frame=" + Time.frameCount; ShlongController.TransitionCount++; _teardownPending = true; _loadingEntryTicks = DateTime.UtcNow.Ticks; _loadingReportCount = 0; _isInLoading = true; try { ShlongController shlongController = ShlongController.ResolveLocalAuthoritative(); if ((Object)(object)shlongController != (Object)null && shlongController.IsLocal) { shlongController.ForceSaveSettings(); if (Plugin.IsDebug) { string[] obj = new string[10] { "[TransitionSave] controller=", ((Object)((Component)shlongController).gameObject).name, " preset=", shlongController.PresetIndex.ToString(), " color=", null, null, null, null, null }; Color colorTint = shlongController.ColorTint; obj[5] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[6] = " ballColor="; colorTint = shlongController.BallColorTint; obj[7] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[8] = " frame="; obj[9] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } } catch (Exception ex) { Plugin.LogWarningLimited("transition.save", "[TransitionSave] " + ex.Message); } ShlongController.QuickDeactivateAllRigs(); CosmeticDisplayManager.OnLoadingDetected(); _lastLocalCondition = currentGameCondition; return; } if ((int)_lastLocalCondition == 0 && (int)currentGameCondition > 0) { _isInLoading = false; if (_pendingConditionLog != null) { if (Plugin.IsDebug) { Plugin.LogDebug(_pendingConditionLog); } _pendingConditionLog = null; } if (Plugin.IsDebug) { Plugin.LogDebug("[TransDiag] GameCondition: " + ((object)Unsafe.As(ref _lastLocalCondition)/*cast due to .constrained prefix*/).ToString() + " -> " + ((object)(*(GameCondition*)(¤tGameCondition))/*cast due to .constrained prefix*/).ToString() + " frame=" + Time.frameCount); } if (_teardownPending) { _teardownPending = false; ShlongController.BeginTransitionTeardownLocal(); } CosmeticDisplayManager.OnRecovered(); ShlongController.FlushPendingCensusLog(); if ((int)currentGameCondition == 1 && RaceModelPatch.PendingAttachmentCount > 0) { int pendingAttachmentCount = RaceModelPatch.PendingAttachmentCount; if (Plugin.IsDebug) { Plugin.LogDebug("[Fix121] Recovery burst flush: pending=" + pendingAttachmentCount + " frame=" + Time.frameCount); } RaceModelPatch.FlushPendingAttachments(pendingAttachmentCount); if (RaceModelPatch.PendingAttachmentCount > 0) { _recoveryFlushPending = true; } } _lastLocalCondition = currentGameCondition; return; } if (_recoveryFlushPending && RaceModelPatch.FlushPendingAttachments(4) == 0) { _recoveryFlushPending = false; if (Plugin.IsDebug) { Plugin.LogDebug("[Fix119] Recovery complete: frame=" + Time.frameCount); } } ShlongController.FlushPendingCensusLog(); if (_pendingConditionLog != null) { if (Plugin.IsDebug) { Plugin.LogDebug(_pendingConditionLog); } _pendingConditionLog = null; } if (currentGameCondition != _lastLocalCondition) { if (Plugin.IsDebug) { Plugin.LogDebug("[TransDiag] GameCondition: " + ((object)Unsafe.As(ref _lastLocalCondition)/*cast due to .constrained prefix*/).ToString() + " -> " + ((object)(*(GameCondition*)(¤tGameCondition))/*cast due to .constrained prefix*/).ToString() + " frame=" + Time.frameCount); } _lastLocalCondition = currentGameCondition; } } private static void Check(object _) { int mainThreadFrame = _mainThreadFrame; if (!_isInMultiplayerSession) { _stallCount = 0; _lastCheckedFrame = mainThreadFrame; return; } if (mainThreadFrame == _lastCheckedFrame && mainThreadFrame > 0) { _stallCount++; Plugin.LogWarningLimited("watchdog.main_thread_pause", "[WATCHDOG] Map load paused for a while. AtlyssShlongs only noticed it, this does not mean shlongs caused it. frame=" + mainThreadFrame + " pauseAtLeast=" + ((double)_stallCount * 20.0).ToString("F0") + "s", 1); } else { if (_stallCount > 0 && Plugin.IsDebug) { Plugin.LogDebug("[WATCHDOG] Main thread recovered after " + ((double)_stallCount * 20.0).ToString("F0") + "s pause at frame=" + _lastCheckedFrame); } _stallCount = 0; } _lastCheckedFrame = mainThreadFrame; if (_isInLoading && _loadingEntryTicks > 0) { double num = (double)(DateTime.UtcNow.Ticks - _loadingEntryTicks) / 10000000.0; if (num > 30.0 && _loadingReportCount < 1) { _loadingReportCount++; Plugin.LogWarningLimited("watchdog.long_loading", "[WATCHDOG] Still loading after " + num.ToString("F1") + "s. AtlyssShlongs is paused during loading; this is only a heads up, not a cause. frame=" + mainThreadFrame + " report=" + _loadingReportCount + "/" + 1, 1); } } } } } namespace AtlyssShlongs.Network { public class NetworkManager { private readonly Dictionary _controllers; private readonly ManualLogSource _log; private ShlongSyncPacket _lastSent; private readonly object _pendingLock = new object(); private readonly Dictionary _pendingPackets = new Dictionary(); public NetworkManager(Dictionary controllers, ManualLogSource log) { _controllers = controllers; _log = log; } public bool RegisterListener() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return CodeTalkerNetwork.RegisterListener(new PacketListener(OnReceived)); } public void ResetDelta() { _lastSent = null; } public void SendFullSync(ShlongController sc) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Invalid comparison between Unknown and I4 if (!CanSendAuthoritativeSync(sc) || sc.PresetIndex < 0 || (Object)(object)SteamLobby._current == (Object)null || ((Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition != 1)) { return; } ShlongSyncPacket shlongSyncPacket = new ShlongSyncPacket { ChangedFields = 16383, DickOffsetX = sc.PositionOffset.x, DickOffsetY = sc.PositionOffset.y, BallsSizeOffset = sc.BallsSizeOffset, CurrentDick = sc.PresetIndex, ArousalTarget = sc.ArousalTarget, FutaToggle = sc.FutaToggle, ClothingOverride = sc.ClothingOverride, BaseRotationX = sc.BaseRotation.x, BaseRotationY = sc.BaseRotation.y, BaseRotationZ = sc.BaseRotation.z, ErectAngleOffset = sc.ErectAngleOffset, DickSizeOffset = sc.ScaleOffset.z, ScaleX = sc.ScaleOffset.x, ScaleY = sc.ScaleOffset.y, ScaleZ = sc.ScaleOffset.z, ColorR = sc.ColorTint.r, ColorG = sc.ColorTint.g, ColorB = sc.ColorTint.b, ColorMode = sc.ColorMode, MatchBody = sc.MatchBody, TextureSourceMode = ShlongController.NormalizeTextureSourceMode(sc.TextureSourceMode), MatchBodyWire = ShlongSyncPacket.EncodeBoolWire(sc.MatchBody), ColorRWire = ShlongSyncPacket.EncodeColorWire(sc.ColorTint.r), ColorGWire = ShlongSyncPacket.EncodeColorWire(sc.ColorTint.g), ColorBWire = ShlongSyncPacket.EncodeColorWire(sc.ColorTint.b), BallColorR = sc.BallColorTint.r, BallColorG = sc.BallColorTint.g, BallColorB = sc.BallColorTint.b, BallColorMode = sc.BallColorMode, BallMatchBody = sc.BallMatchBody, BallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(sc.BallTextureSourceMode), BallMatchBodyWire = ShlongSyncPacket.EncodeBoolWire(sc.BallMatchBody), BallColorRWire = ShlongSyncPacket.EncodeColorWire(sc.BallColorTint.r), BallColorGWire = ShlongSyncPacket.EncodeColorWire(sc.BallColorTint.g), BallColorBWire = ShlongSyncPacket.EncodeColorWire(sc.BallColorTint.b), HideToggle = sc.HideToggle, BulgeAmount = sc.BulgeAmount, BulgePosition = sc.BulgePosition, BulgeWidth = sc.BulgeWidth, BulgeSharpness = sc.BulgeSharpness, BulgeLerpSpeed = sc.BulgeLerpSpeed }; if (Plugin.IsDebug) { Plugin.LogDebug("[NetColorSend] full name=" + ((Object)((Component)sc).gameObject).name + " mode=" + sc.ColorMode + " match=" + sc.MatchBody + " matchWire=" + shlongSyncPacket.MatchBodyWire + " colorFloat=(" + sc.ColorTint.r.ToString("F3") + "," + sc.ColorTint.g.ToString("F3") + "," + sc.ColorTint.b.ToString("F3") + ") colorWire=(" + shlongSyncPacket.ColorRWire + "," + shlongSyncPacket.ColorGWire + "," + shlongSyncPacket.ColorBWire + ") ballMatch=" + sc.BallMatchBody + " ballMatchWire=" + shlongSyncPacket.BallMatchBodyWire + " ballColorFloat=(" + sc.BallColorTint.r.ToString("F3") + "," + sc.BallColorTint.g.ToString("F3") + "," + sc.BallColorTint.b.ToString("F3") + ") ballColorWire=(" + shlongSyncPacket.BallColorRWire + "," + shlongSyncPacket.BallColorGWire + "," + shlongSyncPacket.BallColorBWire + ") frame=" + Time.frameCount); } try { CodeTalkerNetwork.SendNetworkPacket((PacketBase)(object)shlongSyncPacket); } catch (Exception ex) { Plugin.LogWarningLimited("net.send_full_sync", "SendFullSync failed: " + ex.GetType().Name + " - " + ex.Message); } } public void SendSync(ShlongController sc, SyncField forceFields = SyncField.None) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Invalid comparison between Unknown and I4 if ((Object)(object)sc == (Object)null) { return; } if (!CanSendAuthoritativeSync(sc)) { if (Plugin.IsDebug && (Object)(object)sc != (Object)null) { Plugin.LogDebug("[NetSendBlockedNonAuthoritative] name=" + ((Object)((Component)sc).gameObject).name + " isLocal=" + sc.IsLocal + " hasPlayerParent=" + sc.HasPlayerParent + " preset=" + sc.PresetIndex + " frame=" + Time.frameCount); } } else { if (sc.PresetIndex < 0 || (Object)(object)SteamLobby._current == (Object)null || ((Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition != 1)) { return; } ShlongSyncPacket shlongSyncPacket = new ShlongSyncPacket { DickOffsetX = sc.PositionOffset.x, DickOffsetY = sc.PositionOffset.y, BallsSizeOffset = sc.BallsSizeOffset, CurrentDick = sc.PresetIndex, ArousalTarget = sc.ArousalTarget, FutaToggle = sc.FutaToggle, ClothingOverride = sc.ClothingOverride, BaseRotationX = sc.BaseRotation.x, BaseRotationY = sc.BaseRotation.y, BaseRotationZ = sc.BaseRotation.z, ErectAngleOffset = sc.ErectAngleOffset, DickSizeOffset = sc.ScaleOffset.z, ScaleX = sc.ScaleOffset.x, ScaleY = sc.ScaleOffset.y, ScaleZ = sc.ScaleOffset.z, ColorR = sc.ColorTint.r, ColorG = sc.ColorTint.g, ColorB = sc.ColorTint.b, ColorMode = sc.ColorMode, MatchBody = sc.MatchBody, TextureSourceMode = ShlongController.NormalizeTextureSourceMode(sc.TextureSourceMode), MatchBodyWire = ShlongSyncPacket.EncodeBoolWire(sc.MatchBody), ColorRWire = ShlongSyncPacket.EncodeColorWire(sc.ColorTint.r), ColorGWire = ShlongSyncPacket.EncodeColorWire(sc.ColorTint.g), ColorBWire = ShlongSyncPacket.EncodeColorWire(sc.ColorTint.b), BallColorR = sc.BallColorTint.r, BallColorG = sc.BallColorTint.g, BallColorB = sc.BallColorTint.b, BallColorMode = sc.BallColorMode, BallMatchBody = sc.BallMatchBody, BallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(sc.BallTextureSourceMode), BallMatchBodyWire = ShlongSyncPacket.EncodeBoolWire(sc.BallMatchBody), BallColorRWire = ShlongSyncPacket.EncodeColorWire(sc.BallColorTint.r), BallColorGWire = ShlongSyncPacket.EncodeColorWire(sc.BallColorTint.g), BallColorBWire = ShlongSyncPacket.EncodeColorWire(sc.BallColorTint.b), HideToggle = sc.HideToggle, BulgeAmount = sc.BulgeAmount, BulgePosition = sc.BulgePosition, BulgeWidth = sc.BulgeWidth, BulgeSharpness = sc.BulgeSharpness, BulgeLerpSpeed = sc.BulgeLerpSpeed }; SyncField syncField = ComputeDelta(shlongSyncPacket, _lastSent); syncField |= forceFields; if (syncField != SyncField.None) { shlongSyncPacket.ChangedFields = (ushort)syncField; _lastSent = shlongSyncPacket; if (Plugin.IsDebug) { Plugin.LogDebug("[SendSync] name=" + ((Object)((Component)sc).gameObject).name + " isLocal=" + sc.IsLocal + " preset=" + sc.PresetIndex + " mask=" + syncField.ToString() + " rot=(" + sc.BaseRotation.x.ToString("F2") + "," + sc.BaseRotation.y.ToString("F2") + "," + sc.BaseRotation.z.ToString("F2") + ") erectAngle=" + sc.ErectAngleOffset.ToString("F2") + " scale=(" + sc.ScaleOffset.x.ToString("F2") + "," + sc.ScaleOffset.y.ToString("F2") + "," + sc.ScaleOffset.z.ToString("F2") + ") dickSizeOffset=" + sc.ScaleOffset.z.ToString("F2") + " frame=" + Time.frameCount); } if (Plugin.IsDebug && ((syncField & SyncField.Color) != SyncField.None || (syncField & SyncField.BallColor) != SyncField.None)) { Plugin.LogDebug("[NetColorSend] delta name=" + ((Object)((Component)sc).gameObject).name + " mode=" + sc.ColorMode + " match=" + sc.MatchBody + " matchWire=" + shlongSyncPacket.MatchBodyWire + " colorFloat=(" + sc.ColorTint.r.ToString("F3") + "," + sc.ColorTint.g.ToString("F3") + "," + sc.ColorTint.b.ToString("F3") + ") colorWire=(" + shlongSyncPacket.ColorRWire + "," + shlongSyncPacket.ColorGWire + "," + shlongSyncPacket.ColorBWire + ") ballMatch=" + sc.BallMatchBody + " ballMatchWire=" + shlongSyncPacket.BallMatchBodyWire + " ballColorFloat=(" + sc.BallColorTint.r.ToString("F3") + "," + sc.BallColorTint.g.ToString("F3") + "," + sc.BallColorTint.b.ToString("F3") + ") ballColorWire=(" + shlongSyncPacket.BallColorRWire + "," + shlongSyncPacket.BallColorGWire + "," + shlongSyncPacket.BallColorBWire + ") frame=" + Time.frameCount); } try { CodeTalkerNetwork.SendNetworkPacket((PacketBase)(object)shlongSyncPacket); } catch (Exception ex) { Plugin.LogWarningLimited("net.send_sync", "SendSync failed: " + ex.GetType().Name + " - " + ex.Message); } } } } private static SyncField ComputeDelta(ShlongSyncPacket cur, ShlongSyncPacket prev) { if (prev == null) { return SyncField.All; } SyncField syncField = SyncField.None; if (Math.Abs(cur.DickOffsetX - prev.DickOffsetX) > 1E-05f || Math.Abs(cur.DickOffsetY - prev.DickOffsetY) > 1E-05f) { syncField |= SyncField.Position; } if (Math.Abs(cur.ScaleX - prev.ScaleX) > 1E-05f || Math.Abs(cur.ScaleY - prev.ScaleY) > 1E-05f || Math.Abs(cur.ScaleZ - prev.ScaleZ) > 1E-05f) { syncField |= SyncField.Scale; } if (Math.Abs(cur.BallsSizeOffset - prev.BallsSizeOffset) > 1E-05f) { syncField |= SyncField.BallsSize; } if (cur.CurrentDick != prev.CurrentDick) { syncField |= SyncField.Preset; } if (Math.Abs(cur.ArousalTarget - prev.ArousalTarget) > 1E-05f) { syncField |= SyncField.Arousal; } if (cur.FutaToggle != prev.FutaToggle) { syncField |= SyncField.Futa; } if (cur.ClothingOverride != prev.ClothingOverride) { syncField |= SyncField.Clothing; } if (Math.Abs(cur.BaseRotationX - prev.BaseRotationX) > 0.01f || Math.Abs(cur.BaseRotationY - prev.BaseRotationY) > 0.01f || Math.Abs(cur.BaseRotationZ - prev.BaseRotationZ) > 0.01f) { syncField |= SyncField.Rotation; } if (Math.Abs(cur.ErectAngleOffset - prev.ErectAngleOffset) > 0.01f) { syncField |= SyncField.ErectAngle; } if (Math.Abs(cur.ColorR - prev.ColorR) > 0.001f || Math.Abs(cur.ColorG - prev.ColorG) > 0.001f || Math.Abs(cur.ColorB - prev.ColorB) > 0.001f || cur.ColorMode != prev.ColorMode || cur.MatchBody != prev.MatchBody || cur.TextureSourceMode != prev.TextureSourceMode) { syncField |= SyncField.Color; } if (Math.Abs(cur.BallColorR - prev.BallColorR) > 0.001f || Math.Abs(cur.BallColorG - prev.BallColorG) > 0.001f || Math.Abs(cur.BallColorB - prev.BallColorB) > 0.001f || cur.BallColorMode != prev.BallColorMode || cur.BallMatchBody != prev.BallMatchBody || cur.BallTextureSourceMode != prev.BallTextureSourceMode) { syncField |= SyncField.BallColor; } if (cur.HideToggle != prev.HideToggle) { syncField |= SyncField.Hide; } if (Math.Abs(cur.BulgeAmount - prev.BulgeAmount) > 1E-05f || Math.Abs(cur.BulgePosition - prev.BulgePosition) > 1E-05f || Math.Abs(cur.BulgeWidth - prev.BulgeWidth) > 1E-05f || Math.Abs(cur.BulgeSharpness - prev.BulgeSharpness) > 1E-05f || Math.Abs(cur.BulgeLerpSpeed - prev.BulgeLerpSpeed) > 1E-05f) { syncField |= SyncField.Bulge; } return syncField; } private static bool CanSendAuthoritativeSync(ShlongController sc) { if ((Object)(object)sc == (Object)null) { return false; } if (!sc.IsLocal) { return false; } if (!sc.HasPlayerParent) { return false; } if ((Object)(object)((Component)sc).gameObject != (Object)null && ((Object)((Component)sc).gameObject).name.Contains("equipDisplay")) { return false; } if (sc == ShlongController.OurDick) { return true; } try { if ((Object)(object)Player._mainPlayer != (Object)null) { ShlongController componentInChildren = ((Component)Player._mainPlayer).GetComponentInChildren(true); if (sc == componentInChildren) { return true; } } } catch { } return false; } private void OnReceived(PacketHeader header, PacketBase raw) { if (!(raw is ShlongSyncPacket shlongSyncPacket)) { return; } string text = header.SenderID.ToString(); string text2 = Plugin.LocalSteamId; if (string.IsNullOrEmpty(text2) && (Object)(object)Player._mainPlayer != (Object)null && !string.IsNullOrEmpty(Player._mainPlayer.Network_steamID)) { text2 = Player._mainPlayer.Network_steamID; } if (!string.IsNullOrEmpty(text2) && text == text2) { return; } lock (_pendingLock) { if (_pendingPackets.TryGetValue(text, out var value)) { MergePacket(value, shlongSyncPacket); } else { _pendingPackets[text] = ClonePacket(shlongSyncPacket); } } } public void ProcessPending() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 if ((Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition != 1) { return; } Dictionary dictionary; lock (_pendingLock) { if (_pendingPackets.Count == 0) { return; } dictionary = new Dictionary(_pendingPackets); _pendingPackets.Clear(); } foreach (KeyValuePair item in dictionary) { if (!ApplyPacket(item.Key, item.Value)) { lock (_pendingLock) { _pendingPackets[item.Key] = item.Value; } } } } private unsafe bool ApplyPacket(string senderId, ShlongSyncPacket packet) { //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Unknown result type (might be due to invalid IL or missing references) //IL_0528: Unknown result type (might be due to invalid IL or missing references) //IL_0545: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_0871: Unknown result type (might be due to invalid IL or missing references) //IL_0876: Unknown result type (might be due to invalid IL or missing references) //IL_0b86: Unknown result type (might be due to invalid IL or missing references) //IL_0b8b: Unknown result type (might be due to invalid IL or missing references) //IL_0d69: Unknown result type (might be due to invalid IL or missing references) //IL_0d6e: Unknown result type (might be due to invalid IL or missing references) if (!_controllers.TryGetValue(senderId, out var value) || (Object)(object)value == (Object)null) { _controllers.Remove(senderId); return false; } if (value.IsLocal) { return true; } try { SyncField syncField = (SyncField)packet.ChangedFields; if (syncField == SyncField.None) { syncField = SyncField.All; } bool flag = false; int num = packet.CurrentDick; if (Plugin.Presets != null) { num = Plugin.Presets.ResolvePresetForLocalAssets(num); } if ((syncField & SyncField.Preset) != SyncField.None && value.PresetIndex != num) { bool flag2 = true; if (Plugin.IsDebug) { Plugin.LogDebug("[ApplyPacket] sender=" + senderId + " target=" + ((Object)((Component)value).gameObject).name + " targetIsLocal=" + value.IsLocal + " rawChangedFields=" + packet.ChangedFields + " mask=" + syncField.ToString() + " packetDick=" + packet.CurrentDick + " resolvedDick=" + num + " scPreset=" + value.PresetIndex + " willSpawn=" + flag2); } if (Plugin.IsDebug) { Plugin.LogDebug("[NetApplyPresetSpawn] sender=" + senderId + " spawning preset=" + num + " on " + ((Object)((Component)value).gameObject).name); } value.Spawn(num, resetNetworkDelta: false); flag = true; } else if (Plugin.IsDebug) { Plugin.LogDebug("[ApplyPacket] sender=" + senderId + " target=" + ((Object)((Component)value).gameObject).name + " targetIsLocal=" + value.IsLocal + " rawChangedFields=" + packet.ChangedFields + " mask=" + syncField.ToString() + " packetDick=" + packet.CurrentDick + " resolvedDick=" + num + " scPreset=" + value.PresetIndex + " willSpawn=false"); } if ((syncField & SyncField.Position) != SyncField.None) { value.PositionOffset = new Vector2(packet.DickOffsetX, packet.DickOffsetY); flag = true; } if ((syncField & SyncField.BallsSize) != SyncField.None) { value.BallsSizeOffset = packet.BallsSizeOffset; flag = true; } if ((syncField & SyncField.Arousal) != SyncField.None) { value.ArousalTarget = packet.ArousalTarget; } if ((syncField & SyncField.Futa) != SyncField.None) { value.FutaToggle = packet.FutaToggle; } if ((syncField & SyncField.Clothing) != SyncField.None) { value.ClothingOverride = packet.ClothingOverride; } if ((syncField & SyncField.Rotation) != SyncField.None) { value.BaseRotation = new Vector3(packet.BaseRotationX, packet.BaseRotationY, packet.BaseRotationZ); flag = true; } if ((syncField & SyncField.ErectAngle) != SyncField.None) { value.ErectAngleOffset = packet.ErectAngleOffset; flag = true; } if ((syncField & SyncField.Scale) != SyncField.None) { Vector3 scaleOffset = value.ScaleOffset; if (packet.ChangedFields == 0) { value.ScaleOffset = Vector3.one * packet.DickSizeOffset; } else { value.ScaleOffset = new Vector3(packet.ScaleX, packet.ScaleY, packet.ScaleZ); } flag = true; if (Plugin.IsDebug) { string[] obj = new string[24] { "[NetApplyScale] sender=", senderId, " target=", ((Object)((Component)value).gameObject).name, " rawChangedFields=", packet.ChangedFields.ToString(), " mask=", syncField.ToString(), " pktScale=(", packet.ScaleX.ToString("F3"), ",", packet.ScaleY.ToString("F3"), ",", packet.ScaleZ.ToString("F3"), ") pktDickSizeOffset=", packet.DickSizeOffset.ToString("F3"), " prevScale=", null, null, null, null, null, null, null }; Vector3 val = scaleOffset; obj[17] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[18] = " newScale="; val = value.ScaleOffset; obj[19] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[20] = " visualReady="; obj[21] = value.HasReceivedRemoteVisualState.ToString(); obj[22] = " frame="; obj[23] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } bool flag3 = false; bool flag4 = false; if ((syncField & SyncField.Color) != SyncField.None) { float num2 = (ShlongSyncPacket.HasColorWire(packet.ColorRWire) ? ShlongSyncPacket.DecodeColorWire(packet.ColorRWire) : packet.ColorR); float num3 = (ShlongSyncPacket.HasColorWire(packet.ColorGWire) ? ShlongSyncPacket.DecodeColorWire(packet.ColorGWire) : packet.ColorG); float num4 = (ShlongSyncPacket.HasColorWire(packet.ColorBWire) ? ShlongSyncPacket.DecodeColorWire(packet.ColorBWire) : packet.ColorB); if (Plugin.IsDebug) { Plugin.LogDebug("[NetColorApply] sender=" + senderId + " target=" + ((Object)((Component)value).gameObject).name + " field=Color rawFloat=(" + packet.ColorR.ToString("F3") + "," + packet.ColorG.ToString("F3") + "," + packet.ColorB.ToString("F3") + ") wire=(" + packet.ColorRWire + "," + packet.ColorGWire + "," + packet.ColorBWire + ") decoded=(" + num2.ToString("F3") + "," + num3.ToString("F3") + "," + num4.ToString("F3") + ") mode=" + packet.ColorMode + " matchRaw=" + packet.MatchBody + " matchWire=" + packet.MatchBodyWire + " changedFields=" + packet.ChangedFields + " frame=" + Time.frameCount); } bool matchBody = (ShlongSyncPacket.HasBoolWire(packet.MatchBodyWire) ? ShlongSyncPacket.DecodeBoolWire(packet.MatchBodyWire, packet.MatchBody) : (packet.ChangedFields == 0 || packet.MatchBody)); if (Plugin.IsDebug) { Plugin.LogDebug("[NetColorApply] sender=" + senderId + " matchDecoded=" + matchBody + " frame=" + Time.frameCount); } value.ColorTint = new Color(num2, num3, num4); value.ColorMode = packet.ColorMode; value.MatchBody = matchBody; value.TextureSourceMode = ShlongController.NormalizeTextureSourceMode(packet.TextureSourceMode); value.InvalidateColorMaterialCache(dick: true, balls: false); value.ApplyColorTint(); flag3 = true; } if ((syncField & SyncField.BallColor) != SyncField.None) { float num5 = (ShlongSyncPacket.HasColorWire(packet.BallColorRWire) ? ShlongSyncPacket.DecodeColorWire(packet.BallColorRWire) : packet.BallColorR); float num6 = (ShlongSyncPacket.HasColorWire(packet.BallColorGWire) ? ShlongSyncPacket.DecodeColorWire(packet.BallColorGWire) : packet.BallColorG); float num7 = (ShlongSyncPacket.HasColorWire(packet.BallColorBWire) ? ShlongSyncPacket.DecodeColorWire(packet.BallColorBWire) : packet.BallColorB); if (Plugin.IsDebug) { Plugin.LogDebug("[NetColorApply] sender=" + senderId + " target=" + ((Object)((Component)value).gameObject).name + " field=BallColor rawFloat=(" + packet.BallColorR.ToString("F3") + "," + packet.BallColorG.ToString("F3") + "," + packet.BallColorB.ToString("F3") + ") wire=(" + packet.BallColorRWire + "," + packet.BallColorGWire + "," + packet.BallColorBWire + ") decoded=(" + num5.ToString("F3") + "," + num6.ToString("F3") + "," + num7.ToString("F3") + ") mode=" + packet.BallColorMode + " ballMatchRaw=" + packet.BallMatchBody + " ballMatchWire=" + packet.BallMatchBodyWire + " changedFields=" + packet.ChangedFields + " frame=" + Time.frameCount); } bool ballMatchBody = (ShlongSyncPacket.HasBoolWire(packet.BallMatchBodyWire) ? ShlongSyncPacket.DecodeBoolWire(packet.BallMatchBodyWire, packet.BallMatchBody) : (packet.ChangedFields == 0 || packet.BallMatchBody)); if (Plugin.IsDebug) { Plugin.LogDebug("[NetColorApply] sender=" + senderId + " ballMatchDecoded=" + ballMatchBody + " frame=" + Time.frameCount); } value.BallColorTint = new Color(num5, num6, num7); value.BallColorMode = packet.BallColorMode; value.BallMatchBody = ballMatchBody; value.BallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(packet.BallTextureSourceMode); value.InvalidateColorMaterialCache(dick: false, balls: true); value.ApplyBallColorTint(); flag4 = true; } if (flag3 || flag4) { if (value.HasBallsSheathSlots) { CosmeticDisplayManager.ForceRefreshColorsFor(value, dick: true, balls: true); } else { CosmeticDisplayManager.ForceRefreshColorsFor(value, flag3, flag4); } } if ((syncField & SyncField.Hide) != SyncField.None) { value.HideToggle = packet.HideToggle; } if (packet.ChangedFields != 0 && (syncField & SyncField.Bulge) != SyncField.None) { value.BulgeAmount = packet.BulgeAmount; value.BulgePosition = packet.BulgePosition; value.BulgeWidth = ((packet.BulgeWidth > 0.001f) ? packet.BulgeWidth : 1f); value.BulgeSharpness = ((packet.BulgeSharpness > 0.001f) ? packet.BulgeSharpness : 1f); value.BulgeLerpSpeed = ((packet.BulgeLerpSpeed > 0.001f) ? packet.BulgeLerpSpeed : 2f); } if (flag) { value.RefreshTransform(); } if (!value.HasReceivedRemoteVisualState) { bool flag5 = syncField == SyncField.All; bool flag6 = (syncField & SyncField.Preset) != 0; bool flag7 = (syncField & SyncField.Scale) != 0; if (flag5 || (flag6 && flag7)) { value.HasReceivedRemoteVisualState = true; if (Plugin.IsDebug) { string[] obj2 = new string[10] { "[NetVisualReady] sender=", senderId, " mask=", syncField.ToString(), " preset=", value.PresetIndex.ToString(), " scale=", null, null, null }; Vector3 val = value.ScaleOffset; obj2[7] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString(); obj2[8] = " → ready=true frame="; obj2[9] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj2)); } } else if (Plugin.IsDebug) { Plugin.LogDebug("[NetVisualReady] sender=" + senderId + " mask=" + syncField.ToString() + " preset=" + value.PresetIndex + " → still not ready (need Preset+Scale) frame=" + Time.frameCount); } } else if ((syncField & SyncField.Preset) != SyncField.None && (syncField & SyncField.Scale) == 0) { value.HasReceivedRemoteVisualState = false; if (Plugin.IsDebug) { Plugin.LogDebug("[NetVisualReady] sender=" + senderId + " mask=" + syncField.ToString() + " preset=" + value.PresetIndex + " → reset to false (Preset without Scale) frame=" + Time.frameCount); } } return true; } catch (Exception ex) { Plugin.LogWarningLimited("net.apply_packet", "Sync apply failed: " + ex.GetType().Name + " - " + ex.Message); return true; } } private static void MergePacket(ShlongSyncPacket existing, ShlongSyncPacket incoming) { SyncField syncField = (SyncField)incoming.ChangedFields; if (syncField == SyncField.None) { syncField = SyncField.All; } if ((syncField & SyncField.Position) != SyncField.None) { existing.DickOffsetX = incoming.DickOffsetX; existing.DickOffsetY = incoming.DickOffsetY; } if ((syncField & SyncField.Scale) != SyncField.None) { existing.ScaleX = incoming.ScaleX; existing.ScaleY = incoming.ScaleY; existing.ScaleZ = incoming.ScaleZ; existing.DickSizeOffset = incoming.DickSizeOffset; } if ((syncField & SyncField.BallsSize) != SyncField.None) { existing.BallsSizeOffset = incoming.BallsSizeOffset; } if ((syncField & SyncField.Preset) != SyncField.None) { existing.CurrentDick = incoming.CurrentDick; } if ((syncField & SyncField.Arousal) != SyncField.None) { existing.ArousalTarget = incoming.ArousalTarget; } if ((syncField & SyncField.Futa) != SyncField.None) { existing.FutaToggle = incoming.FutaToggle; } if ((syncField & SyncField.Clothing) != SyncField.None) { existing.ClothingOverride = incoming.ClothingOverride; } if ((syncField & SyncField.Rotation) != SyncField.None) { existing.BaseRotationX = incoming.BaseRotationX; existing.BaseRotationY = incoming.BaseRotationY; existing.BaseRotationZ = incoming.BaseRotationZ; } if ((syncField & SyncField.ErectAngle) != SyncField.None) { existing.ErectAngleOffset = incoming.ErectAngleOffset; } if ((syncField & SyncField.Color) != SyncField.None) { existing.ColorR = incoming.ColorR; existing.ColorG = incoming.ColorG; existing.ColorB = incoming.ColorB; existing.ColorMode = incoming.ColorMode; existing.MatchBody = incoming.MatchBody; existing.TextureSourceMode = incoming.TextureSourceMode; existing.MatchBodyWire = incoming.MatchBodyWire; existing.ColorRWire = incoming.ColorRWire; existing.ColorGWire = incoming.ColorGWire; existing.ColorBWire = incoming.ColorBWire; } if ((syncField & SyncField.BallColor) != SyncField.None) { existing.BallColorR = incoming.BallColorR; existing.BallColorG = incoming.BallColorG; existing.BallColorB = incoming.BallColorB; existing.BallColorMode = incoming.BallColorMode; existing.BallMatchBody = incoming.BallMatchBody; existing.BallTextureSourceMode = incoming.BallTextureSourceMode; existing.BallMatchBodyWire = incoming.BallMatchBodyWire; existing.BallColorRWire = incoming.BallColorRWire; existing.BallColorGWire = incoming.BallColorGWire; existing.BallColorBWire = incoming.BallColorBWire; } if ((syncField & SyncField.Hide) != SyncField.None) { existing.HideToggle = incoming.HideToggle; } if ((syncField & SyncField.Bulge) != SyncField.None) { existing.BulgeAmount = incoming.BulgeAmount; existing.BulgePosition = incoming.BulgePosition; existing.BulgeWidth = incoming.BulgeWidth; existing.BulgeSharpness = incoming.BulgeSharpness; existing.BulgeLerpSpeed = incoming.BulgeLerpSpeed; } existing.ChangedFields |= incoming.ChangedFields; } private static ShlongSyncPacket ClonePacket(ShlongSyncPacket packet) { return new ShlongSyncPacket { ChangedFields = packet.ChangedFields, DickOffsetX = packet.DickOffsetX, DickOffsetY = packet.DickOffsetY, DickSizeOffset = packet.DickSizeOffset, BallsSizeOffset = packet.BallsSizeOffset, CurrentDick = packet.CurrentDick, ArousalTarget = packet.ArousalTarget, FutaToggle = packet.FutaToggle, ClothingOverride = packet.ClothingOverride, BaseRotationX = packet.BaseRotationX, BaseRotationY = packet.BaseRotationY, BaseRotationZ = packet.BaseRotationZ, ErectAngleOffset = packet.ErectAngleOffset, ScaleX = packet.ScaleX, ScaleY = packet.ScaleY, ScaleZ = packet.ScaleZ, ColorR = packet.ColorR, ColorG = packet.ColorG, ColorB = packet.ColorB, ColorMode = packet.ColorMode, MatchBody = packet.MatchBody, TextureSourceMode = packet.TextureSourceMode, MatchBodyWire = packet.MatchBodyWire, ColorRWire = packet.ColorRWire, ColorGWire = packet.ColorGWire, ColorBWire = packet.ColorBWire, BodyPartsData = packet.BodyPartsData, BallColorR = packet.BallColorR, BallColorG = packet.BallColorG, BallColorB = packet.BallColorB, BallColorMode = packet.BallColorMode, BallMatchBody = packet.BallMatchBody, BallTextureSourceMode = packet.BallTextureSourceMode, BallMatchBodyWire = packet.BallMatchBodyWire, BallColorRWire = packet.BallColorRWire, BallColorGWire = packet.BallColorGWire, BallColorBWire = packet.BallColorBWire, HideToggle = packet.HideToggle, BulgeAmount = packet.BulgeAmount, BulgePosition = packet.BulgePosition, BulgeWidth = packet.BulgeWidth, BulgeSharpness = packet.BulgeSharpness, BulgeLerpSpeed = packet.BulgeLerpSpeed }; } } } namespace AtlyssShlongs.Input { public static class InputManager { private static ConfigEntry _toggleGui; private static ConfigEntry _toggleArousal; private static ConfigEntry _toggleClothing; private static ConfigEntry _prevDick; private static ConfigEntry _nextDick; private static ConfigEntry _toggleFuta; private static ConfigEntry _increaseBalls; private static ConfigEntry _decreaseBalls; private static ConfigEntry _increaseDick; private static ConfigEntry _decreaseDick; private static ConfigEntry _adjustOffset; private static ConfigEntry _manualSync; private static ConfigEntry _cycleArousal; private static ConfigEntry _toggleHide; private static ConfigEntry _bulgePosition0; private static ConfigEntry _bulgePosition1; private static ConfigEntry _bulgePosition2; private static ConfigEntry _bulgePosition3; private static ConfigEntry _bulgePosition4; private static ConfigEntry _bulgePosition5; private static ConfigEntry _bulgePosition6; private static bool _wasAdjustingOffset; private static Vector2 _oldMousePos; private static Vector2 _oldDickOffset; public static void Initialize(ConfigFile config) { //IL_0016: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_0130: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Invalid comparison between Unknown and I4 //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Invalid comparison between Unknown and I4 //IL_042a: Unknown result type (might be due to invalid IL or missing references) _toggleGui = config.Bind("Shortcuts", "Open GUI", new KeyboardShortcut((KeyCode)287, Array.Empty()), "Open or close the AtlyssShlongs control window."); _toggleArousal = config.Bind("Shortcuts", "Toggle Arousal", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Toggle arousal."); _toggleClothing = config.Bind("Shortcuts", "Toggle Clothing Override", new KeyboardShortcut((KeyCode)99, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Toggle clothing override."); _prevDick = config.Bind("Shortcuts", "Previous Dick", new KeyboardShortcut((KeyCode)104, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Select the previous dick preset."); _nextDick = config.Bind("Shortcuts", "Next Dick", new KeyboardShortcut((KeyCode)106, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Select the next dick preset."); _toggleFuta = config.Bind("Shortcuts", "Toggle Futa", new KeyboardShortcut((KeyCode)102, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Toggle futa mode."); _increaseBalls = config.Bind("Shortcuts", "Increase Balls", new KeyboardShortcut((KeyCode)110, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Increase ball size."); _decreaseBalls = config.Bind("Shortcuts", "Decrease Balls", new KeyboardShortcut((KeyCode)98, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Decrease ball size."); _increaseDick = config.Bind("Shortcuts", "Increase Dick", new KeyboardShortcut((KeyCode)110, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Increase dick size."); _decreaseDick = config.Bind("Shortcuts", "Decrease Dick", new KeyboardShortcut((KeyCode)98, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Decrease dick size."); _adjustOffset = config.Bind("Shortcuts", "Adjust Offset", new KeyboardShortcut((KeyCode)308, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Hold to adjust offset with the mouse; use the wheel to change erect direction."); _manualSync = config.Bind("Shortcuts", "Manual Sync", new KeyboardShortcut((KeyCode)257, Array.Empty()), "Force a sync message."); _cycleArousal = config.Bind("Shortcuts", "Cycle Arousal", new KeyboardShortcut((KeyCode)103, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Cycle through arousal stages."); _toggleHide = config.Bind("Shortcuts", "Toggle Hide Shlong", new KeyboardShortcut((KeyCode)104, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Toggle hiding the shlong (and balls)."); _bulgePosition0 = config.Bind("Shortcuts", "Bulge Position 0", new KeyboardShortcut((KeyCode)0, Array.Empty()), "Set bulge position to 0 (Balls)."); _bulgePosition1 = config.Bind("Shortcuts", "Bulge Position 1", new KeyboardShortcut((KeyCode)0, Array.Empty()), "Set bulge position to 1 (Sheath)."); _bulgePosition2 = config.Bind("Shortcuts", "Bulge Position 2", new KeyboardShortcut((KeyCode)0, Array.Empty()), "Set bulge position to 2 (Root)."); _bulgePosition3 = config.Bind("Shortcuts", "Bulge Position 3", new KeyboardShortcut((KeyCode)0, Array.Empty()), "Set bulge position to 3 (Base)."); _bulgePosition4 = config.Bind("Shortcuts", "Bulge Position 4", new KeyboardShortcut((KeyCode)0, Array.Empty()), "Set bulge position to 4 (Mid)."); _bulgePosition5 = config.Bind("Shortcuts", "Bulge Position 5", new KeyboardShortcut((KeyCode)0, Array.Empty()), "Set bulge position to 5 (Upper)."); _bulgePosition6 = config.Bind("Shortcuts", "Bulge Position 6", new KeyboardShortcut((KeyCode)0, Array.Empty()), "Set bulge position to 6 (Tip)."); KeyboardShortcut value = _toggleGui.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0) { _toggleGui.Value = new KeyboardShortcut((KeyCode)287, Array.Empty()); config.Save(); Plugin.LogDebug("[Hotkey] Open GUI was None in config; restored to F6."); } ConfigEntry val = config.Bind("Migrations", "Hide Shlong Default Hotkey v1", false, "Internal migration flag. True after the default Hide Shlong hotkey has been initialized."); if (!val.Value) { value = _toggleHide.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0) { _toggleHide.Value = new KeyboardShortcut((KeyCode)104, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }); Plugin.LogDebug("[Hotkey] Hide Shlong was None in config; restored to LeftAlt+H."); } val.Value = true; config.Save(); } } public static bool IsToggleGuiPressed() { if (IsRebindingAnyShortcut()) { return false; } return IsShortcutDown(_toggleGui); } public static bool IsManualSyncPressed() { ConfigEntry hotkeysEnabled = PluginConfig.HotkeysEnabled; return (hotkeysEnabled == null || hotkeysEnabled.Value) && !IsTextInputFocused() && IsShortcutDown(_manualSync); } public static bool IsCycleArousalPressed() { ConfigEntry hotkeysEnabled = PluginConfig.HotkeysEnabled; return (hotkeysEnabled == null || hotkeysEnabled.Value) && !IsTextInputFocused() && IsShortcutDown(_cycleArousal); } public static ConfigEntry GetToggleGui() { return _toggleGui; } public static ConfigEntry GetToggleArousal() { return _toggleArousal; } public static ConfigEntry GetToggleClothing() { return _toggleClothing; } public static ConfigEntry GetPrevDick() { return _prevDick; } public static ConfigEntry GetNextDick() { return _nextDick; } public static ConfigEntry GetToggleFuta() { return _toggleFuta; } public static ConfigEntry GetIncreaseBalls() { return _increaseBalls; } public static ConfigEntry GetDecreaseBalls() { return _decreaseBalls; } public static ConfigEntry GetIncreaseDick() { return _increaseDick; } public static ConfigEntry GetDecreaseDick() { return _decreaseDick; } public static ConfigEntry GetAdjustOffset() { return _adjustOffset; } public static ConfigEntry GetManualSync() { return _manualSync; } public static ConfigEntry GetCycleArousal() { return _cycleArousal; } public static ConfigEntry GetToggleHide() { return _toggleHide; } public static ConfigEntry GetBulgePosition0() { return _bulgePosition0; } public static ConfigEntry GetBulgePosition1() { return _bulgePosition1; } public static ConfigEntry GetBulgePosition2() { return _bulgePosition2; } public static ConfigEntry GetBulgePosition3() { return _bulgePosition3; } public static ConfigEntry GetBulgePosition4() { return _bulgePosition4; } public static ConfigEntry GetBulgePosition5() { return _bulgePosition5; } public static ConfigEntry GetBulgePosition6() { return _bulgePosition6; } public static bool ProcessKeyboardInput(ShlongController sc) { //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0482: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) bool result = false; ConfigEntry hotkeysEnabled = PluginConfig.HotkeysEnabled; if (hotkeysEnabled != null && !hotkeysEnabled.Value) { return false; } if (IsTextInputFocused()) { return false; } if (IsShortcutDown(_toggleArousal)) { sc.ArousalTarget = ((sc.ArousalTarget == 0f) ? 100f : 0f); sc.RequestSyncImmediate(); } if (IsShortcutDown(_toggleHide)) { sc.HideToggle = !sc.HideToggle; sc.RequestSyncImmediate(); } if (IsShortcutDown(_cycleArousal)) { sc.CycleArousal(); } if (TryApplyBulgePositionHotkey(sc)) { result = true; } if (IsShortcutDown(_toggleClothing)) { sc.ClothingOverride = !sc.ClothingOverride; sc.RequestSyncImmediate(forceSave: true, SyncField.Clothing); } if (IsShortcutDown(_prevDick)) { int presetCount = Plugin.Presets.PresetCount; int presetIndex = (sc.PresetIndex - 1 + presetCount) % presetCount; sc.QueueInteractivePresetChange(presetIndex); } if (IsShortcutDown(_nextDick)) { int presetCount2 = Plugin.Presets.PresetCount; int presetIndex2 = (sc.PresetIndex + 1) % presetCount2; sc.QueueInteractivePresetChange(presetIndex2); } if (IsShortcutDown(_toggleFuta)) { sc.FutaToggle = !sc.FutaToggle; sc.RequestSyncImmediate(); } if ((Object)(object)sc.BallBone != (Object)null) { if (IsShortcutDown(_increaseBalls)) { sc.BallsSizeOffset = Mathf.Clamp(sc.BallsSizeOffset + 0.07f + sc.BallsSizeOffset * 0.1f, -1f, 10f); sc.RefreshTransform(); LifecycleDiagnostics.OnSizeAdjustment(); result = true; } if (IsShortcutDown(_decreaseBalls)) { sc.BallsSizeOffset = Mathf.Clamp(sc.BallsSizeOffset - (0.07f + sc.BallsSizeOffset * 0.1f), -1f, 10f); sc.RefreshTransform(); LifecycleDiagnostics.OnSizeAdjustment(); result = true; } } if (IsShortcutDown(_increaseDick)) { float num = 0.06f + Mathf.Max(Mathf.Max(sc.ScaleOffset.x, sc.ScaleOffset.y), 0f) * 0.1f; float num2 = Mathf.Clamp(sc.ScaleOffset.x + num, -1f, 10f); float num3 = Mathf.Clamp(sc.ScaleOffset.y + num, -1f, 10f); sc.ScaleOffset = new Vector3(num2, num3, num2); sc.RefreshTransform(); LifecycleDiagnostics.OnSizeAdjustment(); result = true; } if (IsShortcutDown(_decreaseDick)) { float num4 = 0.06f + Mathf.Max(Mathf.Max(sc.ScaleOffset.x, sc.ScaleOffset.y), 0f) * 0.1f; float num5 = Mathf.Clamp(sc.ScaleOffset.x - num4, -1f, 10f); float num6 = Mathf.Clamp(sc.ScaleOffset.y - num4, -1f, 10f); sc.ScaleOffset = new Vector3(num5, num6, num5); sc.RefreshTransform(); LifecycleDiagnostics.OnSizeAdjustment(); result = true; } bool flag = IsShortcutHeld(_adjustOffset); if (!_wasAdjustingOffset && flag) { _oldMousePos = Vector2.op_Implicit(Input.mousePosition); _oldDickOffset = sc.PositionOffset; } if (flag) { Vector2 val = _oldDickOffset + (Vector2.op_Implicit(Input.mousePosition) - _oldMousePos) * 1.5E-05f; sc.PositionOffset = new Vector2(Mathf.Clamp(val.x, -0.05f, 0.05f), Mathf.Clamp(val.y, -0.05f, 0.05f)); sc.ErectAngleOffset = Mathf.Clamp(sc.ErectAngleOffset + Input.mouseScrollDelta.y * 1.5f, -90f, 90f); sc.RefreshTransform(); LifecycleDiagnostics.OnSizeAdjustment(); } if (_wasAdjustingOffset && !flag) { _oldMousePos = Vector2.op_Implicit(Input.mousePosition); _oldDickOffset = sc.PositionOffset; sc.RequestSyncImmediate(); } _wasAdjustingOffset = flag; if (IsShortcutDown(_manualSync)) { sc.RequestSyncImmediate(); } return result; } private static bool TryApplyBulgePositionHotkey(ShlongController sc) { if ((Object)(object)sc == (Object)null) { return false; } float num = -1f; if (IsShortcutDown(_bulgePosition0)) { num = 0f; } else if (IsShortcutDown(_bulgePosition1)) { num = 1f; } else if (IsShortcutDown(_bulgePosition2)) { num = 2f; } else if (IsShortcutDown(_bulgePosition3)) { num = 3f; } else if (IsShortcutDown(_bulgePosition4)) { num = 4f; } else if (IsShortcutDown(_bulgePosition5)) { num = 5f; } else if (IsShortcutDown(_bulgePosition6)) { num = 6f; } if (num < 0f) { return false; } sc.BulgePosition = num; sc.RequestSyncImmediate(forceSave: true, SyncField.Bulge); return true; } private static Vector3 ClampScale(Vector3 scale) { //IL_0001: 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_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_0038: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp(scale.x, -1f, 10f); float num2 = Mathf.Clamp(scale.y, -1f, 10f); return new Vector3(num, num2, num); } public static bool IsRebindingAnyShortcut() { return SettingsWindow.IsRebindActive; } private static bool IsTextInputFocused() { EventSystem current = EventSystem.current; if ((Object)(object)current == (Object)null) { return false; } GameObject currentSelectedGameObject = current.currentSelectedGameObject; if ((Object)(object)currentSelectedGameObject == (Object)null) { return false; } if ((Object)(object)currentSelectedGameObject.GetComponent() != (Object)null) { return true; } MonoBehaviour[] components = currentSelectedGameObject.GetComponents(); for (int i = 0; i < components.Length; i++) { if (!((Object)(object)components[i] == (Object)null)) { string name = ((object)components[i]).GetType().Name; if (name == "TMP_InputField" || name == "TMPInputField") { return true; } } } return false; } private static bool IsShortcutDown(ConfigEntry shortcut) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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) if (shortcut == null) { return false; } KeyboardShortcut value = shortcut.Value; return (int)((KeyboardShortcut)(ref value)).MainKey != 0 && AreModifiersPressed(value) && IsKeyDown(((KeyboardShortcut)(ref value)).MainKey); } private static bool IsShortcutHeld(ConfigEntry shortcut) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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) if (shortcut == null) { return false; } KeyboardShortcut value = shortcut.Value; return (int)((KeyboardShortcut)(ref value)).MainKey != 0 && AreModifiersPressed(value) && IsKeyHeld(((KeyboardShortcut)(ref value)).MainKey); } private static bool AreModifiersPressed(KeyboardShortcut shortcut) { //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_0019: Unknown result type (might be due to invalid IL or missing references) foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if (!IsKeyHeld(modifier)) { return false; } } return true; } private static bool IsKeyDown(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) if ((int)key == 306 || (int)key == 305) { return Input.GetKeyDown((KeyCode)306) || Input.GetKeyDown((KeyCode)305); } if ((int)key == 308 || (int)key == 307) { return Input.GetKeyDown((KeyCode)308) || Input.GetKeyDown((KeyCode)307); } if ((int)key == 304 || (int)key == 303) { return Input.GetKeyDown((KeyCode)304) || Input.GetKeyDown((KeyCode)303); } return Input.GetKeyDown(key); } private static bool IsKeyHeld(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) if ((int)key == 306 || (int)key == 305) { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } if ((int)key == 308 || (int)key == 307) { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } if ((int)key == 304 || (int)key == 303) { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } return Input.GetKey(key); } public static string FormatShortcut(KeyboardShortcut shortcut) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_002e: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0) { return "None"; } List list = new List(); foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { list.Add(((object)modifier/*cast due to .constrained prefix*/).ToString()); } list.Add(((object)((KeyboardShortcut)(ref shortcut)).MainKey/*cast due to .constrained prefix*/).ToString()); return string.Join(" + ", list.ToArray()); } } } namespace AtlyssShlongs.Equipment { public static class LeggingsChecker { private static bool _pEquipLookupDone; private static MemberInfo _pEquipMember; private static bool _equipsLookupDone; private static MemberInfo _equipsMember; private static FieldInfo _scriptableEquipField; private static FieldInfo _vanityEquipField; private static object _leggingsKeyCache; private static bool _leggingsKeyLookupDone; private static int _logCount; private static int _cachedFrame = -1; private static bool _cachedKnown; private static bool _cachedResult = true; private static RaceModelEquipDisplay _cachedRmed; public static bool HasNoLeggingsEquipped(RaceModelEquipDisplay rmed) { if (TryHasNoLeggingsEquipped(rmed, out var noLeggings)) { return noLeggings; } return true; } public static bool TryHasNoLeggingsEquipped(RaceModelEquipDisplay rmed, out bool noLeggings) { noLeggings = false; if ((Object)(object)rmed == (Object)null) { return false; } int frameCount = Time.frameCount; if (frameCount == _cachedFrame && (Object)(object)rmed == (Object)(object)_cachedRmed) { noLeggings = _cachedResult; return _cachedKnown; } try { if (!_pEquipLookupDone) { Type type = ((object)rmed).GetType(); _pEquipMember = (MemberInfo)(AccessTools.Field(type, "_pEquip") ?? ((object)AccessTools.Field(type, "pEquip")) ?? ((object)(AccessTools.Property(type, "_pEquip") ?? AccessTools.Property(type, "PEquip")))); if (_pEquipMember == null) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if ((fieldInfo.Name.IndexOf("quip", StringComparison.OrdinalIgnoreCase) >= 0 || fieldInfo.Name.IndexOf("pEquip", StringComparison.OrdinalIgnoreCase) >= 0) && _pEquipMember == null) { _pEquipMember = fieldInfo; } } } _pEquipLookupDone = true; } if (_pEquipMember == null) { return CacheResult(frameCount, rmed, known: false, result: false, out noLeggings); } object memberValue = GetMemberValue(_pEquipMember, rmed); if (memberValue == null) { return CacheResult(frameCount, rmed, known: false, result: false, out noLeggings); } if (!_equipsLookupDone) { Type type2 = memberValue.GetType(); _equipsMember = (MemberInfo)(((object)AccessTools.Field(type2, "_equips")) ?? ((object)(AccessTools.Property(type2, "Equips") ?? AccessTools.Property(type2, "_equips")))); if (_equipsMember == null) { FieldInfo[] fields2 = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo2 in fields2) { if (typeof(IDictionary).IsAssignableFrom(fieldInfo2.FieldType) && _equipsMember == null) { _equipsMember = fieldInfo2; } } } _equipsLookupDone = true; } if (_equipsMember == null) { return CacheResult(frameCount, rmed, known: false, result: false, out noLeggings); } if (!(GetMemberValue(_equipsMember, memberValue) is IDictionary dictionary)) { return CacheResult(frameCount, rmed, known: false, result: false, out noLeggings); } if (!_leggingsKeyLookupDone) { _leggingsKeyLookupDone = true; foreach (object key in dictionary.Keys) { if (key.ToString().IndexOf("egg", StringComparison.OrdinalIgnoreCase) >= 0) { _leggingsKeyCache = key; break; } } if (_leggingsKeyCache == null && dictionary.Contains("Leggings")) { _leggingsKeyCache = "Leggings"; } } if (_leggingsKeyCache == null || !dictionary.Contains(_leggingsKeyCache)) { return CacheResult(frameCount, rmed, known: false, result: false, out noLeggings); } object obj = dictionary[_leggingsKeyCache]; if (obj == null) { return CacheResult(frameCount, rmed, known: false, result: false, out noLeggings); } if (_scriptableEquipField == null && _vanityEquipField == null) { Type type3 = obj.GetType(); _scriptableEquipField = AccessTools.Field(type3, "_scriptableEquip"); _vanityEquipField = AccessTools.Field(type3, "_vanityEquip"); } bool flag = _scriptableEquipField != null && _scriptableEquipField.GetValue(obj) != null; bool flag2 = _vanityEquipField != null && _vanityEquipField.GetValue(obj) != null; bool flag3 = !flag; if (Plugin.IsDebug && flag2 && flag3) { Plugin.LogDebug("[LeggingsChecker] vanity present but ignored (hasScriptable=false → noLeggings=true)"); } return CacheResult(frameCount, rmed, known: true, flag3, out noLeggings); } catch (Exception ex) { if (_logCount < 3 && Plugin.IsDebug) { Plugin.LogDebug("Leggings check exception: " + ex.Message); _logCount++; } return CacheResult(frameCount, rmed, known: false, result: false, out noLeggings); } } private static bool CacheResult(int frame, RaceModelEquipDisplay rmed, bool known, bool result, out bool noLeggings) { _cachedFrame = frame; _cachedRmed = rmed; _cachedKnown = known; _cachedResult = result; noLeggings = result; return known; } private static object GetMemberValue(MemberInfo member, object target) { if (member is FieldInfo fieldInfo) { return fieldInfo.GetValue(target); } if (member is PropertyInfo propertyInfo) { return propertyInfo.GetValue(target, null); } return null; } } } namespace AtlyssShlongs.Data { public static class Defaults { public static readonly PresetData[] Presets = new PresetData[14] { new PresetData { Id = "byrdle", DisplayName = "Byrdle", PrefabName = "ByrdleDick", ArmatureBone = "DickArmature", MeshName = "Byrdle.M", DynamicBones = new string[1] { "Penis.000" }, Position = new Vector3(0f, -0.00046f, 0.00314f), Rotation = new Vector3(-88.6f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f) }, new PresetData { Id = "bunneh", DisplayName = "Bunneh", PrefabName = "BunnehDick", ArmatureBone = "DickArmature.001", MeshName = "Bunny.M.001", DynamicBones = new string[2] { "Penis.000", "Balls" }, Position = new Vector3(0f, -0.00081f, 0.00252f), Rotation = new Vector3(-100f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f) }, new PresetData { Id = "imp", DisplayName = "Imp", PrefabName = "ImpDick", ArmatureBone = "Armature.001", MeshName = "FlaccidPeen.001", DynamicBones = new string[2] { "Penis.000", "Balls" }, Position = new Vector3(0f, -0.00165f, 0.00276f), Rotation = new Vector3(-107.394f, 0f, 0f), Scale = new Vector3(1.5f, 1.5f, 1.5f) }, new PresetData { Id = "kubold", DisplayName = "Kubold", PrefabName = "KuboldDick", ArmatureBone = "SK_BlueDragon.002", MeshName = "SK_BlueDragon.male.002", DynamicBones = new string[1] { "Penis.000" }, Position = new Vector3(0f, 0.00131f, 0.00323f), Rotation = new Vector3(-97.68f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f) }, new PresetData { Id = "canine", DisplayName = "Canine", PrefabName = "CanineDick", ArmatureBone = "SK_Anubis.002", MeshName = "CaninePenis", DynamicBones = new string[2] { "Penis.000", "Balls1" }, Position = new Vector3(0f, -0.00081f, 0.00252f), Rotation = new Vector3(-100f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f) }, new PresetData { Id = "equine", DisplayName = "Equine", PrefabName = "EquineDick", ArmatureBone = "Armature..012", MeshName = "SK_Deer.male.001", DynamicBones = new string[2] { "Penis.000", "Balls1" }, Position = new Vector3(0f, -0.00144f, 0.0016f), Rotation = new Vector3(-100f, 0f, 0f), Scale = new Vector3(1.5f, 1.5f, 1.5f) }, new PresetData { Id = "hemi", DisplayName = "Hemi", PrefabName = "HemiDick", ArmatureBone = "HemiArmature", MeshName = "HemiPeenMesh", DynamicBones = new string[1] { "Penis.000" }, Position = new Vector3(0f, 0.00067f, 0.00384f), Rotation = new Vector3(-108.68f, 0f, 0f), Scale = new Vector3(1.5f, 1.5f, 1.5f) }, new PresetData { Id = "equine_bulge_test", DisplayName = "Equine Bulge Test", PrefabName = "EquineDick_Bulgy", ArmatureBone = "Armature..012", MeshName = "SK_Deer.male.001", DynamicBones = new string[2] { "Penis.000", "Balls1" }, Position = new Vector3(0f, -0.00144f, 0.0016f), Rotation = new Vector3(-100f, 0f, 0f), Scale = new Vector3(1.5f, 1.5f, 1.5f), AssetSource = PresetAssetSource.Test }, new PresetData { Id = "canine_bulge_test", DisplayName = "Canine Bulge Test", PrefabName = "CanineDick_Bulgy", ArmatureBone = "SK_Anubis.002", MeshName = "CaninePenis", DynamicBones = new string[2] { "Penis.000", "Balls1" }, Position = new Vector3(0f, -0.00081f, 0.00252f), Rotation = new Vector3(-100f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f), AssetSource = PresetAssetSource.Test }, new PresetData { Id = "byrdle_bulge_test", DisplayName = "Byrdle Bulge Test", PrefabName = "ByrdleDick_Bulgy", ArmatureBone = "DickArmature", MeshName = "Byrdle.M", DynamicBones = new string[1] { "Penis.000" }, Position = new Vector3(0f, -0.00046f, 0.00314f), Rotation = new Vector3(-88.6f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f), AssetSource = PresetAssetSource.Test }, new PresetData { Id = "imp_bulge_test", DisplayName = "Imp Bulge Test", PrefabName = "ImpDick_Bulgy", ArmatureBone = "Armature.001", MeshName = "FlaccidPeen.001", DynamicBones = new string[2] { "Penis.000", "Balls" }, Position = new Vector3(0f, -0.00165f, 0.00276f), Rotation = new Vector3(-107.394f, 0f, 0f), Scale = new Vector3(1.5f, 1.5f, 1.5f), AssetSource = PresetAssetSource.Test }, new PresetData { Id = "bunneh_bulge_test", DisplayName = "Bunneh Bulge Test", PrefabName = "BunnehDick_Bulgy", ArmatureBone = "DickArmature.001", MeshName = "Bunny.M.001", DynamicBones = new string[2] { "Penis.000", "Balls" }, Position = new Vector3(0f, -0.00081f, 0.00252f), Rotation = new Vector3(-100f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f), AssetSource = PresetAssetSource.Test }, new PresetData { Id = "kubold_bulge_test", DisplayName = "Kubold Bulge Test", PrefabName = "KuboldDick_Bulgy", ArmatureBone = "SK_BlueDragon.002", MeshName = "SK_BlueDragon.male.002", DynamicBones = new string[1] { "Penis.000" }, Position = new Vector3(0f, 0.00131f, 0.00323f), Rotation = new Vector3(-97.68f, 0f, 0f), Scale = new Vector3(2f, 2f, 2f), AssetSource = PresetAssetSource.Test }, new PresetData { Id = "hemi_bulge_test", DisplayName = "Hemi Bulge Test", PrefabName = "HemiDick_Bulgy", ArmatureBone = "HemiArmature", MeshName = "HemiPeenMesh", DynamicBones = new string[1] { "Penis.000" }, Position = new Vector3(0f, 0.00067f, 0.00384f), Rotation = new Vector3(-108.68f, 0f, 0f), Scale = new Vector3(1.5f, 1.5f, 1.5f), AssetSource = PresetAssetSource.Test } }; public static readonly RaceData[] Races = new RaceData[5] { new RaceData { Index = 0, RaceName = "Byrdle", ModelContains = "Byrdle", AltModelContains = null, BodyMesh = "byrdle_body", AttachBone = "hip", MaterialSlot = 2 }, new RaceData { Index = 1, RaceName = "Chang", ModelContains = "Chang", AltModelContains = null, BodyMesh = "chang_body", AttachBone = "hip", MaterialSlot = 2 }, new RaceData { Index = 2, RaceName = "Imp", ModelContains = "Imp", AltModelContains = null, BodyMesh = "imp_body", AttachBone = "hip", MaterialSlot = 2 }, new RaceData { Index = 3, RaceName = "Kobold", ModelContains = "Kobold", AltModelContains = "Kubold", BodyMesh = "kobold_body", AttachBone = "hip", MaterialSlot = 2 }, new RaceData { Index = 4, RaceName = "Poon", ModelContains = "Poon", AltModelContains = null, BodyMesh = "poon_body", AttachBone = "hip", MaterialSlot = 2 } }; public static int DetectRace(string modelName) { if (string.IsNullOrEmpty(modelName)) { return -1; } for (int i = 0; i < Races.Length; i++) { if (modelName.Contains(Races[i].ModelContains)) { return i; } if (Races[i].AltModelContains != null && modelName.Contains(Races[i].AltModelContains)) { return i; } } return -1; } } public enum PresetAssetSource { Main, Test, External } [Serializable] public class PresetData { public string Id; public string DisplayName; public string PrefabName; public string ArmatureBone; public string MeshName; public string[] DynamicBones; public Vector3 Position; public Vector3 Rotation; public Vector3 Scale; public PresetAssetSource AssetSource; [NonSerialized] public GameObject LoadedPrefab; [NonSerialized] public bool IsExternal; public string FriendlyName { get { if (AssetSource == PresetAssetSource.Test && DisplayName != null) { string text = DisplayName; if (text.EndsWith(" Bulge Test", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - " Bulge Test".Length); } return text; } return DisplayName ?? Id ?? ""; } } } [Serializable] public struct PresetSettings { public Vector3 ScaleOffset; public float BallsSizeOffset; public Vector2 PositionOffset; public Vector3 BaseRotation; public float ErectAngleOffset; public float ArousalTarget; public float BulgeAmount; public float BulgePosition; public float BulgeWidth; public float BulgeSharpness; public float BulgeLerpSpeed; public Color ColorTint; public int ColorMode; public bool MatchBody; public int TextureSourceMode; public Color BallColorTint; public int BallColorMode; public bool BallMatchBody; public int BallTextureSourceMode; public bool FutaToggle; public bool ClothingOverride; public bool HideToggle; } [Serializable] public class ProfileSaveData { public int DickNumber; public float DickOffsetX; public float DickOffsetY; public float BallsSizeOffset; public bool FutaToggle; public bool ClothingOverride; public bool HideToggle; public float SizeOffset; public Vector3 AngleOffset; public float ErectAngle; public Vector3 ScaleOffset; public float ColorR = 1f; public float ColorG = 1f; public float ColorB = 1f; public int ColorMode; public bool MatchBody = true; public int TextureSourceContractVersion; public int TextureSourceMode; public float ArousalLerpSpeed = 2f; public float BulgeAmount; public float BulgePosition; public float BulgeWidth = 1f; public float BulgeSharpness = 1f; public float BulgeLerpSpeed = 2f; public float BallColorR = 1f; public float BallColorG = 1f; public float BallColorB = 1f; public int BallColorMode; public bool BallMatchBody = true; public int BallTextureSourceMode; } [Serializable] public class RaceData { public int Index; public string RaceName; public string ModelContains; public string AltModelContains; public string BodyMesh; public string AttachBone; public int MaterialSlot; } [Serializable] public class PerPresetSettingsEntry { public int PresetIndex; public string PresetId; public PresetSettings Settings; } [Serializable] public class PerPresetSettingsStore { public int SchemaVersion; public PerPresetSettingsEntry[] Entries; } [Serializable] public class CharacterSettingsEntry { public int SlotIndex; public string CharacterName; public string RaceTag; public int CharacterSelectPreviewMode; public ProfileSaveData LastUsed; public PerPresetSettingsEntry[] PerPresetEntries; } [Serializable] public class CharacterSettingsStore { public CharacterSettingsEntry[] Characters; } [Serializable] public class CharacterSettingsFile { public int SchemaVersion = 5; public int SlotIndex; public string CharacterName; public string RaceTag; public int CharacterSelectPreviewMode; public bool HasLastUsed; public int Last_DickNumber; public float Last_DickOffsetX; public float Last_DickOffsetY; public float Last_BallsSizeOffset; public bool Last_FutaToggle; public bool Last_ClothingOverride; public bool Last_HideToggle; public float Last_SizeOffset; public Vector3 Last_AngleOffset; public float Last_ErectAngle; public Vector3 Last_ScaleOffset; public float Last_ColorR = 1f; public float Last_ColorG = 1f; public float Last_ColorB = 1f; public int Last_ColorMode; public bool Last_MatchBody = true; public int Last_TextureSourceMode; public float Last_ArousalLerpSpeed = 2f; public float Last_BulgeAmount; public float Last_BulgePosition; public float Last_BulgeWidth = 1f; public float Last_BulgeSharpness = 1f; public float Last_BulgeLerpSpeed = 2f; public float Last_BallColorR = 1f; public float Last_BallColorG = 1f; public float Last_BallColorB = 1f; public int Last_BallColorMode; public bool Last_BallMatchBody = true; public int Last_BallTextureSourceMode; public CharacterPresetSettingsFileEntry[] PerPresetEntries; } [Serializable] public class CharacterPresetSettingsFileEntry { public int PresetIndex; public string PresetId; public Vector3 ScaleOffset; public float BallsSizeOffset; public Vector2 PositionOffset; public Vector3 BaseRotation; public float ErectAngleOffset; public float ArousalTarget; public float BulgeAmount; public float BulgePosition; public float BulgeWidth = 1f; public float BulgeSharpness = 1f; public float BulgeLerpSpeed = 2f; public Color ColorTint; public int ColorMode; public bool MatchBody; public int TextureSourceMode; public Color BallColorTint; public int BallColorMode; public bool BallMatchBody; public int BallTextureSourceMode; public bool FutaToggle; public bool ClothingOverride; public bool HideToggle; } public class UserPresetManager { public const int CharacterSelectPreviewUseGlobal = 0; public const int CharacterSelectPreviewShow = 1; public const int CharacterSelectPreviewHide = 2; private readonly string _baseDir; private readonly string _presetsDir; private readonly string _lastUsedPath; private readonly string _perPresetPath; private readonly string _charactersDir; private readonly string _legacyCharactersPath; public UserPresetManager(string pluginConfigDir) { _baseDir = Path.Combine(pluginConfigDir, "AtlyssShlongs"); _presetsDir = Path.Combine(_baseDir, "presets"); _lastUsedPath = Path.Combine(_baseDir, "last_settings.json"); _perPresetPath = Path.Combine(_baseDir, "per_preset_settings.json"); _charactersDir = Path.Combine(_baseDir, "Characters"); _legacyCharactersPath = Path.Combine(_baseDir, "Characters.json"); try { if (!Directory.Exists(_baseDir)) { Directory.CreateDirectory(_baseDir); } if (!Directory.Exists(_presetsDir)) { Directory.CreateDirectory(_presetsDir); } if (!Directory.Exists(_charactersDir)) { Directory.CreateDirectory(_charactersDir); } TryMigrateLegacyCharactersJson(); } catch (Exception ex) { Plugin.LogWarningLimited("preset.create_dirs", "Failed to create preset directories: " + ex.Message); } } public void SaveLastUsed(ProfileSaveData data) { try { if (data != null) { File.WriteAllText(_lastUsedPath, JsonUtility.ToJson((object)data, true)); } } catch (Exception ex) { Plugin.LogWarningLimited("preset.save_last_used", "Failed to save last-used settings: " + ex.Message); } } public ProfileSaveData LoadLastUsed() { try { if (!File.Exists(_lastUsedPath)) { return null; } string text = File.ReadAllText(_lastUsedPath); if (string.IsNullOrWhiteSpace(text)) { return null; } return JsonUtility.FromJson(text); } catch (Exception ex) { Plugin.LogWarningLimited("preset.load_last_used", "Failed to load last-used settings: " + ex.Message); return null; } } public void SavePreset(string name, ProfileSaveData data) { try { if (data != null) { string presetPath = GetPresetPath(name); File.WriteAllText(presetPath, JsonUtility.ToJson((object)data, true)); } } catch (Exception ex) { Plugin.LogWarningLimited("preset.save." + name, "Failed to save preset '" + name + "': " + ex.Message); } } public ProfileSaveData LoadPreset(string name) { try { string presetPath = GetPresetPath(name); if (!File.Exists(presetPath)) { return null; } string text = File.ReadAllText(presetPath); if (string.IsNullOrWhiteSpace(text)) { return null; } return JsonUtility.FromJson(text); } catch (Exception ex) { Plugin.LogWarningLimited("preset.load." + name, "Failed to load preset '" + name + "': " + ex.Message); return null; } } public void DeletePreset(string name) { try { string presetPath = GetPresetPath(name); if (File.Exists(presetPath)) { File.Delete(presetPath); } } catch (Exception ex) { Plugin.LogWarningLimited("preset.delete." + name, "Failed to delete preset '" + name + "': " + ex.Message); } } public string[] GetPresetNames() { try { if (!Directory.Exists(_presetsDir)) { return Array.Empty(); } return (from f in Directory.GetFiles(_presetsDir, "*.json") select Path.GetFileNameWithoutExtension(f)).OrderBy((string n) => n, StringComparer.OrdinalIgnoreCase).ToArray(); } catch (Exception ex) { Plugin.LogWarningLimited("preset.enumerate", "Failed to enumerate presets: " + ex.Message); return Array.Empty(); } } private string GetPresetPath(string name) { if (string.IsNullOrWhiteSpace(name)) { name = "Preset"; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { name = name.Replace(oldChar, '_'); } return Path.Combine(_presetsDir, name + ".json"); } public CharacterSettingsEntry LoadCharacterSettings(int slotIndex) { try { if (slotIndex < 0) { return null; } CharacterSettingsEntry characterSettingsEntry = LoadCharacterSettingsFromCharacterFiles(slotIndex); if (HasSettingsPayload(characterSettingsEntry)) { return characterSettingsEntry; } characterSettingsEntry = LoadCharacterSettingsFromLegacyStore(slotIndex); if (HasSettingsPayload(characterSettingsEntry)) { return characterSettingsEntry; } } catch (Exception ex) { Plugin.LogWarningLimited("preset.load_character." + slotIndex, "Failed to load character shlong settings: " + ex.Message); } return null; } public ProfileSaveData LoadCharacterLastUsed(int slotIndex) { return LoadCharacterSettings(slotIndex)?.LastUsed; } public Dictionary LoadCharacterPerPresetSettings(int slotIndex) { CharacterSettingsEntry entry = LoadCharacterSettings(slotIndex); return ExtractPerPresetSettings(entry); } public Dictionary ExtractPerPresetSettings(CharacterSettingsEntry entry) { Dictionary dictionary = new Dictionary(); if (entry == null || entry.PerPresetEntries == null) { return dictionary; } for (int i = 0; i < entry.PerPresetEntries.Length; i++) { PerPresetSettingsEntry perPresetSettingsEntry = entry.PerPresetEntries[i]; if (perPresetSettingsEntry != null && perPresetSettingsEntry.PresetIndex >= 0) { dictionary[perPresetSettingsEntry.PresetIndex] = perPresetSettingsEntry.Settings; } } return dictionary; } public void SaveCharacterSettings(int slotIndex, string characterName, string raceTag, ProfileSaveData lastUsed, Dictionary memory) { try { if (slotIndex < 0) { return; } bool flag = memory != null && memory.Count > 0; if (lastUsed == null && !flag) { Plugin.LogWarningLimited("preset.save_character.empty_payload." + slotIndex, "Skipped writing character shlong settings for slot " + slotIndex + " because both LastUsed and PerPresetEntries were empty. Existing data was left untouched."); return; } if (!Directory.Exists(_charactersDir)) { Directory.CreateDirectory(_charactersDir); } CharacterSettingsEntry characterSettingsEntry = LoadCharacterMetadataFromCharacterFiles(slotIndex); int characterSelectPreviewMode = ((characterSettingsEntry != null) ? NormalizeCharacterSelectPreviewMode(characterSettingsEntry.CharacterSelectPreviewMode) : 0); CharacterSettingsEntry entry = new CharacterSettingsEntry { SlotIndex = slotIndex, CharacterName = ((!string.IsNullOrWhiteSpace(characterName)) ? characterName.Trim() : ((!string.IsNullOrWhiteSpace(characterSettingsEntry?.CharacterName)) ? characterSettingsEntry.CharacterName : ("Slot " + slotIndex))), RaceTag = ((!string.IsNullOrWhiteSpace(raceTag)) ? raceTag : ((characterSettingsEntry != null) ? (characterSettingsEntry.RaceTag ?? string.Empty) : string.Empty)), CharacterSelectPreviewMode = characterSelectPreviewMode, LastUsed = lastUsed, PerPresetEntries = BuildPerPresetEntries(memory) }; string characterFilePath = GetCharacterFilePath(entry); DeleteOtherCharacterFilesForSlot(slotIndex, characterFilePath); CharacterSettingsFile characterSettingsFile = ToDiskFile(entry); string text = JsonUtility.ToJson((object)characterSettingsFile, true); if (string.IsNullOrWhiteSpace(text) || text.Trim() == "{}") { Plugin.LogWarningLimited("preset.save_character.empty_json." + slotIndex, "Character shlong settings serialized to an empty JSON object for slot " + slotIndex + ". The file was not overwritten to avoid data loss."); } else { File.WriteAllText(characterFilePath, text); } } catch (Exception ex) { Plugin.LogWarningLimited("preset.save_character." + slotIndex, "Failed to save character shlong settings: " + ex.Message); } } public int LoadCharacterSelectPreviewMode(int slotIndex) { try { if (slotIndex < 0) { return 0; } CharacterSettingsEntry characterSettingsEntry = LoadCharacterMetadataFromCharacterFiles(slotIndex); if (characterSettingsEntry != null) { return NormalizeCharacterSelectPreviewMode(characterSettingsEntry.CharacterSelectPreviewMode); } characterSettingsEntry = LoadCharacterSettingsFromLegacyStore(slotIndex); if (characterSettingsEntry != null) { return NormalizeCharacterSelectPreviewMode(characterSettingsEntry.CharacterSelectPreviewMode); } } catch (Exception ex) { Plugin.LogWarningLimited("preset.load_character_preview_mode." + slotIndex, "Failed to load character select preview mode: " + ex.Message); } return 0; } public void SaveCharacterSelectPreviewMode(int slotIndex, string characterName, string raceTag, int mode) { try { if (slotIndex >= 0) { if (!Directory.Exists(_charactersDir)) { Directory.CreateDirectory(_charactersDir); } mode = NormalizeCharacterSelectPreviewMode(mode); CharacterSettingsEntry characterSettingsEntry = LoadCharacterMetadataFromCharacterFiles(slotIndex); Dictionary memory = ExtractPerPresetSettings(characterSettingsEntry); CharacterSettingsEntry entry = new CharacterSettingsEntry { SlotIndex = slotIndex, CharacterName = ((!string.IsNullOrWhiteSpace(characterName)) ? characterName.Trim() : ((!string.IsNullOrWhiteSpace(characterSettingsEntry?.CharacterName)) ? characterSettingsEntry.CharacterName : ("Slot " + slotIndex))), RaceTag = ((!string.IsNullOrWhiteSpace(raceTag)) ? raceTag : ((characterSettingsEntry != null) ? (characterSettingsEntry.RaceTag ?? string.Empty) : string.Empty)), CharacterSelectPreviewMode = mode, LastUsed = characterSettingsEntry?.LastUsed, PerPresetEntries = BuildPerPresetEntries(memory) }; string characterFilePath = GetCharacterFilePath(entry); DeleteOtherCharacterFilesForSlot(slotIndex, characterFilePath); CharacterSettingsFile characterSettingsFile = ToDiskFile(entry); string text = JsonUtility.ToJson((object)characterSettingsFile, true); if (!string.IsNullOrWhiteSpace(text) && !(text.Trim() == "{}")) { File.WriteAllText(characterFilePath, text); } } } catch (Exception ex) { Plugin.LogWarningLimited("preset.save_character_preview_mode." + slotIndex, "Failed to save character select preview mode: " + ex.Message); } } private static PerPresetSettingsEntry[] BuildPerPresetEntries(Dictionary memory) { if (memory == null || memory.Count == 0) { return Array.Empty(); } List list = new List(); foreach (KeyValuePair item in memory) { if (item.Key >= 0) { list.Add(new PerPresetSettingsEntry { PresetIndex = item.Key, PresetId = GetPresetIdSafe(item.Key), Settings = item.Value }); } } list.Sort(delegate(PerPresetSettingsEntry a, PerPresetSettingsEntry b) { int num = a?.PresetIndex ?? int.MaxValue; int value = b?.PresetIndex ?? int.MaxValue; return num.CompareTo(value); }); return list.ToArray(); } private CharacterSettingsEntry LoadCharacterSettingsFromCharacterFiles(int slotIndex) { return LoadCharacterSettingsFromCharacterFiles(slotIndex, requirePayload: true); } private CharacterSettingsEntry LoadCharacterMetadataFromCharacterFiles(int slotIndex) { return LoadCharacterSettingsFromCharacterFiles(slotIndex, requirePayload: false); } private CharacterSettingsEntry LoadCharacterSettingsFromCharacterFiles(int slotIndex, bool requirePayload) { if (!Directory.Exists(_charactersDir)) { return null; } string[] array; try { array = (from f in Directory.GetFiles(_charactersDir, "*.json", SearchOption.TopDirectoryOnly) orderby File.GetLastWriteTimeUtc(f) descending select f).ToArray(); } catch (Exception ex) { Plugin.LogWarningLimited("preset.character_dir_enumerate", "Failed to enumerate character shlong setting files: " + ex.Message); return null; } CharacterSettingsEntry characterSettingsEntry = null; for (int num = 0; num < array.Length; num++) { CharacterSettingsEntry characterSettingsEntry2 = ReadCharacterSettingsFile(array[num]); if (characterSettingsEntry2 != null && characterSettingsEntry2.SlotIndex == slotIndex) { if (HasSettingsPayload(characterSettingsEntry2)) { return characterSettingsEntry2; } if (characterSettingsEntry == null) { characterSettingsEntry = characterSettingsEntry2; } } } return requirePayload ? null : characterSettingsEntry; } private CharacterSettingsEntry ReadCharacterSettingsFile(string path) { try { if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return null; } string text = File.ReadAllText(path); if (string.IsNullOrWhiteSpace(text)) { return null; } CharacterSettingsFile file = JsonUtility.FromJson(text); CharacterSettingsEntry characterSettingsEntry = FromDiskFile(file); if (characterSettingsEntry != null) { return characterSettingsEntry; } CharacterSettingsEntry characterSettingsEntry2 = JsonUtility.FromJson(text); if (characterSettingsEntry2 != null && (characterSettingsEntry2.SlotIndex >= 0 || !string.IsNullOrWhiteSpace(characterSettingsEntry2.CharacterName) || !string.IsNullOrWhiteSpace(characterSettingsEntry2.RaceTag))) { return characterSettingsEntry2; } } catch (Exception ex) { Plugin.LogWarningLimited("preset.character_file_read." + Path.GetFileNameWithoutExtension(path), "Failed to read character shlong setting file '" + Path.GetFileName(path) + "': " + ex.Message); } return null; } private string GetCharacterFilePath(CharacterSettingsEntry entry) { string text = entry?.CharacterName; if (string.IsNullOrWhiteSpace(text)) { text = "Slot " + (entry?.SlotIndex ?? 0); } string text2 = SanitizeFileName(text.Trim()); if (string.IsNullOrWhiteSpace(text2)) { text2 = "Slot " + (entry?.SlotIndex ?? 0); } string text3 = Path.Combine(_charactersDir, text2 + ".json"); if (File.Exists(text3)) { CharacterSettingsEntry characterSettingsEntry = ReadCharacterSettingsFile(text3); if (characterSettingsEntry != null && entry != null && characterSettingsEntry.SlotIndex != entry.SlotIndex) { text3 = Path.Combine(_charactersDir, text2 + "_Slot" + entry.SlotIndex + ".json"); } } return text3; } private void DeleteOtherCharacterFilesForSlot(int slotIndex, string keepPath) { try { if (!Directory.Exists(_charactersDir)) { return; } string text = SafeFullPath(keepPath); string[] files = Directory.GetFiles(_charactersDir, "*.json", SearchOption.TopDirectoryOnly); foreach (string path in files) { string a = SafeFullPath(path); if (string.IsNullOrEmpty(text) || !string.Equals(a, text, StringComparison.OrdinalIgnoreCase)) { CharacterSettingsEntry characterSettingsEntry = ReadCharacterSettingsFile(path); if (characterSettingsEntry != null && characterSettingsEntry.SlotIndex == slotIndex) { File.Delete(path); } } } } catch (Exception ex) { Plugin.LogWarningLimited("preset.character_cleanup." + slotIndex, "Failed to clean old character shlong setting files for slot " + slotIndex + ": " + ex.Message); } } public static int NormalizeCharacterSelectPreviewMode(int mode) { return mode switch { 1 => 1, 2 => 2, _ => 0, }; } public static string FormatCharacterSelectPreviewMode(int mode) { mode = NormalizeCharacterSelectPreviewMode(mode); return mode switch { 1 => "Show", 2 => "Hide", _ => "Use Global", }; } private static string SafeFullPath(string path) { try { if (string.IsNullOrEmpty(path)) { return string.Empty; } return Path.GetFullPath(path); } catch { return path ?? string.Empty; } } private static string SanitizeFileName(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } string text = name; char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { text = text.Replace(oldChar, '_'); } text = text.Trim().Trim('.'); if (text.Length > 80) { text = text.Substring(0, 80).Trim(); } return text; } private static bool HasSettingsPayload(CharacterSettingsEntry entry) { if (entry == null) { return false; } if (entry.LastUsed != null) { return true; } return entry.PerPresetEntries != null && entry.PerPresetEntries.Length != 0; } private void TryMigrateLegacyCharactersJson() { try { if (!File.Exists(_legacyCharactersPath)) { return; } string text = File.ReadAllText(_legacyCharactersPath); if (string.IsNullOrWhiteSpace(text) || text.Trim() == "{}") { File.Delete(_legacyCharactersPath); return; } CharacterSettingsStore characterSettingsStore = JsonUtility.FromJson(text); if (characterSettingsStore == null || characterSettingsStore.Characters == null || characterSettingsStore.Characters.Length == 0) { string text2 = Path.Combine(_baseDir, "Characters.invalid_legacy.json"); if (File.Exists(text2)) { File.Delete(text2); } File.Move(_legacyCharactersPath, text2); return; } for (int i = 0; i < characterSettingsStore.Characters.Length; i++) { CharacterSettingsEntry characterSettingsEntry = characterSettingsStore.Characters[i]; if (!HasSettingsPayload(characterSettingsEntry)) { continue; } if (characterSettingsEntry.LastUsed != null && characterSettingsEntry.LastUsed.TextureSourceContractVersion < 1) { characterSettingsEntry.LastUsed.TextureSourceMode = 0; characterSettingsEntry.LastUsed.BallTextureSourceMode = 0; } if (characterSettingsEntry.PerPresetEntries != null) { for (int j = 0; j < characterSettingsEntry.PerPresetEntries.Length; j++) { PerPresetSettingsEntry perPresetSettingsEntry = characterSettingsEntry.PerPresetEntries[j]; if (perPresetSettingsEntry != null) { PresetSettings settings = perPresetSettingsEntry.Settings; settings.TextureSourceMode = 0; settings.BallTextureSourceMode = 0; perPresetSettingsEntry.Settings = settings; } } } SaveCharacterSettings(characterSettingsEntry.SlotIndex, characterSettingsEntry.CharacterName, characterSettingsEntry.RaceTag, characterSettingsEntry.LastUsed, ExtractPerPresetSettings(characterSettingsEntry)); } string text3 = Path.Combine(_baseDir, "Characters.legacy.json"); if (File.Exists(text3)) { File.Delete(text3); } File.Move(_legacyCharactersPath, text3); } catch (Exception ex) { Plugin.LogWarningLimited("preset.character_migrate", "Failed to migrate legacy Characters.json: " + ex.Message); } } private CharacterSettingsEntry LoadCharacterSettingsFromLegacyStore(int slotIndex) { try { if (!File.Exists(_legacyCharactersPath)) { return null; } string text = File.ReadAllText(_legacyCharactersPath); if (string.IsNullOrWhiteSpace(text) || text.Trim() == "{}") { return null; } CharacterSettingsStore characterSettingsStore = JsonUtility.FromJson(text); if (characterSettingsStore == null || characterSettingsStore.Characters == null) { return null; } for (int i = 0; i < characterSettingsStore.Characters.Length; i++) { CharacterSettingsEntry characterSettingsEntry = characterSettingsStore.Characters[i]; if (characterSettingsEntry == null || characterSettingsEntry.SlotIndex != slotIndex || !HasSettingsPayload(characterSettingsEntry)) { continue; } if (characterSettingsEntry.LastUsed != null && characterSettingsEntry.LastUsed.TextureSourceContractVersion < 1) { characterSettingsEntry.LastUsed.TextureSourceMode = 0; characterSettingsEntry.LastUsed.BallTextureSourceMode = 0; } if (characterSettingsEntry.PerPresetEntries != null) { for (int j = 0; j < characterSettingsEntry.PerPresetEntries.Length; j++) { PerPresetSettingsEntry perPresetSettingsEntry = characterSettingsEntry.PerPresetEntries[j]; if (perPresetSettingsEntry != null) { PresetSettings settings = perPresetSettingsEntry.Settings; settings.TextureSourceMode = 0; settings.BallTextureSourceMode = 0; perPresetSettingsEntry.Settings = settings; } } } return characterSettingsEntry; } } catch (Exception ex) { Plugin.LogWarningLimited("preset.character_legacy_load." + slotIndex, "Failed to load legacy Characters.json entry for slot " + slotIndex + ": " + ex.Message); } return null; } public void SavePerPresetSettings(Dictionary memory) { try { PerPresetSettingsStore perPresetSettingsStore = new PerPresetSettingsStore { SchemaVersion = 1, Entries = BuildPerPresetEntries(memory) }; File.WriteAllText(_perPresetPath, JsonUtility.ToJson((object)perPresetSettingsStore, true)); } catch (Exception ex) { Plugin.LogWarningLimited("preset.save_per_preset", "Failed to save per-preset settings: " + ex.Message); } } public Dictionary LoadPerPresetSettings() { Dictionary dictionary = new Dictionary(); try { if (!File.Exists(_perPresetPath)) { return dictionary; } string text = File.ReadAllText(_perPresetPath); if (string.IsNullOrWhiteSpace(text)) { return dictionary; } PerPresetSettingsStore perPresetSettingsStore = JsonUtility.FromJson(text); if (perPresetSettingsStore?.Entries == null) { return dictionary; } for (int i = 0; i < perPresetSettingsStore.Entries.Length; i++) { PerPresetSettingsEntry perPresetSettingsEntry = perPresetSettingsStore.Entries[i]; if (perPresetSettingsEntry != null && perPresetSettingsEntry.PresetIndex >= 0) { PresetSettings value = NormalizeBulgeSettings(perPresetSettingsEntry.Settings); if (perPresetSettingsStore.SchemaVersion < 1) { value.TextureSourceMode = 0; value.BallTextureSourceMode = 0; } else { value.TextureSourceMode = ShlongController.NormalizeTextureSourceMode(value.TextureSourceMode); value.BallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(value.BallTextureSourceMode); } dictionary[perPresetSettingsEntry.PresetIndex] = value; } } } catch (Exception ex) { Plugin.LogWarningLimited("preset.load_per_preset", "Failed to load per-preset settings: " + ex.Message); } return dictionary; } private static PresetSettings NormalizeBulgeSettings(PresetSettings settings) { settings.BulgeAmount = Mathf.Clamp(settings.BulgeAmount, 0f, 100f); settings.BulgePosition = Mathf.Clamp(settings.BulgePosition, 0f, 6f); if (settings.BulgeWidth <= 0.001f) { settings.BulgeWidth = 1f; } if (settings.BulgeSharpness <= 0.001f) { settings.BulgeSharpness = 1f; } if (settings.BulgeLerpSpeed <= 0.001f) { settings.BulgeLerpSpeed = 2f; } return settings; } public static ProfileSaveData CaptureFromController(ShlongController sc) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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) if ((Object)(object)sc == (Object)null) { return null; } return new ProfileSaveData { DickNumber = sc.PresetIndex, DickOffsetX = sc.PositionOffset.x, DickOffsetY = sc.PositionOffset.y, BallsSizeOffset = sc.BallsSizeOffset, FutaToggle = sc.FutaToggle, ClothingOverride = sc.ClothingOverride, HideToggle = sc.HideToggle, SizeOffset = sc.ScaleOffset.z, AngleOffset = sc.BaseRotation, ErectAngle = sc.ErectAngleOffset, ScaleOffset = sc.ScaleOffset, ColorR = sc.ColorTint.r, ColorG = sc.ColorTint.g, ColorB = sc.ColorTint.b, ColorMode = sc.ColorMode, MatchBody = sc.MatchBody, TextureSourceContractVersion = 1, TextureSourceMode = ShlongController.NormalizeTextureSourceMode(sc.TextureSourceMode), ArousalLerpSpeed = sc.ArousalLerpSpeed, BulgeAmount = sc.BulgeAmount, BulgePosition = sc.BulgePosition, BulgeWidth = sc.BulgeWidth, BulgeSharpness = sc.BulgeSharpness, BulgeLerpSpeed = sc.BulgeLerpSpeed, BallColorR = sc.BallColorTint.r, BallColorG = sc.BallColorTint.g, BallColorB = sc.BallColorTint.b, BallColorMode = sc.BallColorMode, BallMatchBody = sc.BallMatchBody, BallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(sc.BallTextureSourceMode) }; } private static string GetPresetIdSafe(int presetIndex) { try { PresetData presetData = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(presetIndex) : null); return (presetData != null && !string.IsNullOrEmpty(presetData.Id)) ? presetData.Id : string.Empty; } catch { return string.Empty; } } private static CharacterSettingsFile ToDiskFile(CharacterSettingsEntry entry) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) CharacterSettingsFile characterSettingsFile = new CharacterSettingsFile { SchemaVersion = 5, SlotIndex = (entry?.SlotIndex ?? (-1)), CharacterName = ((entry != null) ? (entry.CharacterName ?? string.Empty) : string.Empty), RaceTag = ((entry != null) ? (entry.RaceTag ?? string.Empty) : string.Empty), CharacterSelectPreviewMode = NormalizeCharacterSelectPreviewMode(entry?.CharacterSelectPreviewMode ?? 0), PerPresetEntries = ToDiskPresetEntries(entry?.PerPresetEntries) }; if (entry != null && entry.LastUsed != null) { ProfileSaveData lastUsed = entry.LastUsed; characterSettingsFile.HasLastUsed = true; characterSettingsFile.Last_DickNumber = lastUsed.DickNumber; characterSettingsFile.Last_DickOffsetX = lastUsed.DickOffsetX; characterSettingsFile.Last_DickOffsetY = lastUsed.DickOffsetY; characterSettingsFile.Last_BallsSizeOffset = lastUsed.BallsSizeOffset; characterSettingsFile.Last_FutaToggle = lastUsed.FutaToggle; characterSettingsFile.Last_ClothingOverride = lastUsed.ClothingOverride; characterSettingsFile.Last_HideToggle = lastUsed.HideToggle; characterSettingsFile.Last_SizeOffset = lastUsed.SizeOffset; characterSettingsFile.Last_AngleOffset = lastUsed.AngleOffset; characterSettingsFile.Last_ErectAngle = lastUsed.ErectAngle; characterSettingsFile.Last_ScaleOffset = lastUsed.ScaleOffset; characterSettingsFile.Last_ColorR = lastUsed.ColorR; characterSettingsFile.Last_ColorG = lastUsed.ColorG; characterSettingsFile.Last_ColorB = lastUsed.ColorB; characterSettingsFile.Last_ColorMode = lastUsed.ColorMode; characterSettingsFile.Last_MatchBody = lastUsed.MatchBody; characterSettingsFile.Last_TextureSourceMode = ShlongController.NormalizeTextureSourceMode(lastUsed.TextureSourceMode); characterSettingsFile.Last_ArousalLerpSpeed = lastUsed.ArousalLerpSpeed; characterSettingsFile.Last_BulgeAmount = lastUsed.BulgeAmount; characterSettingsFile.Last_BulgePosition = lastUsed.BulgePosition; characterSettingsFile.Last_BulgeWidth = ((lastUsed.BulgeWidth > 0.001f) ? lastUsed.BulgeWidth : 1f); characterSettingsFile.Last_BulgeSharpness = ((lastUsed.BulgeSharpness > 0.001f) ? lastUsed.BulgeSharpness : 1f); characterSettingsFile.Last_BulgeLerpSpeed = ((lastUsed.BulgeLerpSpeed > 0.001f) ? lastUsed.BulgeLerpSpeed : 2f); characterSettingsFile.Last_BallColorR = lastUsed.BallColorR; characterSettingsFile.Last_BallColorG = lastUsed.BallColorG; characterSettingsFile.Last_BallColorB = lastUsed.BallColorB; characterSettingsFile.Last_BallColorMode = lastUsed.BallColorMode; characterSettingsFile.Last_BallMatchBody = lastUsed.BallMatchBody; characterSettingsFile.Last_BallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(lastUsed.BallTextureSourceMode); } return characterSettingsFile; } private static CharacterSettingsEntry FromDiskFile(CharacterSettingsFile file) { if (file == null) { return null; } if (file.SchemaVersion <= 0 && string.IsNullOrWhiteSpace(file.CharacterName) && string.IsNullOrWhiteSpace(file.RaceTag) && file.SlotIndex == 0 && !file.HasLastUsed && (file.PerPresetEntries == null || file.PerPresetEntries.Length == 0)) { return null; } return new CharacterSettingsEntry { SlotIndex = file.SlotIndex, CharacterName = (file.CharacterName ?? string.Empty), RaceTag = (file.RaceTag ?? string.Empty), CharacterSelectPreviewMode = NormalizeCharacterSelectPreviewMode(file.CharacterSelectPreviewMode), LastUsed = (file.HasLastUsed ? ProfileFromDiskFile(file) : null), PerPresetEntries = FromDiskPresetEntries(file.PerPresetEntries, file.SchemaVersion) }; } private static ProfileSaveData ProfileFromDiskFile(CharacterSettingsFile file) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) bool clothingOverride = file.Last_ClothingOverride; if (file.SchemaVersion < 4 && file.PerPresetEntries != null) { for (int i = 0; i < file.PerPresetEntries.Length; i++) { CharacterPresetSettingsFileEntry characterPresetSettingsFileEntry = file.PerPresetEntries[i]; if (characterPresetSettingsFileEntry != null && characterPresetSettingsFileEntry.PresetIndex == file.Last_DickNumber) { clothingOverride = characterPresetSettingsFileEntry.ClothingOverride; break; } } } return new ProfileSaveData { DickNumber = file.Last_DickNumber, DickOffsetX = file.Last_DickOffsetX, DickOffsetY = file.Last_DickOffsetY, BallsSizeOffset = file.Last_BallsSizeOffset, FutaToggle = file.Last_FutaToggle, ClothingOverride = clothingOverride, HideToggle = file.Last_HideToggle, SizeOffset = file.Last_SizeOffset, AngleOffset = file.Last_AngleOffset, ErectAngle = file.Last_ErectAngle, ScaleOffset = file.Last_ScaleOffset, ColorR = file.Last_ColorR, ColorG = file.Last_ColorG, ColorB = file.Last_ColorB, ColorMode = file.Last_ColorMode, MatchBody = file.Last_MatchBody, TextureSourceContractVersion = ((file.SchemaVersion >= 5) ? 1 : 0), TextureSourceMode = ((file.SchemaVersion >= 5) ? ShlongController.NormalizeTextureSourceMode(file.Last_TextureSourceMode) : 0), ArousalLerpSpeed = file.Last_ArousalLerpSpeed, BulgeAmount = ((file.SchemaVersion >= 5) ? file.Last_BulgeAmount : 0f), BulgePosition = ((file.SchemaVersion >= 5) ? file.Last_BulgePosition : 0f), BulgeWidth = ((file.SchemaVersion >= 5 && file.Last_BulgeWidth > 0.001f) ? file.Last_BulgeWidth : 1f), BulgeSharpness = ((file.SchemaVersion >= 5 && file.Last_BulgeSharpness > 0.001f) ? file.Last_BulgeSharpness : 1f), BulgeLerpSpeed = ((file.SchemaVersion >= 5 && file.Last_BulgeLerpSpeed > 0.001f) ? file.Last_BulgeLerpSpeed : 2f), BallColorR = file.Last_BallColorR, BallColorG = file.Last_BallColorG, BallColorB = file.Last_BallColorB, BallColorMode = file.Last_BallColorMode, BallMatchBody = file.Last_BallMatchBody, BallTextureSourceMode = ((file.SchemaVersion >= 5) ? ShlongController.NormalizeTextureSourceMode(file.Last_BallTextureSourceMode) : 0) }; } private static CharacterPresetSettingsFileEntry[] ToDiskPresetEntries(PerPresetSettingsEntry[] entries) { //IL_007f: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) if (entries == null || entries.Length == 0) { return Array.Empty(); } List list = new List(); foreach (PerPresetSettingsEntry perPresetSettingsEntry in entries) { if (perPresetSettingsEntry != null && perPresetSettingsEntry.PresetIndex >= 0) { PresetSettings settings = perPresetSettingsEntry.Settings; list.Add(new CharacterPresetSettingsFileEntry { PresetIndex = perPresetSettingsEntry.PresetIndex, PresetId = (perPresetSettingsEntry.PresetId ?? string.Empty), ScaleOffset = settings.ScaleOffset, BallsSizeOffset = settings.BallsSizeOffset, PositionOffset = settings.PositionOffset, BaseRotation = settings.BaseRotation, ErectAngleOffset = settings.ErectAngleOffset, ArousalTarget = settings.ArousalTarget, BulgeAmount = settings.BulgeAmount, BulgePosition = settings.BulgePosition, BulgeWidth = ((settings.BulgeWidth > 0.001f) ? settings.BulgeWidth : 1f), BulgeSharpness = ((settings.BulgeSharpness > 0.001f) ? settings.BulgeSharpness : 1f), BulgeLerpSpeed = ((settings.BulgeLerpSpeed > 0.001f) ? settings.BulgeLerpSpeed : 2f), ColorTint = settings.ColorTint, ColorMode = settings.ColorMode, MatchBody = settings.MatchBody, TextureSourceMode = ShlongController.NormalizeTextureSourceMode(settings.TextureSourceMode), BallColorTint = settings.BallColorTint, BallColorMode = settings.BallColorMode, BallMatchBody = settings.BallMatchBody, BallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(settings.BallTextureSourceMode), FutaToggle = settings.FutaToggle, ClothingOverride = settings.ClothingOverride, HideToggle = settings.HideToggle }); } } return list.ToArray(); } private static PerPresetSettingsEntry[] FromDiskPresetEntries(CharacterPresetSettingsFileEntry[] entries, int schemaVersion) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) if (entries == null || entries.Length == 0) { return Array.Empty(); } List list = new List(); foreach (CharacterPresetSettingsFileEntry characterPresetSettingsFileEntry in entries) { if (characterPresetSettingsFileEntry != null && characterPresetSettingsFileEntry.PresetIndex >= 0) { list.Add(new PerPresetSettingsEntry { PresetIndex = characterPresetSettingsFileEntry.PresetIndex, PresetId = (characterPresetSettingsFileEntry.PresetId ?? string.Empty), Settings = new PresetSettings { ScaleOffset = characterPresetSettingsFileEntry.ScaleOffset, BallsSizeOffset = characterPresetSettingsFileEntry.BallsSizeOffset, PositionOffset = characterPresetSettingsFileEntry.PositionOffset, BaseRotation = characterPresetSettingsFileEntry.BaseRotation, ErectAngleOffset = characterPresetSettingsFileEntry.ErectAngleOffset, ArousalTarget = characterPresetSettingsFileEntry.ArousalTarget, BulgeAmount = ((schemaVersion >= 5) ? characterPresetSettingsFileEntry.BulgeAmount : 0f), BulgePosition = ((schemaVersion >= 5) ? characterPresetSettingsFileEntry.BulgePosition : 0f), BulgeWidth = ((schemaVersion >= 5 && characterPresetSettingsFileEntry.BulgeWidth > 0.001f) ? characterPresetSettingsFileEntry.BulgeWidth : 1f), BulgeSharpness = ((schemaVersion >= 5 && characterPresetSettingsFileEntry.BulgeSharpness > 0.001f) ? characterPresetSettingsFileEntry.BulgeSharpness : 1f), BulgeLerpSpeed = ((schemaVersion >= 5 && characterPresetSettingsFileEntry.BulgeLerpSpeed > 0.001f) ? characterPresetSettingsFileEntry.BulgeLerpSpeed : 2f), ColorTint = characterPresetSettingsFileEntry.ColorTint, ColorMode = characterPresetSettingsFileEntry.ColorMode, MatchBody = characterPresetSettingsFileEntry.MatchBody, TextureSourceMode = ((schemaVersion >= 5) ? ShlongController.NormalizeTextureSourceMode(characterPresetSettingsFileEntry.TextureSourceMode) : 0), BallColorTint = characterPresetSettingsFileEntry.BallColorTint, BallColorMode = characterPresetSettingsFileEntry.BallColorMode, BallMatchBody = characterPresetSettingsFileEntry.BallMatchBody, BallTextureSourceMode = ((schemaVersion >= 5) ? ShlongController.NormalizeTextureSourceMode(characterPresetSettingsFileEntry.BallTextureSourceMode) : 0), FutaToggle = characterPresetSettingsFileEntry.FutaToggle, ClothingOverride = characterPresetSettingsFileEntry.ClothingOverride, HideToggle = characterPresetSettingsFileEntry.HideToggle } }); } } return list.ToArray(); } } } namespace AtlyssShlongs.Core { public class AssetManager { private class TextureCandidateDiag { internal Texture2D Texture; internal int Score; internal bool Viable; internal bool Utility; } private AssetBundle _mainBundle; private AssetBundle _testBundle; private string _mainBundlePath; private string _testBundlePath; private Texture2D[] _mainBundleTextures; private Texture2D[] _testBundleTextures; private readonly ManualLogSource _log; public const string TestBundleFileName = "ShlongsPackage_test.unity3d"; public bool HasTestBundle => (Object)(object)_testBundle != (Object)null; public string TestBundlePath => _testBundlePath; public string MainBundlePath => _mainBundlePath; public bool HasExactTestBundleFile { get { if ((Object)(object)_testBundle == (Object)null) { return false; } if (string.IsNullOrEmpty(_testBundlePath)) { return false; } return string.Equals(Path.GetFileName(_testBundlePath), "ShlongsPackage_test.unity3d", StringComparison.OrdinalIgnoreCase); } } public AssetManager(ManualLogSource log) { _log = log; } public bool LoadBundle(string pluginLocation) { string text = FindBundlePath(pluginLocation, "ShlongsPackage.unity3d"); if (text == null) { _log.LogError((object)("ShlongsPackage.unity3d not found near: " + pluginLocation)); return false; } _mainBundle = AssetBundle.LoadFromFile(text); if ((Object)(object)_mainBundle == (Object)null) { _log.LogError((object)("Failed to load main AssetBundle from: " + text)); return false; } _mainBundlePath = text; Plugin.LogDebug("Main AssetBundle loaded: " + text); string text2 = FindBundlePath(pluginLocation, "ShlongsPackage_test.unity3d"); if (text2 == null) { text2 = FindTestBundleAnyExtension(pluginLocation); if (text2 != null) { Plugin.LogDebug("Test AssetBundle resolved via fuzzy match: " + text2); } } if (text2 != null) { try { _testBundle = AssetBundle.LoadFromFile(text2); if ((Object)(object)_testBundle != (Object)null) { _testBundlePath = text2; Plugin.LogDebug("Test AssetBundle loaded: " + text2); } else { Plugin.LogWarningLimited("asset.test_bundle_invalid", "Failed to load test AssetBundle from: " + text2 + " (file is not a valid Unity AssetBundle)"); } } catch (Exception ex) { Plugin.LogWarningLimited("asset.test_bundle_load", "Failed to load test AssetBundle: " + ex.Message); } } else { Plugin.LogDebug("Optional test AssetBundle not found: ShlongsPackage_test.unity3d"); } return true; } public GameObject LoadPrefab(string prefabName) { if ((Object)(object)_mainBundle == (Object)null) { return null; } return _mainBundle.LoadAsset(prefabName); } public Texture2D FindBestTextureForPreset(PresetData preset) { if (preset == null) { return null; } Texture2D[] textureAssetsForPreset = GetTextureAssetsForPreset(preset); if (textureAssetsForPreset == null || textureAssetsForPreset.Length == 0) { return null; } Texture2D val = null; int num = int.MinValue; foreach (Texture2D val2 in textureAssetsForPreset) { if (!((Object)(object)val2 == (Object)null)) { int num2 = ScoreTextureForPreset(val2, preset); if (num2 > num) { num = num2; val = val2; } } } if ((Object)(object)val != (Object)null && num > 0) { return val; } return FindOnlyViableNonUtilityTexture(textureAssetsForPreset); } public string DescribeBestTextureForPreset(PresetData preset) { Texture2D val = FindBestTextureForPreset(preset); if ((Object)(object)val == (Object)null) { return ""; } return ((Object)val).name + " " + ((Texture)val).width + "x" + ((Texture)val).height; } public string DescribeTextureCandidatesForPreset(PresetData preset, int maxCount = 80) { StringBuilder stringBuilder = new StringBuilder(2048); if (preset == null) { return ""; } Texture2D[] textureAssetsForPreset = GetTextureAssetsForPreset(preset); stringBuilder.AppendLine("TextureCandidateInventory preset=" + preset.Id + " source=" + preset.AssetSource.ToString() + " bundle=" + ((preset.AssetSource == PresetAssetSource.Test) ? (_testBundlePath ?? "") : (_mainBundlePath ?? "
"))); if (textureAssetsForPreset == null) { stringBuilder.AppendLine(" textures= (LoadAllAssets failed or bundle missing)"); return stringBuilder.ToString().TrimEnd(); } stringBuilder.AppendLine(" textureCount=" + textureAssetsForPreset.Length); if (textureAssetsForPreset.Length == 0) { return stringBuilder.ToString().TrimEnd(); } List list = new List(); foreach (Texture2D val in textureAssetsForPreset) { if (!((Object)(object)val == (Object)null)) { string lower = (((Object)val).name ?? string.Empty).ToLowerInvariant(); bool viable = IsViableVisualTexture(val); bool utility = LooksLikeUtilityTextureName(lower); int score = ScoreTextureForPreset(val, preset); list.Add(new TextureCandidateDiag { Texture = val, Score = score, Viable = viable, Utility = utility }); } } list.Sort(delegate(TextureCandidateDiag a, TextureCandidateDiag b) { int num3 = b.Score.CompareTo(a.Score); if (num3 != 0) { return num3; } int value = (((Object)(object)a.Texture != (Object)null) ? (((Texture)a.Texture).width * ((Texture)a.Texture).height) : 0); return (((Object)(object)b.Texture != (Object)null) ? (((Texture)b.Texture).width * ((Texture)b.Texture).height) : 0).CompareTo(value); }); int num = Math.Min(maxCount, list.Count); for (int num2 = 0; num2 < num; num2++) { TextureCandidateDiag textureCandidateDiag = list[num2]; Texture2D texture = textureCandidateDiag.Texture; stringBuilder.AppendLine(" [" + num2 + "] score=" + textureCandidateDiag.Score + " viable=" + textureCandidateDiag.Viable + " utility=" + textureCandidateDiag.Utility + " name=" + (((Object)(object)texture != (Object)null) ? ((Object)texture).name : "") + " size=" + (((Object)(object)texture != (Object)null) ? (((Texture)texture).width + "x" + ((Texture)texture).height) : "")); } if (list.Count > num) { stringBuilder.AppendLine(" ... " + (list.Count - num) + " more texture(s) omitted"); } return stringBuilder.ToString().TrimEnd(); } private Texture2D[] GetTextureAssetsForPreset(PresetData preset) { AssetBundle bundleForPreset = GetBundleForPreset(preset); if ((Object)(object)bundleForPreset == (Object)null) { return null; } try { if ((Object)(object)bundleForPreset == (Object)(object)_testBundle) { if (_testBundleTextures == null) { _testBundleTextures = bundleForPreset.LoadAllAssets(); } return _testBundleTextures; } if ((Object)(object)bundleForPreset == (Object)(object)_mainBundle) { if (_mainBundleTextures == null) { _mainBundleTextures = bundleForPreset.LoadAllAssets(); } return _mainBundleTextures; } } catch (Exception ex) { Plugin.LogWarningLimited("asset.texture_scan." + ((preset != null) ? preset.Id : "null"), "Texture scan failed for preset " + ((preset != null) ? preset.Id : "") + ": " + ex.Message, 1); } return null; } private static Texture2D FindOnlyViableNonUtilityTexture(Texture2D[] textures) { Texture2D val = null; int num = 0; if (textures == null) { return null; } foreach (Texture2D val2 in textures) { if (!IsViableVisualTexture(val2)) { continue; } string lower = (((Object)val2).name ?? string.Empty).ToLowerInvariant(); if (!LooksLikeUtilityTextureName(lower)) { val = val2; num++; if (num > 1) { return null; } } } return (num == 1) ? val : null; } private static int ScoreTextureForPreset(Texture2D tex, PresetData preset) { if (!IsViableVisualTexture(tex) || preset == null) { return -1073741824; } string text = (((Object)tex).name ?? string.Empty).ToLowerInvariant(); if (LooksLikeUtilityTextureName(text)) { return -1000; } int score = 0; AddTokenScore(ref score, text, StripTestSuffix(preset.Id), 90); AddTokenScore(ref score, text, preset.DisplayName, 80); AddTokenScore(ref score, text, preset.FriendlyName, 80); AddTokenScore(ref score, text, preset.PrefabName, 60); AddTokenScore(ref score, text, preset.MeshName, 35); if (ContainsAny(text, "shlong", "dick", "cock", "penis", "peen", "shaft", "bodymat")) { score += 15; } if (text.IndexOf("tex", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("texture", StringComparison.OrdinalIgnoreCase) >= 0) { score += 5; } if (preset.AssetSource == PresetAssetSource.Test && ContainsAny(text, "test", "bulge", "bulgy", "updated")) { score += 10; } if (((Texture)tex).width >= 64 && ((Texture)tex).height >= 64) { score += 5; } if (((Texture)tex).width >= 256 || ((Texture)tex).height >= 256) { score += 5; } return score; } private static bool IsViableVisualTexture(Texture2D tex) { if ((Object)(object)tex == (Object)null) { return false; } string text = ((Object)tex).name ?? string.Empty; if (text.IndexOf("UnityWhite", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (text.Equals("white", StringComparison.OrdinalIgnoreCase)) { return false; } if (((Texture)tex).width <= 4 && ((Texture)tex).height <= 4) { return false; } return true; } private static bool LooksLikeUtilityTextureName(string lower) { if (string.IsNullOrEmpty(lower)) { return false; } return lower.IndexOf("normal", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("bump", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("mask", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("metal", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("rough", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("smooth", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("occlusion", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("emission", StringComparison.OrdinalIgnoreCase) >= 0 || lower.IndexOf("spec", StringComparison.OrdinalIgnoreCase) >= 0; } private static string StripTestSuffix(string text) { if (string.IsNullOrEmpty(text)) { return text; } string text2 = text; text2 = text2.Replace("_bulge_test", ""); text2 = text2.Replace(" Bulge Test", ""); text2 = text2.Replace("_Bulgy", ""); return text2.Replace("Bulgy", ""); } private static void AddTokenScore(ref int score, string haystackLower, string source, int weight) { if (string.IsNullOrEmpty(haystackLower) || string.IsNullOrEmpty(source)) { return; } string text = StripTestSuffix(source).ToLowerInvariant(); string[] array = text.Split(new char[8] { '_', '-', '.', ' ', '(', ')', '[', ']' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { if (text2.Length >= 3 && !(text2 == "test") && !(text2 == "bulge") && !(text2 == "bulgy") && haystackLower.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0) { score += weight; } } } private static bool ContainsAny(string text, params string[] tokens) { if (string.IsNullOrEmpty(text) || tokens == null) { return false; } foreach (string value in tokens) { if (!string.IsNullOrEmpty(value) && text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private AssetBundle GetBundleForPreset(PresetData preset) { if (preset == null) { return _mainBundle; } if (preset.AssetSource == PresetAssetSource.Test) { return _testBundle; } return _mainBundle; } public void LoadPresetPrefabs(PresetData[] presets) { if ((Object)(object)_mainBundle == (Object)null) { return; } for (int i = 0; i < presets.Length; i++) { AssetBundle bundleForPreset = GetBundleForPreset(presets[i]); if ((Object)(object)bundleForPreset == (Object)null) { if (presets[i].AssetSource == PresetAssetSource.Test) { Plugin.LogDebug("Skipping test preset (test bundle not loaded): " + presets[i].Id); } continue; } presets[i].LoadedPrefab = bundleForPreset.LoadAsset(presets[i].PrefabName); if ((Object)(object)presets[i].LoadedPrefab == (Object)null) { Plugin.LogWarningLimited("asset.prefab_missing." + presets[i].PrefabName, "Prefab not found: " + presets[i].PrefabName + " (source=" + (((Object)(object)bundleForPreset == (Object)(object)_testBundle) ? "TEST" : "MAIN") + ")"); continue; } Plugin.LogDebug("Loaded preset " + presets[i].Id + " from " + (((Object)(object)bundleForPreset == (Object)(object)_testBundle) ? "TEST" : "MAIN") + " bundle: " + presets[i].PrefabName); SkinnedMeshRenderer[] componentsInChildren = presets[i].LoadedPrefab.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val in componentsInChildren) { if (presets[i].AssetSource == PresetAssetSource.Test && (Object)(object)val.sharedMesh != (Object)null && val.sharedMesh.blendShapeCount > 0) { Mesh sharedMesh = val.sharedMesh; Plugin.LogDebug("[BlendShape][TestPreset:" + presets[i].Id + "] mesh=" + ((Object)sharedMesh).name + " count=" + sharedMesh.blendShapeCount); for (int k = 0; k < sharedMesh.blendShapeCount; k++) { Plugin.LogDebug("[BlendShape][TestPreset:" + presets[i].Id + "] " + k + " = " + sharedMesh.GetBlendShapeName(k)); } } } } } private string FindBundlePath(string pluginLocation, string bundleFileName) { string directoryName = Path.GetDirectoryName(pluginLocation); string text = Path.Combine(directoryName, bundleFileName); if (File.Exists(text)) { return text; } try { string[] files = Directory.GetFiles(directoryName, bundleFileName, SearchOption.TopDirectoryOnly); int num = 0; if (num < files.Length) { return files[num]; } string[] directories = Directory.GetDirectories(directoryName); foreach (string path in directories) { text = Path.Combine(path, bundleFileName); if (File.Exists(text)) { return text; } } } catch (Exception ex) { Plugin.LogWarningLimited("asset.bundle_search", "Bundle search error: " + ex.Message); } string directoryName2 = Path.GetDirectoryName(directoryName); if (directoryName2 != null) { text = Path.Combine(directoryName2, bundleFileName); if (File.Exists(text)) { return text; } } return null; } private string FindTestBundleAnyExtension(string pluginLocation) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension("ShlongsPackage_test.unity3d"); string directoryName = Path.GetDirectoryName(pluginLocation); if (string.IsNullOrEmpty(directoryName)) { return null; } string text = TryMatchInDir(directoryName, fileNameWithoutExtension); if (text != null) { return text; } try { string[] directories = Directory.GetDirectories(directoryName); foreach (string dir in directories) { text = TryMatchInDir(dir, fileNameWithoutExtension); if (text != null) { return text; } } } catch (Exception ex) { Plugin.LogWarningLimited("asset.test_bundle_search", "Test bundle fuzzy search error: " + ex.Message); } string directoryName2 = Path.GetDirectoryName(directoryName); if (!string.IsNullOrEmpty(directoryName2)) { text = TryMatchInDir(directoryName2, fileNameWithoutExtension); if (text != null) { return text; } } return null; } private static string TryMatchInDir(string dir, string baseName) { if (!Directory.Exists(dir)) { return null; } string[] files = Directory.GetFiles(dir, baseName + "*", SearchOption.TopDirectoryOnly); foreach (string text in files) { string extension = Path.GetExtension(text); if (!string.Equals(extension, ".meta", StringComparison.OrdinalIgnoreCase)) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); if (string.Equals(fileNameWithoutExtension, baseName, StringComparison.OrdinalIgnoreCase)) { return text; } } } return null; } } internal class BlendShapeDriver { public static readonly string[] BulgeBlendShapeNames = new string[7] { "Bulge_00_Balls", "Bulge_01_Sheath", "Bulge_02_Root", "Bulge_03_Base", "Bulge_04_Mid", "Bulge_05_Upper", "Bulge_06_Tip" }; private SkinnedMeshRenderer _cachedSmr; private Mesh _cachedMesh; private int _arousedIndex = -1; private bool _arousedIsLegacyFallback; private readonly int[] _bulgeIndices = new int[BulgeBlendShapeNames.Length]; private int _bulgeKeysFound; public bool HasAroused => _arousedIndex >= 0; public bool ArousedIsLegacyFallback => _arousedIsLegacyFallback; public int BulgeKeysFound => _bulgeKeysFound; public int BulgeKeyTotal => BulgeBlendShapeNames.Length; public bool HasAnyBulge => _bulgeKeysFound > 0; public void EnsureCached(SkinnedMeshRenderer smr) { if ((Object)(object)smr == (Object)null) { Reset(); return; } Mesh sharedMesh = smr.sharedMesh; if ((Object)(object)smr == (Object)(object)_cachedSmr && (Object)(object)sharedMesh == (Object)(object)_cachedMesh) { return; } _cachedSmr = smr; _cachedMesh = sharedMesh; _arousedIndex = -1; _arousedIsLegacyFallback = false; _bulgeKeysFound = 0; for (int i = 0; i < _bulgeIndices.Length; i++) { _bulgeIndices[i] = -1; } if ((Object)(object)sharedMesh == (Object)null) { return; } int blendShapeIndex = sharedMesh.GetBlendShapeIndex("Aroused"); if (blendShapeIndex >= 0) { _arousedIndex = blendShapeIndex; } else { blendShapeIndex = sharedMesh.GetBlendShapeIndex("Erect"); if (blendShapeIndex >= 0) { _arousedIndex = blendShapeIndex; _arousedIsLegacyFallback = true; } } for (int j = 0; j < BulgeBlendShapeNames.Length; j++) { int blendShapeIndex2 = sharedMesh.GetBlendShapeIndex(BulgeBlendShapeNames[j]); if (blendShapeIndex2 < 0 && j == 3) { blendShapeIndex2 = sharedMesh.GetBlendShapeIndex("Bulge_03_Sheath"); } _bulgeIndices[j] = blendShapeIndex2; if (blendShapeIndex2 >= 0) { _bulgeKeysFound++; } } } public void Reset() { _cachedSmr = null; _cachedMesh = null; _arousedIndex = -1; _arousedIsLegacyFallback = false; _bulgeKeysFound = 0; for (int i = 0; i < _bulgeIndices.Length; i++) { _bulgeIndices[i] = -1; } } public void ApplyAroused(SkinnedMeshRenderer smr, float target, float lerpSpeed) { if (!((Object)(object)smr == (Object)null)) { EnsureCached(smr); if (_arousedIndex >= 0 && !((Object)(object)smr.sharedMesh == (Object)null) && smr.sharedMesh.blendShapeCount > _arousedIndex) { target = Mathf.Clamp(target, 0f, 100f); float num = Time.deltaTime / Mathf.Max(lerpSpeed, 0.1f); float blendShapeWeight = smr.GetBlendShapeWeight(_arousedIndex); smr.SetBlendShapeWeight(_arousedIndex, Mathf.Lerp(blendShapeWeight, target, num)); } } } public void ApplyArousedImmediate(SkinnedMeshRenderer smr, float target) { if (!((Object)(object)smr == (Object)null)) { EnsureCached(smr); if (_arousedIndex >= 0 && !((Object)(object)smr.sharedMesh == (Object)null) && smr.sharedMesh.blendShapeCount > _arousedIndex) { smr.SetBlendShapeWeight(_arousedIndex, Mathf.Clamp(target, 0f, 100f)); } } } public void ApplyBulge(SkinnedMeshRenderer smr, float bulgeAmount, float bulgePosition, float bulgeWidth, float bulgeSharpness, float lerpSpeed) { if ((Object)(object)smr == (Object)null) { return; } EnsureCached(smr); if (_bulgeKeysFound == 0 || (Object)(object)smr.sharedMesh == (Object)null) { return; } float amount = Mathf.Clamp(bulgeAmount, 0f, 100f); float num = _bulgeIndices.Length - 1; float center = Mathf.Clamp(bulgePosition, 0f, num); float width = Mathf.Max(0.001f, bulgeWidth); float sharpness = Mathf.Max(0.05f, bulgeSharpness); float num2 = Time.deltaTime * Mathf.Max(lerpSpeed, 0.1f) * 0.25f; for (int i = 0; i < _bulgeIndices.Length; i++) { int num3 = _bulgeIndices[i]; if (num3 >= 0) { float num4 = CalculateBulgeTarget(i, amount, center, width, sharpness); float blendShapeWeight = smr.GetBlendShapeWeight(num3); smr.SetBlendShapeWeight(num3, Mathf.Lerp(blendShapeWeight, num4, num2)); } } } public void ApplyBulgeImmediate(SkinnedMeshRenderer smr, float bulgeAmount, float bulgePosition, float bulgeWidth, float bulgeSharpness) { if ((Object)(object)smr == (Object)null) { return; } EnsureCached(smr); if (_bulgeKeysFound == 0 || (Object)(object)smr.sharedMesh == (Object)null) { return; } float amount = Mathf.Clamp(bulgeAmount, 0f, 100f); float num = _bulgeIndices.Length - 1; float center = Mathf.Clamp(bulgePosition, 0f, num); float width = Mathf.Max(0.001f, bulgeWidth); float sharpness = Mathf.Max(0.05f, bulgeSharpness); for (int i = 0; i < _bulgeIndices.Length; i++) { int num2 = _bulgeIndices[i]; if (num2 >= 0) { float num3 = CalculateBulgeTarget(i, amount, center, width, sharpness); smr.SetBlendShapeWeight(num2, num3); } } } private static float CalculateBulgeTarget(int index, float amount, float center, float width, float sharpness) { float num = Mathf.Abs((float)index - center); if (num > width) { return 0f; } float num2 = num / width; float num3 = Mathf.Pow(Mathf.Clamp01(1f - num2), sharpness); return amount * num3; } public void ClearBulgeWeights(SkinnedMeshRenderer smr) { if ((Object)(object)smr == (Object)null) { return; } EnsureCached(smr); if (_bulgeKeysFound == 0) { return; } for (int i = 0; i < _bulgeIndices.Length; i++) { int num = _bulgeIndices[i]; if (num >= 0) { smr.SetBlendShapeWeight(num, 0f); } } } } internal static class CosmeticDisplayManager { private class ProceduralJiggleBone { internal Transform Bone; internal Quaternion BaseLocalRotation; internal Vector3 Offset; internal Vector3 Velocity; internal float Weight; internal string Name; } private class ProceduralJiggleChain { internal string Name; internal bool IsBall; internal List Bones = new List(); internal float DbDamping; internal float DbElasticity; internal float DbStiffness; internal float DbInert; } private class DisplayRig { internal GameObject DisplayRoot; internal SkinnedMeshRenderer DickMesh; internal SkinnedMeshRenderer[] Balls; internal DynamicBone[] ShaftDynamicBones; internal bool ArousalControlsShaftJiggle; internal bool ShaftJiggleStateKnown; internal bool ShaftJiggleActive; internal Transform HipBone; internal string SourceSteamId; internal string SizeBoneName; internal string BallBoneName; internal Transform CachedSizeBone; internal Transform CachedBallBone; internal bool BonesCached; internal int SpawnedPresetIndex = -1; internal int SpawnedRaceIndex = -1; internal Material OriginalBodyMaterial; internal Material[] OriginalDickMaterials; internal Dictionary OriginalMaterialsByRenderer = new Dictionary(); internal int MaterialResyncCount; internal Shader LastRaceBodyShader; internal Texture LastRaceBodyTexture; internal string LastRaceBodyAdjustmentSignature; internal Color LastColorTint; internal bool LastMatchBody = true; internal int LastColorMode; internal int LastTextureSourceMode; internal Color LastBallColorTint; internal bool LastBallMatchBody = true; internal int LastBallColorMode; internal int LastBallTextureSourceMode; internal Vector2 PositionOffset; internal Vector3 BaseRotation; internal float ErectAngleOffset; internal Vector3 ScaleOffset; internal float BallsSizeOffset; internal bool LastAppliedVisible; internal bool PendingVisible; internal float PendingVisibleSince; internal bool LastKnownNoLeggings = true; internal bool HasKnownNoLeggings; internal int ThrottledStaleConsecutiveCount; internal float PresetChangedSince = -1f; internal float TransferredAt = -1f; internal bool LastAppliedBodyVisible = true; internal bool PendingBodyVisible = true; internal float PendingBodyVisibleSince; internal BlendShapeDriver BlendShapes = new BlendShapeDriver(); internal PlayerRaceModel CachedPRM; internal Material[] TemplateDickMaterials; internal Dictionary TemplateMaterialsByRenderer = new Dictionary(); internal bool TestPresetMaterialReady = true; internal bool HasStableScaleOffset; internal Vector3 LastStableScaleOffset; internal Vector3 PendingScaleOffset; internal float PendingScaleSince = -1f; internal List JiggleChains = new List(); internal bool JiggleInitialized; internal Vector3 LastHipWorldPos; internal Quaternion LastHipWorldRot; internal bool HasLastHipPose; internal Vector3 LastDriverWorldPos; internal Quaternion LastDriverWorldRot; internal bool HasLastDriverPose; internal float LastJiggleTargetMagnitude; internal bool LastJiggleVisible; } private static readonly Dictionary _rigs = new Dictionary(); private static readonly List _removeBuffer = new List(); private static bool _needsRebuild; private static bool _frozen; private static bool _quitting; private static bool _initialized; private const int MaxCreatesPerFrame = 2; private const int ValidationCheckIntervalFrames = 15; private const float VisibilityDebounceSeconds = 0.2f; private const float PresetChangeDebounceSeconds = 0.6f; private const float ScaleZeroDebounceSeconds = 0.75f; internal static int LastJiggleTickFrame; internal static int LastNoChainsCount; internal static float LastJiggleTargetMagnitude; private static readonly string[] _jiggleBoneKeywords = new string[11] { "penis", "dick", "shaft", "peen", "sheath", "root", "base", "mid", "upper", "tip", "ball" }; private static readonly string[] _fallbackShaftKeywords = new string[4] { "penis", "dick", "peen", "shaft" }; private static readonly string[] _fallbackBallKeywords = new string[2] { "ball", "sheath" }; private static readonly string[] _fallbackExcludeKeywords = new string[4] { "armature", "root", "hip", "pelvis" }; internal static int ActiveCount => _rigs.Count; internal static bool IsActive => _rigs.Count > 0; internal static int TotalJiggleChains { get { int num = 0; foreach (KeyValuePair rig in _rigs) { if (rig.Value?.JiggleChains != null) { num += rig.Value.JiggleChains.Count; } } return num; } } internal static int TotalJiggleBones { get { int num = 0; foreach (KeyValuePair rig in _rigs) { List list = rig.Value?.JiggleChains; if (list == null) { continue; } for (int i = 0; i < list.Count; i++) { if (list[i]?.Bones != null) { num += list[i].Bones.Count; } } } return num; } } internal static int VisibleRigCount { get { int num = 0; foreach (KeyValuePair rig in _rigs) { if (rig.Value != null && rig.Value.LastAppliedVisible) { num++; } } return num; } } internal static int RigsWithJiggleChains { get { int num = 0; foreach (KeyValuePair rig in _rigs) { if (rig.Value?.JiggleChains != null && rig.Value.JiggleChains.Count > 0) { num++; } } return num; } } internal static void Initialize() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if (!_initialized) { _initialized = true; Application.quitting += OnApplicationQuit; Application.onBeforeRender += new UnityAction(UpdatePoseBeforeRender); } } private static void OnApplicationQuit() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown Application.onBeforeRender -= new UnityAction(UpdatePoseBeforeRender); _quitting = true; foreach (KeyValuePair rig in _rigs) { if ((Object)(object)rig.Value.DisplayRoot != (Object)null) { Object.DestroyImmediate((Object)(object)rig.Value.DisplayRoot); } } _rigs.Clear(); } internal static void Tick() { if (_frozen || _quitting || PluginConfig.EnableLocalCosmeticDisplay == null || !PluginConfig.EnableLocalCosmeticDisplay.Value) { return; } MapInstance val = (((Object)(object)Player._mainPlayer != (Object)null) ? Player._mainPlayer.Network_playerMapInstance : null); int num = 0; foreach (ShlongController allInstance in ShlongController.AllInstances) { if ((Object)(object)allInstance == (Object)null || allInstance.PresetIndex < 0 || !allInstance.HasPlayerParent || allInstance.HasRuntimeRig || allInstance.IsOwnerForceHidden() || _rigs.ContainsKey(allInstance)) { continue; } if (!allInstance.IsLocal && !allInstance.HasReceivedRemoteVisualState) { if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] SkipNotReady source=" + ((Object)((Component)allInstance).gameObject).name + " preset=" + allInstance.PresetIndex + " local=" + allInstance.IsLocal + " frame=" + Time.frameCount); } } else if (!((Object)(object)allInstance.PlayerObj != (Object)null) || !((Object)(object)allInstance.PlayerObj.Network_playerMapInstance != (Object)(object)val)) { if (num >= 2) { break; } if (TryCreate(allInstance)) { num++; } } } } private static bool TryCreate(ShlongController source) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) int num = source.PresetIndex; int raceIndex = source.RaceIndex; if (Plugin.Presets != null) { num = Plugin.Presets.ResolvePresetForLocalAssets(num); } if (num < 0 || Plugin.Presets == null) { return false; } SpawnResult spawnResult = ModelAttacher.SpawnCosmeticLocal(num, raceIndex, ((Component)source).transform, Plugin.Presets, Plugin.Log); if (!spawnResult.Success) { if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] Spawn failed: preset=" + num + " on " + ((Object)((Component)source).gameObject).name); } return false; } DisplayRig displayRig = new DisplayRig { DisplayRoot = spawnResult.InstanceRoot, HipBone = spawnResult.AttachBone, DickMesh = spawnResult.DickMesh, Balls = spawnResult.BallMeshes, ShaftDynamicBones = spawnResult.ShaftDynamicBones, ArousalControlsShaftJiggle = spawnResult.ArousalControlsShaftJiggle, SourceSteamId = source.GetKnownSteamId(), PositionOffset = spawnResult.InitialOffset, BaseRotation = spawnResult.InitialRotation, SpawnedPresetIndex = num, SpawnedRaceIndex = raceIndex, MaterialResyncCount = 0 }; PresetData preset = Plugin.Presets.GetPreset(num); displayRig.TestPresetMaterialReady = preset == null || preset.AssetSource != PresetAssetSource.Test; displayRig.SizeBoneName = preset?.ArmatureBone; displayRig.BallBoneName = null; if (preset != null && preset.DynamicBones != null) { for (int i = 0; i < preset.DynamicBones.Length; i++) { if (preset.DynamicBones[i] != null && preset.DynamicBones[i].Contains("Balls")) { displayRig.BallBoneName = preset.DynamicBones[i]; break; } } } displayRig.CachedPRM = source.CachedPlayerRaceModel; if ((Object)(object)displayRig.CachedPRM == (Object)null) { displayRig.CachedPRM = ((Component)source).GetComponent(); } if (spawnResult.TemplateDickMaterials != null && spawnResult.TemplateDickMaterials.Length != 0) { displayRig.TemplateDickMaterials = (Material[])spawnResult.TemplateDickMaterials.Clone(); } else if ((Object)(object)spawnResult.DickMesh != (Object)null && ((Renderer)spawnResult.DickMesh).sharedMaterials != null) { displayRig.TemplateDickMaterials = (Material[])((Renderer)spawnResult.DickMesh).sharedMaterials.Clone(); } if (spawnResult.TemplateMaterialsByRenderer != null) { foreach (KeyValuePair item in spawnResult.TemplateMaterialsByRenderer) { if ((Object)(object)item.Key != (Object)null && item.Value != null) { displayRig.TemplateMaterialsByRenderer[item.Key] = (Material[])item.Value.Clone(); } } } else if (spawnResult.BallMeshes != null) { for (int j = 0; j < spawnResult.BallMeshes.Length; j++) { SkinnedMeshRenderer val = spawnResult.BallMeshes[j]; if ((Object)(object)val != (Object)null && ((Renderer)val).sharedMaterials != null) { displayRig.TemplateMaterialsByRenderer[val] = (Material[])((Renderer)val).sharedMaterials.Clone(); } } } displayRig.OriginalBodyMaterial = GetBodyMaterial(source); CacheOriginalShlongMaterialsFromCurrentNeutralState(displayRig); SyncSettingsFromSource(source, displayRig); if ((Object)(object)displayRig.DickMesh != (Object)null && (Object)(object)displayRig.DickMesh.sharedMesh != (Object)null && displayRig.DickMesh.sharedMesh.blendShapeCount > 0) { displayRig.BlendShapes.ApplyArousedImmediate(displayRig.DickMesh, source.ArousalTarget); displayRig.BlendShapes.ApplyBulgeImmediate(displayRig.DickMesh, source.BulgeAmount, source.BulgePosition, source.BulgeWidth, source.BulgeSharpness); } UpdateNativeShaftJiggleForArousal(source, displayRig); displayRig.LastColorTint = source.ColorTint; displayRig.LastMatchBody = source.MatchBody; displayRig.LastColorMode = source.ColorMode; displayRig.LastTextureSourceMode = ShlongController.NormalizeTextureSourceMode(source.TextureSourceMode); displayRig.LastBallColorTint = source.BallColorTint; displayRig.LastBallMatchBody = source.BallMatchBody; displayRig.LastBallColorMode = source.BallColorMode; displayRig.LastBallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(source.BallTextureSourceMode); displayRig.LastAppliedVisible = false; displayRig.PendingVisible = false; displayRig.PendingVisibleSince = Time.unscaledTime; ApplyDickColor(displayRig); ApplyBallColor(displayRig); SetRigVisible(displayRig, visible: false); if (!PluginConfig.UseNativeRemoteDynamicBone) { InitializeJiggleChains(source, displayRig, preset); } _rigs[source] = displayRig; LifecycleDiagnostics.OnCosmeticFullSpawn(); if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] Create source=" + ((Object)((Component)source).gameObject).name + " preset=" + num + " race=" + raceIndex + " local=" + source.IsLocal + " ready=" + source.HasReceivedRemoteVisualState + " total=" + _rigs.Count + " frame=" + Time.frameCount); } return true; } internal static void OnLoadingDetected() { foreach (KeyValuePair rig in _rigs) { if ((Object)(object)rig.Value.DisplayRoot != (Object)null) { rig.Value.DisplayRoot.SetActive(false); } } _frozen = true; } internal static void OnRecovered() { int count = _rigs.Count; foreach (KeyValuePair rig in _rigs) { if ((Object)(object)rig.Value.DisplayRoot != (Object)null) { Object.Destroy((Object)(object)rig.Value.DisplayRoot); } } _rigs.Clear(); _frozen = false; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] Recovered: cleaned up " + count + " rigs for recreation frame=" + Time.frameCount); } } internal static void RecreateAllDisplayRigsForConfigChange(string reason) { int count = _rigs.Count; foreach (KeyValuePair rig in _rigs) { if (rig.Value != null && (Object)(object)rig.Value.DisplayRoot != (Object)null) { Object.Destroy((Object)(object)rig.Value.DisplayRoot); } } _rigs.Clear(); _removeBuffer.Clear(); _needsRebuild = false; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] RecreateAllDisplayRigsForConfigChange: reason=" + reason + " destroyed=" + count + " frame=" + Time.frameCount); } } internal static void TransferRig(ShlongController from, ShlongController to) { if (!((Object)(object)from == (Object)null) && !((Object)(object)to == (Object)null) && _rigs.TryGetValue(from, out var value)) { _rigs.Remove(from); value.TransferredAt = Time.unscaledTime; _rigs[to] = value; bool flag = !to.IsLocal && !to.HasReceivedRemoteVisualState; if (flag) { SetRigVisible(value, visible: false); } if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] TransferRig\n from=" + ((Object)((Component)from).gameObject).name + "\n to=" + ((Object)((Component)to).gameObject).name + "\n toReady=" + to.HasReceivedRemoteVisualState + "\n toPreset=" + to.PresetIndex + "\n hidden=" + flag + "\n frame=" + Time.frameCount); } } } private static void ApplyTestPresetTextureFallbacks(DisplayRig rig, PresetData testPreset, Material raceBodyMaterial) { if (rig == null || testPreset == null || testPreset.AssetSource != PresetAssetSource.Test) { return; } bool flag = false; Texture2D val = ((Plugin.Assets != null) ? Plugin.Assets.FindBestTextureForPreset(testPreset) : null); if ((Object)(object)val != (Object)null) { flag |= ApplyTextureAssetFallbacksToRenderer(rig.DickMesh, (Texture)(object)val, testPreset.Id, "TestBundle", "Dick"); if (rig.Balls != null) { for (int i = 0; i < rig.Balls.Length; i++) { flag |= ApplyTextureAssetFallbacksToRenderer(rig.Balls[i], (Texture)(object)val, testPreset.Id, "TestBundle", "Ball" + i); } } } Texture val2 = (((Object)(object)raceBodyMaterial != (Object)null) ? MaterialSkinUtility.GetBestVisualTexture(raceBodyMaterial) : null); if ((Object)(object)val2 != (Object)null) { flag |= ApplyBodyAtlasFallbacksToRenderer(rig, rig.DickMesh, raceBodyMaterial, testPreset.Id, "Dick"); if (rig.Balls != null) { for (int j = 0; j < rig.Balls.Length; j++) { flag |= ApplyBodyAtlasFallbacksToRenderer(rig, rig.Balls[j], raceBodyMaterial, testPreset.Id, "Ball" + j); } } } if (Plugin.Presets != null) { int index = Plugin.Presets.FindOriginalCounterpartIndex(testPreset); PresetData preset = Plugin.Presets.GetPreset(index); if (preset != null && (Object)(object)preset.LoadedPrefab != (Object)null) { Material[] array = MaterialSkinUtility.FindBestPrefabRendererMaterials(preset.LoadedPrefab, preset.MeshName); if (array != null && array.Length != 0) { flag |= ApplyOriginalCounterpartTextureFallbacksToRenderer(rig.DickMesh, array, testPreset.Id, preset.Id, "Dick"); if (rig.Balls != null) { for (int k = 0; k < rig.Balls.Length; k++) { flag |= ApplyOriginalCounterpartTextureFallbacksToRenderer(rig.Balls[k], array, testPreset.Id, preset.Id, "Ball" + k); } } } } } if (flag && Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay][TestTextureFallbacks] testPreset=" + testPreset.Id + " testBundleTexture=" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "") + " bodyAtlasTexture=" + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "") + " frame=" + Time.frameCount); } } private static bool ApplyBodyAtlasFallbacksToRenderer(DisplayRig rig, SkinnedMeshRenderer renderer, Material raceBodyMaterial, string testPresetId, string group) { if ((Object)(object)renderer == (Object)null || (Object)(object)raceBodyMaterial == (Object)null) { return false; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if ((Object)(object)val == (Object)null) { continue; } bool flag2 = MaterialSkinUtility.IsBallsSheathMaterial(val) || (group?.StartsWith("Ball", StringComparison.OrdinalIgnoreCase) ?? false); bool copyColorAdjustments = false; if (MaterialSkinUtility.ApplyBodyAtlasVisuals(val, raceBodyMaterial, "RaceBodyAtlas:" + testPresetId + ":" + group + ":" + i, copyColorAdjustments)) { flag = true; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay][BodyAtlasFallbackSlot] group=" + group + " slot=" + i + " isBallSlot=" + flag2 + " match=" + copyColorAdjustments + " testPreset=" + testPresetId + " bodyTex=" + (((Object)(object)raceBodyMaterial.mainTexture != (Object)null) ? ((Object)raceBodyMaterial.mainTexture).name : "") + " current=" + ((Object)val).name + " frame=" + Time.frameCount); } } } if (flag) { ((Renderer)renderer).sharedMaterials = sharedMaterials; } return flag; } private static bool ApplyTextureAssetFallbacksToRenderer(SkinnedMeshRenderer renderer, Texture texture, string testPresetId, string sourceLabel, string group) { if ((Object)(object)renderer == (Object)null || (Object)(object)texture == (Object)null) { return false; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if (!((Object)(object)val == (Object)null) && MaterialSkinUtility.ApplyTextureAssetIfTextureMissing(val, texture, sourceLabel + ":" + testPresetId + ":" + group + ":" + i)) { flag = true; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay][TestTextureFallbackSlot] group=" + group + " slot=" + i + " testPreset=" + testPresetId + " texture=" + ((Object)texture).name + " current=" + ((Object)val).name + " frame=" + Time.frameCount); } } } if (flag) { ((Renderer)renderer).sharedMaterials = sharedMaterials; } return flag; } private static bool ApplyOriginalCounterpartTextureFallbacksToRenderer(SkinnedMeshRenderer renderer, Material[] fallbackMats, string testPresetId, string originalPresetId, string group) { if ((Object)(object)renderer == (Object)null || fallbackMats == null || fallbackMats.Length == 0) { return false; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if ((Object)(object)val == (Object)null) { continue; } Material val2 = MaterialSkinUtility.PickFallbackMaterialForSlot(val, fallbackMats, i); if (!((Object)(object)val2 == (Object)null) && MaterialSkinUtility.ApplyFallbackVisualsIfTextureMissing(val, val2)) { flag = true; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay][OriginalCounterpartFallbackSlot] group=" + group + " slot=" + i + " testPreset=" + testPresetId + " originalPreset=" + originalPresetId + " current=" + ((Object)val).name + " fallback=" + ((Object)val2).name + " tex=" + (((Object)(object)val.mainTexture != (Object)null) ? ((Object)val.mainTexture).name : "") + " frame=" + Time.frameCount); } } } if (flag) { ((Renderer)renderer).sharedMaterials = sharedMaterials; } return flag; } internal unsafe static void ForceRefreshColorsFor(ShlongController source, bool dick, bool balls) { //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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_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_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || !_rigs.TryGetValue(source, out var value) || value == null) { return; } bool flag = (Object)(object)value.DickMesh != (Object)null && DickMeshHasBallsSheathSlots(value); if (flag || dick) { value.LastColorTint = source.ColorTint; value.LastMatchBody = source.MatchBody; value.LastColorMode = source.ColorMode; value.LastTextureSourceMode = ShlongController.NormalizeTextureSourceMode(source.TextureSourceMode); } if (flag || balls) { value.LastBallColorTint = source.BallColorTint; value.LastBallMatchBody = source.BallMatchBody; value.LastBallColorMode = source.BallColorMode; value.LastBallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(source.BallTextureSourceMode); } ResetMaterialResyncTracking(value); TryResyncMaterial(source, value); if (!value.TestPresetMaterialReady) { return; } if (flag) { ApplySplitColorToDickMesh(value); if (Plugin.IsDebug) { string[] obj = new string[16] { "[CosmeticDisplay][ForceSplitColorRefresh] source=", ((Object)((Component)source).gameObject).name, " requestedDick=", dick.ToString(), " requestedBalls=", balls.ToString(), " match=", source.MatchBody.ToString(), " ballMatch=", source.BallMatchBody.ToString(), " color=", null, null, null, null, null }; Color colorTint = source.ColorTint; obj[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[12] = " ballColor="; colorTint = source.BallColorTint; obj[13] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[14] = " materialResyncForced=true frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } return; } if (dick) { ApplyDickColor(value); } if (balls) { ApplyBallColor(value); } if (Plugin.IsDebug) { string[] obj2 = new string[16] { "[CosmeticDisplay][ForceColorRefresh] source=", ((Object)((Component)source).gameObject).name, " dick=", dick.ToString(), " balls=", balls.ToString(), " color=", null, null, null, null, null, null, null, null, null }; Color colorTint = source.ColorTint; obj2[7] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj2[8] = " match="; obj2[9] = source.MatchBody.ToString(); obj2[10] = " ballColor="; colorTint = source.BallColorTint; obj2[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj2[12] = " ballMatch="; obj2[13] = source.BallMatchBody.ToString(); obj2[14] = " materialResyncForced=true frame="; obj2[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj2)); } } private static void ResetMaterialResyncTracking(DisplayRig rig) { if (rig != null) { rig.MaterialResyncCount = 0; rig.LastRaceBodyShader = null; rig.LastRaceBodyTexture = null; rig.LastRaceBodyAdjustmentSignature = null; rig.OriginalBodyMaterial = null; PresetData presetData = Plugin.Presets?.GetPreset(rig.SpawnedPresetIndex); rig.TestPresetMaterialReady = presetData == null || presetData.AssetSource != PresetAssetSource.Test; } } internal static void RemoveRig(ShlongController source) { if (!_quitting && !((Object)(object)source == (Object)null) && _rigs.TryGetValue(source, out var value)) { if ((Object)(object)value.DisplayRoot != (Object)null) { Object.Destroy((Object)(object)value.DisplayRoot); } _rigs.Remove(source); if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] RemoveRig: " + (((Object)(object)source != (Object)null) ? ((Object)((Component)source).gameObject).name : "null") + " total=" + _rigs.Count + " frame=" + Time.frameCount); } } } internal static void UpdateDisplay() { if (_frozen || _quitting || _rigs.Count == 0) { return; } _removeBuffer.Clear(); foreach (KeyValuePair rig in _rigs) { ShlongController key = rig.Key; DisplayRig value = rig.Value; if (TryGetImmediateStaleReason(key, value, out var reason)) { DestroyRig(key, value, reason); continue; } if (key.PresetIndex != value.SpawnedPresetIndex) { if (value.PresetChangedSince < 0f) { value.PresetChangedSince = Time.unscaledTime; SetRigVisible(value, visible: false); value.LastAppliedVisible = false; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] PresetMismatch: hiding rig during debounce source=" + ((Object)((Component)key).gameObject).name + " sourcePreset=" + key.PresetIndex + " rigPreset=" + value.SpawnedPresetIndex + " frame=" + Time.frameCount); } } else if (Time.unscaledTime - value.PresetChangedSince >= 0.6f) { DestroyRig(key, value, "PresetChanged"); } continue; } value.PresetChangedSince = -1f; if (TryGetThrottledStaleReason(key, value, out reason)) { value.ThrottledStaleConsecutiveCount++; if (value.ThrottledStaleConsecutiveCount >= 2) { DestroyRig(key, value, reason); } } else { if (Time.frameCount % 15 == 0) { value.ThrottledStaleConsecutiveCount = 0; } UpdateSingleRig(key, value); } } for (int i = 0; i < _removeBuffer.Count; i++) { _rigs.Remove(_removeBuffer[i]); } if (!_needsRebuild) { return; } _needsRebuild = false; Dictionary dictionary = new Dictionary(); foreach (KeyValuePair rig2 in _rigs) { if ((Object)(object)rig2.Key != (Object)null) { dictionary[rig2.Key] = rig2.Value; } } _rigs.Clear(); foreach (KeyValuePair item in dictionary) { _rigs[item.Key] = item.Value; } } private static bool TryGetImmediateStaleReason(ShlongController source, DisplayRig rig, out string reason) { if ((Object)(object)source == (Object)null || !Object.op_Implicit((Object)(object)source)) { reason = "SourceDestroyed"; return true; } if (rig == null || (Object)(object)rig.DisplayRoot == (Object)null) { reason = "DisplayRootMissing"; return true; } if (!source.HasPlayerParent) { reason = "NoPlayerParent"; return true; } if (source.PresetIndex < 0 && (rig == null || !(rig.TransferredAt >= 0f) || !(Time.unscaledTime - rig.TransferredAt < 0.6f))) { reason = "PresetInvalid"; return true; } if (source.HasRuntimeRig) { reason = "RuntimeRigPresent"; return true; } if ((Object)(object)rig.HipBone == (Object)null) { reason = "HipBoneMissing"; return true; } reason = null; return false; } private static bool TryGetThrottledStaleReason(ShlongController source, DisplayRig rig, out string reason) { reason = null; if (Time.frameCount % 15 != 0) { return false; } string knownSteamId = source.GetKnownSteamId(); if (!string.IsNullOrEmpty(knownSteamId)) { rig.SourceSteamId = knownSteamId; } if (!string.IsNullOrEmpty(rig.SourceSteamId) && Plugin.Controllers != null && Plugin.Controllers.TryGetValue(rig.SourceSteamId, out var value) && (Object)(object)value != (Object)null && (Object)(object)value != (Object)(object)source) { reason = "AuthoritativeControllerMismatch"; return true; } if ((Object)(object)source.PlayerObj != (Object)null && source.PlayerObj._bufferingStatus) { reason = "PlayerBuffering"; return true; } MapInstance val = (((Object)(object)Player._mainPlayer != (Object)null) ? Player._mainPlayer.Network_playerMapInstance : null); MapInstance val2 = (((Object)(object)source.PlayerObj != (Object)null) ? source.PlayerObj.Network_playerMapInstance : null); if ((Object)(object)val2 != (Object)(object)val) { reason = "MapInstanceMismatch"; return true; } return false; } private static void DestroyRig(ShlongController source, DisplayRig rig, string reason) { if (rig != null && (Object)(object)rig.DisplayRoot != (Object)null) { Object.Destroy((Object)(object)rig.DisplayRoot); } if ((Object)(object)source != (Object)null) { _removeBuffer.Add(source); } else { _needsRebuild = true; } if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] StaleRigDestroy: " + reason + " source=" + (((Object)(object)source != (Object)null) ? ((Object)((Component)source).gameObject).name : "null") + " steamId=" + (((Object)(object)source != (Object)null) ? source.GetKnownSteamId() : "?") + " sourcePreset=" + (((Object)(object)source != (Object)null) ? source.PresetIndex.ToString() : "?") + " rigPreset=" + ((rig != null) ? rig.SpawnedPresetIndex.ToString() : "?") + " total=" + _rigs.Count + " frame=" + Time.frameCount); } } private static void SetRigVisible(DisplayRig rig, bool visible) { if (rig == null) { return; } if ((Object)(object)rig.DickMesh != (Object)null) { ((Renderer)rig.DickMesh).enabled = visible; } if (rig.Balls != null) { for (int i = 0; i < rig.Balls.Length; i++) { if ((Object)(object)rig.Balls[i] != (Object)null) { ((Renderer)rig.Balls[i]).enabled = visible; } } } if (!visible) { rig.LastJiggleVisible = false; ResetJiggleChains(rig); } } private static bool SyncRigToHipPose(DisplayRig rig) { //IL_003c: 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_0059: Unknown result type (might be due to invalid IL or missing references) if (rig == null || (Object)(object)rig.DisplayRoot == (Object)null || (Object)(object)rig.HipBone == (Object)null) { return false; } Transform transform = rig.DisplayRoot.transform; transform.SetPositionAndRotation(rig.HipBone.position, rig.HipBone.rotation); transform.localScale = rig.HipBone.lossyScale; return true; } private static void UpdatePoseBeforeRender() { if (_frozen || _quitting || _rigs.Count == 0) { return; } foreach (KeyValuePair rig in _rigs) { DisplayRig value = rig.Value; if (value != null && !((Object)(object)value.DisplayRoot == (Object)null) && value.DisplayRoot.activeInHierarchy) { SyncRigToHipPose(value); } } } private static void UpdateNativeShaftJiggleForArousal(ShlongController source, DisplayRig rig) { if ((Object)(object)source == (Object)null || rig == null || !rig.ArousalControlsShaftJiggle || rig.ShaftDynamicBones == null || rig.ShaftDynamicBones.Length == 0) { return; } bool flag = source.ArousalTarget > 0.001f; if (rig.ShaftJiggleStateKnown && rig.ShaftJiggleActive == flag) { return; } rig.ShaftJiggleStateKnown = true; rig.ShaftJiggleActive = flag; float weight = (flag ? 1f : 0f); for (int i = 0; i < rig.ShaftDynamicBones.Length; i++) { DynamicBone val = rig.ShaftDynamicBones[i]; if ((Object)(object)val != (Object)null) { val.SetWeight(weight); } } } private static void UpdateSingleRig(ShlongController source, DisplayRig rig) { //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) if (!SyncRigToHipPose(rig)) { return; } SyncSettingsFromSource(source, rig); if (!rig.BonesCached) { if (rig.SizeBoneName != null) { rig.CachedSizeBone = rig.DisplayRoot.transform.RecursiveFindChild(rig.SizeBoneName); } if (rig.BallBoneName != null) { rig.CachedBallBone = rig.DisplayRoot.transform.RecursiveFindChild(rig.BallBoneName); } rig.BonesCached = true; } if ((Object)(object)rig.CachedSizeBone != (Object)null) { PresetData preset = Plugin.Presets.GetPreset(rig.SpawnedPresetIndex); if (preset != null) { rig.CachedSizeBone.localScale = new Vector3(preset.Scale.x + rig.ScaleOffset.x, preset.Scale.y + rig.ScaleOffset.y, preset.Scale.z + rig.ScaleOffset.z); rig.CachedSizeBone.localRotation = Quaternion.Euler(rig.BaseRotation.x + rig.ErectAngleOffset, rig.BaseRotation.y, rig.BaseRotation.z); rig.CachedSizeBone.localPosition = new Vector3(0f, rig.PositionOffset.y, rig.PositionOffset.x); } } if ((Object)(object)rig.CachedBallBone != (Object)null) { rig.CachedBallBone.localScale = Vector3.one + Vector3.one * rig.BallsSizeOffset; } if ((Object)(object)rig.DickMesh != (Object)null && (Object)(object)rig.DickMesh.sharedMesh != (Object)null && rig.DickMesh.sharedMesh.blendShapeCount > 0) { float arousalTarget = source.ArousalTarget; float arousalLerpSpeed = source.ArousalLerpSpeed; float bulgeLerpSpeed = source.BulgeLerpSpeed; rig.BlendShapes.ApplyAroused(rig.DickMesh, arousalTarget, arousalLerpSpeed); rig.BlendShapes.ApplyBulge(rig.DickMesh, source.BulgeAmount, source.BulgePosition, source.BulgeWidth, source.BulgeSharpness, bulgeLerpSpeed); } UpdateNativeShaftJiggleForArousal(source, rig); if (Time.frameCount % 60 == 0) { PlayerRaceModel val = source.CachedPlayerRaceModel; if ((Object)(object)val == (Object)null) { val = ((Component)source).GetComponent(); } if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)rig.CachedPRM) { rig.CachedPRM = val; } } if (Time.frameCount % 30 == 0) { if (source.ColorTint != rig.LastColorTint || source.MatchBody != rig.LastMatchBody || source.ColorMode != rig.LastColorMode || ShlongController.NormalizeTextureSourceMode(source.TextureSourceMode) != rig.LastTextureSourceMode) { rig.LastColorTint = source.ColorTint; rig.LastMatchBody = source.MatchBody; rig.LastColorMode = source.ColorMode; rig.LastTextureSourceMode = ShlongController.NormalizeTextureSourceMode(source.TextureSourceMode); ApplyDickColor(rig); } if (source.BallColorTint != rig.LastBallColorTint || source.BallMatchBody != rig.LastBallMatchBody || source.BallColorMode != rig.LastBallColorMode || ShlongController.NormalizeTextureSourceMode(source.BallTextureSourceMode) != rig.LastBallTextureSourceMode) { rig.LastBallColorTint = source.BallColorTint; rig.LastBallMatchBody = source.BallMatchBody; rig.LastBallColorMode = source.BallColorMode; rig.LastBallTextureSourceMode = ShlongController.NormalizeTextureSourceMode(source.BallTextureSourceMode); ApplyBallColor(rig); } } PresetData presetData = Plugin.Presets?.GetPreset(rig.SpawnedPresetIndex); if (presetData != null && presetData.AssetSource == PresetAssetSource.Test) { bool flag = !rig.TestPresetMaterialReady && Time.frameCount % 3 == 0; bool flag2 = Time.frameCount % 60 == 0; if (flag || flag2) { TryResyncMaterial(source, rig); } } else if (rig.MaterialResyncCount < 3 && Time.frameCount % 10 == 0) { TryResyncMaterial(source, rig); } if (Time.frameCount % 3 == 0) { UpdateVisibility(source, rig); } UpdateProceduralJiggle(source, rig); } private static bool DickMeshHasBallsSheathSlots(DisplayRig rig) { if (rig == null) { return false; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(rig.OriginalDickMaterials)) { return true; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(rig.TemplateDickMaterials)) { return true; } if ((Object)(object)rig.DickMesh != (Object)null && MaterialSkinUtility.HasBallsSheathMaterialSlot(((Renderer)rig.DickMesh).sharedMaterials)) { return true; } return false; } private static Material[] SelectSplitMaterialSource(Material[] originals, Material[] templates, Material[] live) { if (MaterialSkinUtility.HasBallsSheathMaterialSlot(originals)) { return originals; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(templates)) { return templates; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(live)) { return live; } return originals ?? templates ?? live; } private static Color NormalizeLegacyNeutralTint(Color tint, bool matchBody, int colorMode) { //IL_0007: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (!matchBody && colorMode == 0 && Mathf.Abs(tint.r - 0.5f) < 0.001f && Mathf.Abs(tint.g - 0.5f) < 0.001f && Mathf.Abs(tint.b - 0.5f) < 0.001f) { return Color.white; } return tint; } private static bool IsBodyAtlasRuntimeBase(Material mat) { if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(((Object)mat).name)) { return false; } return ((Object)mat).name.IndexOf("_BodyAtlas", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)mat).name.IndexOf("RaceBodyAtlas", StringComparison.OrdinalIgnoreCase) >= 0; } private static Material BuildSlotAwareMatchBodyBase(Material raceBase, Material visibleBodyBase, Material templateBase, bool matchBody) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if (!matchBody) { return raceBase ?? templateBase; } if ((Object)(object)raceBase != (Object)null && (Object)(object)visibleBodyBase != (Object)null && IsBodyAtlasRuntimeBase(raceBase)) { Material val = new Material(raceBase); ((Object)val).name = ((Object)raceBase).name.Replace(" (Instance)", "").Replace("_MatchedBodyBase", "") + "_MatchedBodyBase"; MaterialSkinUtility.CopyCharacterColorAdjustmentPropertiesForced(visibleBodyBase, val); MaterialSkinUtility.CopyBodyTintLikeProperties(visibleBodyBase, val); return val; } return visibleBodyBase ?? raceBase ?? templateBase; } private static void ApplySplitColorToDickMesh(DisplayRig rig) { //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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_0172: 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) if (rig == null || (Object)(object)rig.DickMesh == (Object)null) { return; } Material[] sharedMaterials = ((Renderer)rig.DickMesh).sharedMaterials; Material[] array = SelectSplitMaterialSource(rig.OriginalDickMaterials, rig.TemplateDickMaterials, sharedMaterials); if (array == null || array.Length == 0) { return; } bool flag = MaterialSkinUtility.HasBallsSheathMaterialSlot(array); if (Plugin.IsDebug && !flag) { Plugin.LogDebug("[SplitColorSlot][WARN] split rebuild called but selected source has no BodyMat2 originalHas=" + MaterialSkinUtility.HasBallsSheathMaterialSlot(rig.OriginalDickMaterials) + " templateHas=" + MaterialSkinUtility.HasBallsSheathMaterialSlot(rig.TemplateDickMaterials) + " liveHas=" + MaterialSkinUtility.HasBallsSheathMaterialSlot(sharedMaterials)); } Material[] array2 = (Material[])(object)new Material[array.Length]; for (int i = 0; i < array.Length; i++) { Material val = array[i]; bool flag2 = MaterialSkinUtility.IsBallsSheathMaterial(val); Color tint = (flag2 ? rig.LastBallColorTint : rig.LastColorTint); bool matchBody = (flag2 ? rig.LastBallMatchBody : rig.LastMatchBody); Material val2 = ((rig.TemplateDickMaterials != null && i < rig.TemplateDickMaterials.Length) ? rig.TemplateDickMaterials[i] : null); Material val3 = BuildSlotAwareMatchBodyBase(val, rig.OriginalBodyMaterial, val2, matchBody); tint = NormalizeLegacyNeutralTint(tint, matchBody, flag2 ? rig.LastBallColorMode : rig.LastColorMode); int textureSourceMode = (flag2 ? rig.LastBallTextureSourceMode : rig.LastTextureSourceMode); array2[i] = ShlongController.BuildColoredMaterial(val3, tint, matchBody, textureSourceMode); if (Plugin.IsDebug) { Plugin.LogDebug("[SplitColorSlot] slot=" + i + " isBallSlot=" + flag2 + " match=" + matchBody + " raceBase=" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "") + " raceShader=" + (((Object)(object)val != (Object)null && (Object)(object)val.shader != (Object)null) ? ((Object)val.shader).name : "") + " solidTemplate=" + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "") + " solidTemplateShader=" + (((Object)(object)val2 != (Object)null && (Object)(object)val2.shader != (Object)null) ? ((Object)val2.shader).name : "") + " selectedBase=" + (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : "") + " selectedShader=" + (((Object)(object)val3 != (Object)null && (Object)(object)val3.shader != (Object)null) ? ((Object)val3.shader).name : "") + " result=" + (((Object)(object)array2[i] != (Object)null) ? ((Object)array2[i]).name : "") + " resultShader=" + (((Object)(object)array2[i] != (Object)null && (Object)(object)array2[i].shader != (Object)null) ? ((Object)array2[i].shader).name : "") + " renderQueue=" + (((Object)(object)array2[i] != (Object)null) ? array2[i].renderQueue.ToString() : "")); } } ((Renderer)rig.DickMesh).sharedMaterials = array2; } private static void ApplyDickColor(DisplayRig rig) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rig.DickMesh == (Object)null)) { if (DickMeshHasBallsSheathSlots(rig)) { ApplySplitColorToDickMesh(rig); } else { ApplyColorToRenderer(rig.DickMesh, rig.OriginalDickMaterials, rig.TemplateDickMaterials, rig.LastColorTint, rig.LastMatchBody, rig.LastColorMode, rig.LastTextureSourceMode, rig.OriginalBodyMaterial); } } } private static void ApplyBallColor(DisplayRig rig) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rig.DickMesh != (Object)null && DickMeshHasBallsSheathSlots(rig)) { ApplySplitColorToDickMesh(rig); } if (rig.Balls == null) { return; } for (int i = 0; i < rig.Balls.Length; i++) { SkinnedMeshRenderer val = rig.Balls[i]; if (!((Object)(object)val == (Object)null)) { rig.OriginalMaterialsByRenderer.TryGetValue(val, out var value); rig.TemplateMaterialsByRenderer.TryGetValue(val, out var value2); ApplyColorToRenderer(val, value, value2, rig.LastBallColorTint, rig.LastBallMatchBody, rig.LastBallColorMode, rig.LastBallTextureSourceMode, rig.OriginalBodyMaterial); } } } private static void ApplyColorToRenderer(SkinnedMeshRenderer smr, Material[] originalMaterials, Material[] templateMaterials, Color tint, bool matchBody, int colorMode, int textureSourceMode, Material fallbackBodyMat) { //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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) textureSourceMode = ShlongController.NormalizeTextureSourceMode(textureSourceMode); if (originalMaterials != null && originalMaterials.Length > 1) { Material[] array = (Material[])(object)new Material[originalMaterials.Length]; for (int i = 0; i < originalMaterials.Length; i++) { Material val = originalMaterials[i] ?? ((Renderer)smr).sharedMaterials[i]; Material val2 = ((templateMaterials != null && i < templateMaterials.Length) ? templateMaterials[i] : null); Material baseMat = (matchBody ? (fallbackBodyMat ?? val ?? val2) : (val ?? val2)); Color tint2 = NormalizeLegacyNeutralTint(tint, matchBody, colorMode); array[i] = ShlongController.BuildColoredMaterial(baseMat, tint2, matchBody, textureSourceMode); } ((Renderer)smr).sharedMaterials = array; } else { Material val3 = ((originalMaterials != null && originalMaterials.Length == 1 && (Object)(object)originalMaterials[0] != (Object)null) ? originalMaterials[0] : (fallbackBodyMat ?? ((Renderer)smr).sharedMaterial)); Material val4 = ((templateMaterials != null && templateMaterials.Length >= 1) ? templateMaterials[0] : null); Material val5 = (matchBody ? (fallbackBodyMat ?? val3 ?? val4) : (val3 ?? val4)); tint = NormalizeLegacyNeutralTint(tint, matchBody, colorMode); Material val6 = ShlongController.BuildColoredMaterial(val5, tint, matchBody, textureSourceMode); if ((Object)(object)val6 == (Object)(object)val5) { ((Renderer)smr).sharedMaterial = val5; } else { ((Renderer)smr).material = val6; } } } private static bool IsGeneratedColorMaterial(Material mat) { return ShlongController.IsGeneratedColorMaterial(mat); } private static Material[] CloneNeutralMaterialArray(Material[] src, string debugLabel) { if (src == null) { return null; } Material[] array = (Material[])(object)new Material[src.Length]; for (int i = 0; i < src.Length; i++) { if ((Object)(object)src[i] != (Object)null && IsGeneratedColorMaterial(src[i])) { if (Plugin.IsDebug) { Plugin.LogDebug("[OriginalMaterialCache] prevented generated material from becoming original source=" + debugLabel + " slot=" + i + " mat=" + ((Object)src[i]).name); } } else if (Plugin.IsDebug) { Plugin.LogDebug("[OriginalMaterialCache] cached source=" + debugLabel + " slot=" + i + " mat=" + (((Object)(object)src[i] != (Object)null) ? ((Object)src[i]).name : "") + " generatedColorMaterial=" + ((Object)(object)src[i] != (Object)null && IsGeneratedColorMaterial(src[i]))); } array[i] = src[i]; } return array; } private static void CacheOriginalShlongMaterials(DisplayRig rig) { rig.OriginalDickMaterials = null; rig.OriginalMaterialsByRenderer.Clear(); if (rig.TemplateDickMaterials != null && rig.TemplateDickMaterials.Length != 0) { rig.OriginalDickMaterials = CloneNeutralMaterialArray(rig.TemplateDickMaterials, "template"); } else if ((Object)(object)rig.DickMesh != (Object)null && ((Renderer)rig.DickMesh).sharedMaterials != null) { rig.OriginalDickMaterials = CloneNeutralMaterialArray(((Renderer)rig.DickMesh).sharedMaterials, "current"); } if (rig.Balls == null) { return; } for (int i = 0; i < rig.Balls.Length; i++) { SkinnedMeshRenderer val = rig.Balls[i]; if (!((Object)(object)val == (Object)null)) { if (rig.TemplateMaterialsByRenderer.TryGetValue(val, out var value) && value != null) { rig.OriginalMaterialsByRenderer[val] = CloneNeutralMaterialArray(value, "template"); } else if (((Renderer)val).sharedMaterials != null) { rig.OriginalMaterialsByRenderer[val] = CloneNeutralMaterialArray(((Renderer)val).sharedMaterials, "current"); } } } } private static void CacheOriginalShlongMaterialsFromCurrentNeutralState(DisplayRig rig) { if (rig == null) { return; } rig.OriginalDickMaterials = null; rig.OriginalMaterialsByRenderer.Clear(); if ((Object)(object)rig.DickMesh != (Object)null && ((Renderer)rig.DickMesh).sharedMaterials != null) { rig.OriginalDickMaterials = CloneNeutralMaterialArray(((Renderer)rig.DickMesh).sharedMaterials, "current-neutral-raceshaded"); } if (rig.Balls == null) { return; } for (int i = 0; i < rig.Balls.Length; i++) { SkinnedMeshRenderer val = rig.Balls[i]; if ((Object)(object)val != (Object)null && ((Renderer)val).sharedMaterials != null) { rig.OriginalMaterialsByRenderer[val] = CloneNeutralMaterialArray(((Renderer)val).sharedMaterials, "current-neutral-raceshaded"); } } } private unsafe static void SyncSettingsFromSource(ShlongController source, DisplayRig rig) { //IL_0003: 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_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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0044: 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_004b: 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_007d: 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_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) rig.PositionOffset = source.PositionOffset; rig.BaseRotation = source.BaseRotation; rig.ErectAngleOffset = source.ErectAngleOffset; rig.BallsSizeOffset = source.BallsSizeOffset; Vector3 scaleOffset = source.ScaleOffset; if (source.IsLocal) { rig.ScaleOffset = scaleOffset; rig.LastStableScaleOffset = scaleOffset; rig.HasStableScaleOffset = true; rig.PendingScaleSince = -1f; return; } bool flag = scaleOffset == Vector3.zero; bool flag2 = rig.HasStableScaleOffset && rig.LastStableScaleOffset != Vector3.zero; if (flag && flag2) { if (rig.PendingScaleSince < 0f) { rig.PendingScaleOffset = scaleOffset; rig.PendingScaleSince = Time.unscaledTime; } float num = Time.unscaledTime - rig.PendingScaleSince; if (num < 0.75f) { rig.ScaleOffset = rig.LastStableScaleOffset; if (Plugin.IsDebug) { string[] obj = new string[10] { "[CosmeticDisplay] HoldTransientZeroScale source=", ((Object)((Component)source).gameObject).name, " sourceScale=", null, null, null, null, null, null, null }; Vector3 val = scaleOffset; obj[3] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[4] = " displayedScale="; val = rig.LastStableScaleOffset; obj[5] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[6] = " pendingFor="; obj[7] = num.ToString("F2"); obj[8] = "s frame="; obj[9] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } else { rig.ScaleOffset = scaleOffset; rig.LastStableScaleOffset = scaleOffset; rig.PendingScaleSince = -1f; } } else { rig.ScaleOffset = scaleOffset; if (!flag) { rig.LastStableScaleOffset = scaleOffset; rig.HasStableScaleOffset = true; } rig.PendingScaleSince = -1f; } } private static void UpdateVisibility(ShlongController source, DisplayRig rig) { if ((Object)(object)rig.DickMesh == (Object)null) { return; } try { bool displayBoobs = false; bool flag = false; bool noLeggingsEquipped = rig.HasKnownNoLeggings && rig.LastKnownNoLeggings; bool charMenuON = Plugin.CharMenuON; bool activeInHierarchy = ((Component)source).gameObject.activeInHierarchy; PlayerRaceModel cachedPRM = rig.CachedPRM; if ((Object)(object)cachedPRM != (Object)null) { displayBoobs = cachedPRM._displayBoobs; } RaceModelEquipDisplay raceModelEquipDisplay = source.RaceModelEquipDisplay; if ((Object)(object)raceModelEquipDisplay != (Object)null) { flag = raceModelEquipDisplay._hideLeggingsVisual; } bool noLeggings; bool flag2 = LeggingsChecker.TryHasNoLeggingsEquipped(source.RaceModelEquipDisplay, out noLeggings); if (flag2) { noLeggingsEquipped = noLeggings; rig.LastKnownNoLeggings = noLeggings; rig.HasKnownNoLeggings = true; } bool futaToggle = source.FutaToggle; bool clothingOverride = source.ClothingOverride; bool flag3 = source.IsOwnerForceHidden(); bool flag4 = (Object)(object)cachedPRM == (Object)null || (Object)(object)cachedPRM._baseBodyMesh == (Object)null || ((Renderer)cachedPRM._baseBodyMesh).enabled; if (flag4 != rig.PendingBodyVisible) { rig.PendingBodyVisible = flag4; rig.PendingBodyVisibleSince = Time.unscaledTime; } bool playerBodyVisible = rig.LastAppliedBodyVisible; if (flag4 == rig.LastAppliedBodyVisible || Time.unscaledTime - rig.PendingBodyVisibleSince >= 0.2f) { rig.LastAppliedBodyVisible = flag4; playerBodyVisible = flag4; } bool testPresetMaterialReady = rig.TestPresetMaterialReady; bool flag5 = testPresetMaterialReady && VisibilityResolver.ShouldShowDick(source.IsLocal, charMenuON, activeInHierarchy, displayBoobs, futaToggle, clothingOverride, flag, noLeggingsEquipped, playerBodyVisible, source.HideToggle, flag3, 0, PluginConfig.HideOtherPlayersShlongs != null && PluginConfig.HideOtherPlayersShlongs.Value); if (!clothingOverride && !flag && !flag2 && !rig.HasKnownNoLeggings) { flag5 = false; } if (flag5 != rig.PendingVisible) { rig.PendingVisible = flag5; rig.PendingVisibleSince = Time.unscaledTime; } if ((flag5 == rig.LastAppliedVisible || Time.unscaledTime - rig.PendingVisibleSince >= 0.2f || charMenuON || flag3 || !testPresetMaterialReady) && flag5 != rig.LastAppliedVisible) { rig.LastAppliedVisible = flag5; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] VisibilityChange\n source=" + ((Object)((Component)source).gameObject).name + "\n visible=" + flag5 + "\n preset=" + source.PresetIndex + "\n rigPreset=" + rig.SpawnedPresetIndex + "\n isLocal=" + source.IsLocal + "\n goActive=" + activeInHierarchy + "\n bodyVisible=" + playerBodyVisible + "\n rawBodyVisible=" + flag4 + "\n displayBoobs=" + displayBoobs + "\n futaToggle=" + futaToggle + "\n clothingOverride=" + clothingOverride + "\n hideLeggings=" + flag + "\n knownNoLeggings=" + flag2 + "\n noLeggings=" + noLeggingsEquipped + "\n hasKnownNoLeggings=" + rig.HasKnownNoLeggings + "\n hideToggle=" + source.HideToggle + "\n forceHidden=" + flag3 + "\n isCharMenu=" + charMenuON + "\n frame=" + Time.frameCount); } } SetRigVisible(rig, rig.LastAppliedVisible); if (source.IsLocal && rig.LastAppliedVisible && (Object)(object)CameraCollision._current != (Object)null && VisibilityResolver.ShouldHideForCamera(CameraCollision._current._unhidePlayerModel)) { SetRigVisible(rig, visible: false); } } catch (Exception ex) { if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] UpdateVisibility error: " + ex.Message); } } } private static void InitializeJiggleChains(ShlongController source, DisplayRig rig, PresetData preset) { rig.JiggleChains.Clear(); rig.JiggleInitialized = true; rig.HasLastHipPose = false; rig.HasLastDriverPose = false; rig.LastJiggleTargetMagnitude = 0f; rig.LastJiggleVisible = false; if (rig == null || (Object)(object)rig.DisplayRoot == (Object)null) { return; } if (preset == null) { if (Plugin.IsDebug) { Plugin.LogDebug("[RemoteJiggle][NoChains] preset= displayRoot=" + ((Object)rig.DisplayRoot).name); } TryAddFallbackJiggleChains(source, rig, allowSupplement: false); return; } if (preset.DynamicBones == null || preset.DynamicBones.Length == 0) { if (Plugin.IsDebug) { Plugin.LogDebug("[RemoteJiggle][NoDynamicBones] preset=" + preset.Id + " displayRoot=" + ((Object)rig.DisplayRoot).name); } TryAddFallbackJiggleChains(source, rig, allowSupplement: false); return; } if (Plugin.IsDebug) { MonoBehaviour[] componentsInChildren = rig.DisplayRoot.GetComponentsInChildren(true); MonoBehaviour[] array = componentsInChildren; foreach (MonoBehaviour val in array) { if (!((Object)(object)val == (Object)null)) { string name = ((object)val).GetType().Name; if (name.IndexOf("Dynamic", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Jiggle", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Spring", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Bone", StringComparison.OrdinalIgnoreCase) >= 0) { Plugin.LogDebug("[RemoteJiggle][DiagComponents] root=" + ((Object)rig.DisplayRoot).name + " component=" + name + " enabled=" + ((Behaviour)val).enabled); } } } } for (int j = 0; j < preset.DynamicBones.Length; j++) { string text = preset.DynamicBones[j]; if (string.IsNullOrEmpty(text)) { continue; } Transform val2 = rig.DisplayRoot.transform.RecursiveFindChild(text); if ((Object)(object)val2 == (Object)null) { if (Plugin.IsDebug) { Plugin.LogDebug("[RemoteJiggle][Init] missing bone preset=" + preset.Id + " bone=" + text); } continue; } Transform val3 = ((!string.IsNullOrEmpty(rig.SizeBoneName)) ? rig.DisplayRoot.transform.RecursiveFindChild(rig.SizeBoneName) : null); Transform val4 = val2; if ((Object)(object)val3 != (Object)null && (Object)(object)val4 == (Object)(object)val3 && val4.childCount > 0) { val4 = val4.GetChild(0); } if (!((Object)(object)val4 == (Object)null)) { bool isBall = text.IndexOf("ball", StringComparison.OrdinalIgnoreCase) >= 0; AddSoftJiggleChain(source, rig, val4, text, isBall); if (Plugin.IsDebug) { Plugin.LogDebug("[RemoteJiggle][Init] source=" + ((Object)((Component)source).gameObject).name + " local=" + source.IsLocal + " preset=" + preset.Id + " bone=" + text + " root=" + ((Object)val4).name + " isBall=" + isBall); } } } if (Plugin.IsDebug && rig.JiggleChains.Count == 0) { Plugin.LogDebug("[RemoteJiggle][NoChains] preset=" + preset.Id + " dynamicBones=" + preset.DynamicBones.Length + " displayRoot=" + ((Object)rig.DisplayRoot).name + " (all bones missing from rig)"); } if (rig.JiggleChains.Count == 0) { TryAddFallbackJiggleChains(source, rig, allowSupplement: false); } else { TryAddFallbackJiggleChains(source, rig, allowSupplement: true); } } private static bool HasJiggleRoot(DisplayRig rig, Transform t) { if (rig == null || rig.JiggleChains == null || (Object)(object)t == (Object)null) { return false; } for (int i = 0; i < rig.JiggleChains.Count; i++) { ProceduralJiggleChain proceduralJiggleChain = rig.JiggleChains[i]; if (proceduralJiggleChain == null) { continue; } for (int j = 0; j < proceduralJiggleChain.Bones.Count; j++) { if (proceduralJiggleChain.Bones[j] != null && (Object)(object)proceduralJiggleChain.Bones[j].Bone == (Object)(object)t) { return true; } } } return false; } private static void CollectJiggleBones(Transform root, List bones, bool isBall, int maxBones = 8) { if ((Object)(object)root == (Object)null) { return; } bones.Add(root); Transform val = root; while (bones.Count < maxBones && val.childCount == 1) { val = val.GetChild(0); string text = ((Object)val).name.ToLowerInvariant(); bool flag = false; string[] fallbackExcludeKeywords = _fallbackExcludeKeywords; foreach (string value in fallbackExcludeKeywords) { if (text.Contains(value)) { flag = true; break; } } if (flag) { break; } bones.Add(val); } if (bones.Count != 1) { return; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); Transform[] array = componentsInChildren; foreach (Transform val2 in array) { if (bones.Count >= maxBones) { break; } if ((Object)(object)val2 == (Object)(object)root) { continue; } string text2 = ((Object)val2).name.ToLowerInvariant(); bool flag2 = false; string[] fallbackExcludeKeywords2 = _fallbackExcludeKeywords; foreach (string value2 in fallbackExcludeKeywords2) { if (text2.Contains(value2)) { flag2 = true; break; } } if (flag2) { continue; } bool flag3 = false; string[] jiggleBoneKeywords = _jiggleBoneKeywords; foreach (string value3 in jiggleBoneKeywords) { if (text2.Contains(value3)) { flag3 = true; break; } } if (flag3 && !bones.Contains(val2)) { bones.Add(val2); } } } private static void AddSoftJiggleChain(ShlongController source, DisplayRig rig, Transform root, string name, bool isBall) { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if (rig == null || (Object)(object)root == (Object)null) { return; } ProceduralJiggleChain proceduralJiggleChain = new ProceduralJiggleChain(); proceduralJiggleChain.Name = name; proceduralJiggleChain.IsBall = isBall; proceduralJiggleChain.DbDamping = (isBall ? 0.2f : 0.33f); proceduralJiggleChain.DbElasticity = 0.1f; proceduralJiggleChain.DbStiffness = (isBall ? 0.4f : 0.85f); proceduralJiggleChain.DbInert = (isBall ? 0.15f : 0.37f); List list = new List(); CollectJiggleBones(root, list, isBall); if (list.Count == 0) { list.Add(root); } for (int i = 0; i < list.Count; i++) { Transform val = list[i]; if (!((Object)(object)val == (Object)null)) { float num = ((list.Count <= 1) ? 1f : ((float)i / (float)(list.Count - 1))); float weight = (isBall ? 0.55f : Mathf.Lerp(0.25f, 1f, num)); proceduralJiggleChain.Bones.Add(new ProceduralJiggleBone { Bone = val, BaseLocalRotation = val.localRotation, Offset = Vector3.zero, Velocity = Vector3.zero, Weight = weight, Name = ((Object)val).name }); } } if (proceduralJiggleChain.Bones.Count > 0) { rig.JiggleChains.Add(proceduralJiggleChain); } if (Plugin.IsDebug) { Plugin.LogDebug("[RemoteJiggle][SoftChain] source=" + (((Object)(object)source != (Object)null) ? ((Object)((Component)source).gameObject).name : "") + " name=" + name + " root=" + ((Object)root).name + " isBall=" + isBall + " bones=" + proceduralJiggleChain.Bones.Count); } } private static void TryAddFallbackJiggleChains(ShlongController source, DisplayRig rig, bool allowSupplement) { if ((Object)(object)rig.DisplayRoot == (Object)null) { return; } Transform shaftCandidate = null; Transform ballCandidate = null; HashSet seen = new HashSet(); ScanRenderer(rig.DickMesh); if (rig.Balls != null) { for (int i = 0; i < rig.Balls.Length; i++) { ScanRenderer(rig.Balls[i]); } } AddFallback(shaftCandidate, isBall: false); if ((Object)(object)ballCandidate != (Object)null && (Object)(object)ballCandidate != (Object)(object)shaftCandidate) { AddFallback(ballCandidate, isBall: true); } if (Plugin.IsDebug && rig.JiggleChains.Count == 0) { Plugin.LogDebug("[RemoteJiggle][FallbackChain] no candidate bones found in renderers source=" + ((Object)((Component)source).gameObject).name); } void AddFallback(Transform t, bool isBall) { if (!((Object)(object)t == (Object)null) && (!allowSupplement || !HasJiggleRoot(rig, t))) { AddSoftJiggleChain(source, rig, t, ((Object)t).name, isBall); } } void ScanRenderer(SkinnedMeshRenderer smr) { if (!((Object)(object)smr == (Object)null) && smr.bones != null) { Transform[] bones = smr.bones; foreach (Transform val in bones) { if (!((Object)(object)val == (Object)null) && seen.Add(val)) { string text = ((Object)val).name.ToLowerInvariant(); bool flag = false; string[] fallbackExcludeKeywords = _fallbackExcludeKeywords; foreach (string value in fallbackExcludeKeywords) { if (text.Contains(value)) { flag = true; break; } } if (!flag) { if ((Object)(object)shaftCandidate == (Object)null) { string[] fallbackShaftKeywords = _fallbackShaftKeywords; foreach (string value2 in fallbackShaftKeywords) { if (text.Contains(value2)) { shaftCandidate = val; break; } } } if ((Object)(object)ballCandidate == (Object)null) { string[] fallbackBallKeywords = _fallbackBallKeywords; foreach (string value3 in fallbackBallKeywords) { if (text.Contains(value3)) { ballCandidate = val; break; } } } } } } } } } private static Vector3 ToDisplayLocalDirection(DisplayRig rig, Vector3 worldVector) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0028: 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) if (rig != null && (Object)(object)rig.DisplayRoot != (Object)null) { return rig.DisplayRoot.transform.InverseTransformDirection(worldVector); } return worldVector; } private static Vector3 ToJiggleDriverLocalDirection(ShlongController source, DisplayRig rig, Vector3 worldVector) { //IL_008c: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) Transform val = null; if ((Object)(object)source != (Object)null && (Object)(object)source.PlayerObj != (Object)null) { val = ((Component)source.PlayerObj).transform; } else if ((Object)(object)source != (Object)null && (Object)(object)((Component)source).transform != (Object)null) { val = ((Component)source).transform; } else if (rig != null && (Object)(object)rig.DisplayRoot != (Object)null) { val = rig.DisplayRoot.transform; } if ((Object)(object)val != (Object)null) { return val.InverseTransformDirection(worldVector); } return worldVector; } private static Vector3 RotationDeltaToDisplayLocal(DisplayRig rig, Quaternion current, Quaternion previous, out float angleDeg) { //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_0003: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) Quaternion val = current * Quaternion.Inverse(previous); Vector3 val2 = default(Vector3); ((Quaternion)(ref val)).ToAngleAxis(ref angleDeg, ref val2); if (angleDeg > 180f) { angleDeg -= 360f; } if (float.IsNaN(val2.x) || float.IsNaN(val2.y) || float.IsNaN(val2.z) || ((Vector3)(ref val2)).sqrMagnitude < 1E-06f) { angleDeg = 0f; return Vector3.zero; } return ToDisplayLocalDirection(rig, ((Vector3)(ref val2)).normalized * angleDeg); } private static Vector3 RotationDeltaToWorldVector(Quaternion current, Quaternion previous, out float angleDeg) { //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_0003: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) Quaternion val = current * Quaternion.Inverse(previous); Vector3 val2 = default(Vector3); ((Quaternion)(ref val)).ToAngleAxis(ref angleDeg, ref val2); if (angleDeg > 180f) { angleDeg -= 360f; } if (float.IsNaN(val2.x) || float.IsNaN(val2.y) || float.IsNaN(val2.z) || ((Vector3)(ref val2)).sqrMagnitude < 1E-06f) { angleDeg = 0f; return Vector3.zero; } return ((Vector3)(ref val2)).normalized * angleDeg; } private static Vector3 MapWorldMotionToJiggleTarget(ShlongController source, DisplayRig rig, Vector3 worldVel, Vector3 worldAngularDeg, float velToDeg, float angToDeg) { //IL_0003: 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_0009: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_002b: 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_007e: 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_0092: 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_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_00ad: 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_00b5: 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_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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ToJiggleDriverLocalDirection(source, rig, worldVel); Vector3 val2 = ToJiggleDriverLocalDirection(source, rig, worldAngularDeg); float num = Mathf.Abs(val.x); float num2 = Mathf.Abs(val.y); float num3 = Mathf.Abs(val.z); if (num2 > num * 1.5f && num2 > num3 * 1.5f) { val.x *= 0.1f; val2.y *= 0.2f; } Vector3 val3 = new Vector3(val.x, 0f - (val.y + val.z * 0.45f), (0f - val.z) * 0.1f) * velToDeg; return val3 + new Vector3(val2.y, (0f - val2.x) * 0.35f, val2.z * 0.2f) * angToDeg; } private static Vector3 MapLocalMotionToJiggleTarget(Vector3 localVel, Vector3 localAngular, float velToDeg, float angToDeg) { //IL_0001: 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_000d: 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_0028: 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_0033: 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_0035: 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_0048: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0069: Unknown result type (might be due to invalid IL or missing references) Vector3 val = new Vector3(localVel.x, 0f - (localVel.y + localVel.z * 0.45f), (0f - localVel.z) * 0.1f) * velToDeg; return val + new Vector3(localAngular.y, (0f - localAngular.x) * 0.35f, localAngular.z * 0.2f) * angToDeg; } private static void UpdateProceduralJiggle(ShlongController source, DisplayRig rig) { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027c: 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_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0391: 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_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04bd: Unknown result type (might be due to invalid IL or missing references) //IL_04c2: Unknown result type (might be due to invalid IL or missing references) //IL_04c4: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: Unknown result type (might be due to invalid IL or missing references) //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_061a: Unknown result type (might be due to invalid IL or missing references) //IL_061f: Unknown result type (might be due to invalid IL or missing references) //IL_0626: Unknown result type (might be due to invalid IL or missing references) //IL_062b: Unknown result type (might be due to invalid IL or missing references) //IL_064c: Unknown result type (might be due to invalid IL or missing references) //IL_0773: Unknown result type (might be due to invalid IL or missing references) //IL_0775: Unknown result type (might be due to invalid IL or missing references) //IL_077b: Unknown result type (might be due to invalid IL or missing references) //IL_0780: Unknown result type (might be due to invalid IL or missing references) //IL_0782: Unknown result type (might be due to invalid IL or missing references) //IL_0794: Unknown result type (might be due to invalid IL or missing references) //IL_0799: Unknown result type (might be due to invalid IL or missing references) //IL_0841: Unknown result type (might be due to invalid IL or missing references) //IL_0859: Unknown result type (might be due to invalid IL or missing references) //IL_0871: Unknown result type (might be due to invalid IL or missing references) //IL_0819: Unknown result type (might be due to invalid IL or missing references) //IL_0827: Unknown result type (might be due to invalid IL or missing references) //IL_0833: Unknown result type (might be due to invalid IL or missing references) //IL_0838: Unknown result type (might be due to invalid IL or missing references) //IL_083d: Unknown result type (might be due to invalid IL or missing references) //IL_07c7: Unknown result type (might be due to invalid IL or missing references) //IL_07be: Unknown result type (might be due to invalid IL or missing references) //IL_08a4: Unknown result type (might be due to invalid IL or missing references) //IL_08a9: Unknown result type (might be due to invalid IL or missing references) //IL_08ad: Unknown result type (might be due to invalid IL or missing references) //IL_08b2: Unknown result type (might be due to invalid IL or missing references) //IL_08b9: Unknown result type (might be due to invalid IL or missing references) //IL_08bf: Unknown result type (might be due to invalid IL or missing references) //IL_08c4: Unknown result type (might be due to invalid IL or missing references) //IL_08c9: Unknown result type (might be due to invalid IL or missing references) //IL_07cc: Unknown result type (might be due to invalid IL or missing references) //IL_090b: Unknown result type (might be due to invalid IL or missing references) //IL_091e: Unknown result type (might be due to invalid IL or missing references) //IL_0923: Unknown result type (might be due to invalid IL or missing references) //IL_092b: Unknown result type (might be due to invalid IL or missing references) //IL_0932: Unknown result type (might be due to invalid IL or missing references) //IL_0938: Unknown result type (might be due to invalid IL or missing references) //IL_093d: Unknown result type (might be due to invalid IL or missing references) //IL_0942: Unknown result type (might be due to invalid IL or missing references) //IL_09b6: Unknown result type (might be due to invalid IL or missing references) //IL_09bd: Unknown result type (might be due to invalid IL or missing references) //IL_09c2: Unknown result type (might be due to invalid IL or missing references) //IL_09c7: Unknown result type (might be due to invalid IL or missing references) //IL_08e0: Unknown result type (might be due to invalid IL or missing references) //IL_08e7: Unknown result type (might be due to invalid IL or missing references) //IL_08ec: Unknown result type (might be due to invalid IL or missing references) //IL_08f3: Unknown result type (might be due to invalid IL or missing references) //IL_08f9: Unknown result type (might be due to invalid IL or missing references) //IL_08fe: Unknown result type (might be due to invalid IL or missing references) //IL_0903: Unknown result type (might be due to invalid IL or missing references) //IL_07e0: Unknown result type (might be due to invalid IL or missing references) //IL_07e2: Unknown result type (might be due to invalid IL or missing references) //IL_07fa: Unknown result type (might be due to invalid IL or missing references) //IL_07ff: Unknown result type (might be due to invalid IL or missing references) //IL_0804: Unknown result type (might be due to invalid IL or missing references) if (PluginConfig.EnableRemoteJiggleExperimental == null || !PluginConfig.EnableRemoteJiggleExperimental.Value || PluginConfig.UseNativeRemoteDynamicBone || (Object)(object)source == (Object)null || rig == null || (Object)(object)rig.HipBone == (Object)null) { return; } if (!rig.LastAppliedVisible) { rig.LastJiggleVisible = false; } else { if (source.IsLocal && (PluginConfig.EnableLocalCosmeticJiggleExperimental == null || !PluginConfig.EnableLocalCosmeticJiggleExperimental.Value)) { return; } if (PluginConfig.RemoteJiggleDebugPulseRoot != null && PluginConfig.RemoteJiggleDebugPulseRoot.Value && PluginConfig.RemoteJiggleDebugPulse != null && PluginConfig.RemoteJiggleDebugPulse.Value) { LastJiggleTickFrame = Time.frameCount; float num = Mathf.Sin(Time.unscaledTime * 6f) * 8f; Transform val = (((Object)(object)rig.CachedSizeBone != (Object)null) ? rig.CachedSizeBone : (((Object)(object)rig.DisplayRoot != (Object)null) ? rig.DisplayRoot.transform : null)); if ((Object)(object)val != (Object)null) { val.localRotation *= Quaternion.Euler(num, 0f, 0f); if (Plugin.IsDebug && Time.frameCount % 120 == 0) { Plugin.LogDebug("[RemoteJiggle][DebugPulseRoot] target=" + ((Object)val).name + " pulse=" + num.ToString("F2")); } } return; } if (rig.JiggleChains == null || rig.JiggleChains.Count == 0) { LastNoChainsCount++; return; } if (!rig.LastJiggleVisible) { ResetJiggleChains(rig); rig.LastJiggleVisible = true; return; } float num2 = Mathf.Clamp(Time.deltaTime, 0.001f, 0.05f); Transform val2 = null; val2 = (((Object)(object)source.PlayerObj != (Object)null) ? ((Component)source.PlayerObj).transform : ((!((Object)(object)((Component)source).transform != (Object)null)) ? rig.HipBone : ((Component)source).transform)); if ((Object)(object)val2 == (Object)null) { return; } Vector3 position = val2.position; Quaternion rotation = val2.rotation; Vector3 position2 = rig.HipBone.position; Quaternion rotation2 = rig.HipBone.rotation; if (!rig.HasLastDriverPose || !rig.HasLastHipPose) { rig.LastDriverWorldPos = position; rig.LastDriverWorldRot = rotation; rig.HasLastDriverPose = true; rig.LastHipWorldPos = position2; rig.LastHipWorldRot = rotation2; rig.HasLastHipPose = true; return; } Vector3 val3 = (position - rig.LastDriverWorldPos) / num2; Vector3 val4 = (position2 - rig.LastHipWorldPos) / num2; Vector3 val5 = ToDisplayLocalDirection(rig, val3); Vector3 val6 = ToDisplayLocalDirection(rig, val4); float angleDeg; Vector3 val7 = RotationDeltaToWorldVector(rotation, rig.LastDriverWorldRot, out angleDeg); float angleDeg2; Vector3 val8 = RotationDeltaToWorldVector(rotation2, rig.LastHipWorldRot, out angleDeg2); Vector3 val9 = ToDisplayLocalDirection(rig, val7); Vector3 val10 = ToDisplayLocalDirection(rig, val8); rig.LastDriverWorldPos = position; rig.LastDriverWorldRot = rotation; rig.LastHipWorldPos = position2; rig.LastHipWorldRot = rotation2; Vector3 val11 = val4 - val3; Vector3 val12 = val6 - val5; Vector3 val13 = val8 - val7; Vector3 val14 = val10 - val9; float num3 = angleDeg2 - angleDeg; float num4 = ((PluginConfig.RemoteJiggleStrength != null) ? Mathf.Clamp(PluginConfig.RemoteJiggleStrength.Value, 0f, 6f) : 1f); float num5 = ((PluginConfig.RemoteJiggleStiffness != null) ? Mathf.Max(0.1f, PluginConfig.RemoteJiggleStiffness.Value) : 14f); float num6 = ((PluginConfig.RemoteJiggleDamping != null) ? Mathf.Clamp01(PluginConfig.RemoteJiggleDamping.Value) : 0.82f); float num7 = ((PluginConfig.RemoteJiggleMaxDegrees != null) ? Mathf.Clamp(PluginConfig.RemoteJiggleMaxDegrees.Value, 0f, 45f) : 12f); float velToDeg = ((PluginConfig.RemoteJiggleVelocityToDegrees != null) ? Mathf.Clamp(PluginConfig.RemoteJiggleVelocityToDegrees.Value, 0f, 8f) : 1.25f); float angToDeg = ((PluginConfig.RemoteJiggleAngularToDegrees != null) ? Mathf.Clamp(PluginConfig.RemoteJiggleAngularToDegrees.Value, 0f, 4f) : 0.35f); float num8 = ((PluginConfig.RemoteJiggleMinimumKick != null) ? Mathf.Clamp(PluginConfig.RemoteJiggleMinimumKick.Value, 0f, 3f) : 0.25f); Vector3 worldVel = val3 + val11 * 0.75f; Vector3 worldAngularDeg = val7 + val13 * 0.75f; bool flag = ((Vector3)(ref val3)).magnitude > 0.15f || Mathf.Abs(angleDeg) > 1f; bool flag2 = ((Vector3)(ref val11)).magnitude > 0.04f || Mathf.Abs(num3) > 0.35f; bool flag3 = flag || flag2; float num9 = 0f; if (PluginConfig.RemoteJiggleDebugPulse != null && PluginConfig.RemoteJiggleDebugPulse.Value) { num9 = Mathf.Sin(Time.unscaledTime * 6f) * Mathf.Min(num7, 10f); } LastJiggleTickFrame = Time.frameCount; bool flag4 = Plugin.IsDebug && Time.frameCount % 300 == 0; int num10 = 0; ProceduralJiggleBone proceduralJiggleBone = null; float num11 = 0f; for (int i = 0; i < rig.JiggleChains.Count; i++) { ProceduralJiggleChain proceduralJiggleChain = rig.JiggleChains[i]; if (proceduralJiggleChain == null || proceduralJiggleChain.Bones == null) { continue; } if (rig.ArousalControlsShaftJiggle && !proceduralJiggleChain.IsBall && source.ArousalTarget <= 0.001f) { for (int j = 0; j < proceduralJiggleChain.Bones.Count; j++) { ProceduralJiggleBone proceduralJiggleBone2 = proceduralJiggleChain.Bones[j]; if (proceduralJiggleBone2 != null) { proceduralJiggleBone2.Offset = Vector3.zero; proceduralJiggleBone2.Velocity = Vector3.zero; if ((Object)(object)proceduralJiggleBone2.Bone != (Object)null) { proceduralJiggleBone2.Bone.localRotation = proceduralJiggleBone2.BaseLocalRotation; } } } continue; } float num12 = Mathf.Clamp01(proceduralJiggleChain.DbDamping); float num13 = Mathf.Clamp01(proceduralJiggleChain.DbElasticity); float num14 = Mathf.Clamp01(proceduralJiggleChain.DbStiffness); float num15 = Mathf.Clamp01(proceduralJiggleChain.DbInert); float num16 = (proceduralJiggleChain.IsBall ? 0.65f : 1f); float num17 = Mathf.Lerp(0.5f, 1.25f, num15); float num18 = Mathf.Max(0.1f, num5 * Mathf.Lerp(0.45f, 1.15f, num14)); float num19 = Mathf.Clamp01(num6 - num12 * 0.08f); float num20 = num13 * Mathf.Max(0.1f, num5) * 0.2f; for (int k = 0; k < proceduralJiggleChain.Bones.Count; k++) { ProceduralJiggleBone proceduralJiggleBone3 = proceduralJiggleChain.Bones[k]; if (proceduralJiggleBone3 != null && !((Object)(object)proceduralJiggleBone3.Bone == (Object)null)) { num10++; if (proceduralJiggleBone == null) { proceduralJiggleBone = proceduralJiggleBone3; } Vector3 val15 = MapWorldMotionToJiggleTarget(source, rig, worldVel, worldAngularDeg, velToDeg, angToDeg); Vector3 val16 = val15 * (num4 * num16 * proceduralJiggleBone3.Weight * num17); if (((Vector3)(ref val16)).magnitude < num8 && flag3) { Vector3 val17 = ((((Vector3)(ref val15)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val15)).normalized : Vector3.up); float num21 = (flag ? 1f : 0.45f); val16 += val17 * (num8 * num4 * num16 * proceduralJiggleBone3.Weight * num17 * num21); } if (num9 != 0f) { val16 += new Vector3(num9, 0f, 0f) * proceduralJiggleBone3.Weight; } val16.x = Mathf.Clamp(val16.x, 0f - num7, num7); val16.y = Mathf.Clamp(val16.y, 0f - num7, num7); val16.z = Mathf.Clamp(val16.z, 0f - num7, num7); if (((Vector3)(ref val16)).magnitude > num11) { num11 = ((Vector3)(ref val16)).magnitude; } proceduralJiggleBone3.Velocity += (val16 - proceduralJiggleBone3.Offset) * num18 * num2; if (num20 > 0f) { proceduralJiggleBone3.Velocity += -proceduralJiggleBone3.Offset * num20 * num2; } proceduralJiggleBone3.Velocity *= Mathf.Pow(num19, num2 * 60f); proceduralJiggleBone3.Offset += proceduralJiggleBone3.Velocity * num2; proceduralJiggleBone3.Offset.x = Mathf.Clamp(proceduralJiggleBone3.Offset.x, 0f - num7, num7); proceduralJiggleBone3.Offset.y = Mathf.Clamp(proceduralJiggleBone3.Offset.y, 0f - num7, num7); proceduralJiggleBone3.Offset.z = Mathf.Clamp(proceduralJiggleBone3.Offset.z, 0f - num7, num7); proceduralJiggleBone3.Bone.localRotation = proceduralJiggleBone3.BaseLocalRotation * Quaternion.Euler(proceduralJiggleBone3.Offset); } } } rig.LastJiggleTargetMagnitude = num11; LastJiggleTargetMagnitude = num11; if (flag4) { Plugin.LogDebug("[RemoteJiggle][Tick] source=" + ((Object)((Component)source).gameObject).name + " chains=" + rig.JiggleChains.Count + " bones=" + num10 + " driverVel=" + ((Vector3)(ref val5)).ToString("F2") + " animVel=" + ((Vector3)(ref val12)).ToString("F2") + " driverAngle=" + angleDeg.ToString("F1") + " animAngle=" + num3.ToString("F1") + " targetMagnitude=" + rig.LastJiggleTargetMagnitude.ToString("F2") + " strength=" + num4.ToString("F2") + " stiffness=" + num5.ToString("F1") + " damping=" + num6.ToString("F2") + " maxDeg=" + num7.ToString("F1") + " firstBoneOffset=" + ((proceduralJiggleBone != null) ? ((Vector3)(ref proceduralJiggleBone.Offset)).ToString("F2") : "no-live-bone")); } } } private static void ResetJiggleChains(DisplayRig rig) { //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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (rig == null || rig.JiggleChains == null) { return; } for (int i = 0; i < rig.JiggleChains.Count; i++) { ProceduralJiggleChain proceduralJiggleChain = rig.JiggleChains[i]; if (proceduralJiggleChain == null) { continue; } for (int j = 0; j < proceduralJiggleChain.Bones.Count; j++) { ProceduralJiggleBone proceduralJiggleBone = proceduralJiggleChain.Bones[j]; if (proceduralJiggleBone != null) { proceduralJiggleBone.Offset = Vector3.zero; proceduralJiggleBone.Velocity = Vector3.zero; if ((Object)(object)proceduralJiggleBone.Bone != (Object)null) { proceduralJiggleBone.Bone.localRotation = proceduralJiggleBone.BaseLocalRotation; } } } } rig.HasLastHipPose = false; rig.HasLastDriverPose = false; rig.LastJiggleTargetMagnitude = 0f; } private static void TryResyncMaterial(ShlongController source, DisplayRig rig) { if ((Object)(object)rig.DickMesh == (Object)null) { return; } PresetData presetData = Plugin.Presets?.GetPreset(rig.SpawnedPresetIndex); if (presetData != null && presetData.AssetSource == PresetAssetSource.Test) { Material bodyMaterial = GetBodyMaterial(source); if ((Object)(object)bodyMaterial == (Object)null) { rig.TestPresetMaterialReady = false; if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][Retry] source body material not ready source=" + ((Object)((Component)source).gameObject).name + " preset=" + presetData.Id + " attempt=" + rig.MaterialResyncCount + " frame=" + Time.frameCount); } return; } Shader shader = bodyMaterial.shader; Texture mainTexture = bodyMaterial.mainTexture; string characterColorAdjustmentSignature = MaterialSkinUtility.GetCharacterColorAdjustmentSignature(bodyMaterial); if ((Object)(object)rig.LastRaceBodyShader == (Object)(object)shader && (Object)(object)rig.LastRaceBodyTexture == (Object)(object)mainTexture && rig.LastRaceBodyAdjustmentSignature == characterColorAdjustmentSignature && rig.MaterialResyncCount > 0 && rig.TestPresetMaterialReady) { if (rig.MaterialResyncCount < 60) { rig.MaterialResyncCount = 60; } return; } if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][Resync] source=" + ((Object)((Component)source).gameObject).name + " preset=" + presetData.Id + " sourceMat=" + ((Object)bodyMaterial).name + " sourceShader=" + (((Object)(object)shader != (Object)null) ? ((Object)shader).name : "") + " sourceTex=" + (((Object)(object)mainTexture != (Object)null) ? ((Object)mainTexture).name : "") + " attempt=" + rig.MaterialResyncCount + " frame=" + Time.frameCount); } bool flag = false; if (rig.TemplateDickMaterials != null && rig.TemplateDickMaterials.Length != 0) { ((Renderer)rig.DickMesh).sharedMaterials = (Material[])rig.TemplateDickMaterials.Clone(); } if (rig.Balls != null) { for (int i = 0; i < rig.Balls.Length; i++) { if ((Object)(object)rig.Balls[i] != (Object)null && rig.TemplateMaterialsByRenderer.TryGetValue(rig.Balls[i], out var value) && value != null) { ((Renderer)rig.Balls[i]).sharedMaterials = (Material[])value.Clone(); } } } flag |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(rig.DickMesh, bodyMaterial, "Dick", presetData.Id); if (rig.Balls != null) { for (int j = 0; j < rig.Balls.Length; j++) { if ((Object)(object)rig.Balls[j] != (Object)null) { flag |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(rig.Balls[j], bodyMaterial, "Ball", presetData.Id); } } } ApplyTestPresetTextureFallbacks(rig, presetData, bodyMaterial); rig.LastRaceBodyShader = shader; rig.LastRaceBodyTexture = mainTexture; rig.LastRaceBodyAdjustmentSignature = characterColorAdjustmentSignature; rig.MaterialResyncCount++; rig.TestPresetMaterialReady = true; rig.OriginalBodyMaterial = bodyMaterial; CacheOriginalShlongMaterialsFromCurrentNeutralState(rig); ApplyDickColor(rig); ApplyBallColor(rig); if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][ResyncApplied] source=" + ((Object)((Component)source).gameObject).name + " preset=" + presetData.Id + " changed=" + flag + " reappliedColor=true frame=" + Time.frameCount); } } else { if (rig.MaterialResyncCount >= 3) { return; } Material bodyMaterial2 = GetBodyMaterial(source); if ((Object)(object)bodyMaterial2 == (Object)null) { return; } bool flag2 = false; if (rig.TemplateDickMaterials != null && rig.TemplateDickMaterials.Length != 0) { ((Renderer)rig.DickMesh).sharedMaterials = (Material[])rig.TemplateDickMaterials.Clone(); } flag2 |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(rig.DickMesh, bodyMaterial2, "Dick", (presetData != null) ? presetData.Id : "original"); if (rig.Balls != null) { for (int k = 0; k < rig.Balls.Length; k++) { SkinnedMeshRenderer val = rig.Balls[k]; if (!((Object)(object)val == (Object)null)) { if (rig.TemplateMaterialsByRenderer.TryGetValue(val, out var value2) && value2 != null) { ((Renderer)val).sharedMaterials = (Material[])value2.Clone(); } flag2 |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(val, bodyMaterial2, "Ball", (presetData != null) ? presetData.Id : "original"); } } } if (flag2) { rig.MaterialResyncCount++; rig.TestPresetMaterialReady = true; rig.OriginalBodyMaterial = bodyMaterial2; CacheOriginalShlongMaterialsFromCurrentNeutralState(rig); ApplyDickColor(rig); ApplyBallColor(rig); } } } private static Material GetBodyMaterial(ShlongController source) { RaceData race = Plugin.Presets.GetRace(source.RaceIndex); if (race == null) { return null; } Transform val = ((Component)source).transform.RecursiveFindChild(race.BodyMesh); if ((Object)(object)val == (Object)null) { return null; } SkinnedMeshRenderer component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null && ((Renderer)component).sharedMaterials != null && race.MaterialSlot >= 0 && race.MaterialSlot < ((Renderer)component).sharedMaterials.Length) { Material val2 = ((Renderer)component).sharedMaterials[race.MaterialSlot]; if (MaterialSkinUtility.IsMaskOrInvalidBodyMaterial(val2)) { return null; } return val2; } return null; } } internal static class MaterialSkinUtility { private static readonly string[] PreferredSourceTextureProperties = new string[12] { "_MainTex", "_BaseMap", "_BaseColorMap", "_Albedo", "_AlbedoTex", "_Diffuse", "_DiffuseTex", "_BaseTex", "_ColorMap", "_ColorTex", "_BodyTex", "_SkinTex" }; private static readonly string[] DestinationMainTextureProperties = new string[10] { "_MainTex", "_BaseMap", "_BaseColorMap", "_Albedo", "_AlbedoTex", "_Diffuse", "_DiffuseTex", "_BaseTex", "_ColorMap", "_ColorTex" }; private static readonly string[] CharacterAdjustmentTokens = new string[6] { "hue", "bright", "contrast", "saturat", "hsv", "hbc" }; private static readonly string[] CommonCharacterAdjustmentProperties = new string[14] { "_Hue", "_HueShift", "_HueOffset", "_Brightness", "_Bright", "_Contrast", "_Saturation", "_Sat", "_HSV", "_Hsv", "_HBC", "_HueBrightnessContrast", "_ColorAdjust", "_ColorAdjustment" }; private static readonly string[] CommonBodyTintProperties = new string[2] { "_ColorTint", "_Tint" }; private static string NormalizeMaterialRoleName(Material mat) { if ((Object)(object)mat == (Object)null) { return string.Empty; } string text = ((Object)mat).name ?? ""; text = text.Replace(" (Instance)", ""); text = text.Replace("_RaceShaded", ""); return text.Replace("_ShlongColorRuntime", ""); } internal static bool IsBallsSheathMaterial(Material mat) { string text = NormalizeMaterialRoleName(mat); if (text.IndexOf("BodyMat2", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (text.IndexOf("Sheath", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (text.IndexOf("Ball", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return false; } internal static bool HasBallsSheathMaterialSlot(Material[] mats) { if (mats == null) { return false; } for (int i = 0; i < mats.Length; i++) { if (IsBallsSheathMaterial(mats[i])) { return true; } } return false; } internal static bool IsMaskOrInvalidBodyMaterial(Material mat) { if ((Object)(object)mat == (Object)null) { return true; } Shader shader = mat.shader; if ((Object)(object)shader == (Object)null) { return true; } string name = ((Object)shader).name; if (string.Equals(name, "Sprites/Mask", StringComparison.Ordinal)) { return true; } if (string.Equals(name, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { return true; } string name2 = ((Object)mat).name; if (!string.IsNullOrEmpty(name2) && name2.StartsWith("Sprites-Mask", StringComparison.Ordinal)) { return true; } return false; } internal static Material GetRaceBodyMaterial(SkinnedMeshRenderer bodySMR, RaceData race) { if ((Object)(object)bodySMR == (Object)null || race == null) { return null; } if (((Renderer)bodySMR).sharedMaterials == null) { return null; } if (race.MaterialSlot < 0 || race.MaterialSlot >= ((Renderer)bodySMR).sharedMaterials.Length) { return null; } Material val = ((Renderer)bodySMR).sharedMaterials[race.MaterialSlot]; if (IsMaskOrInvalidBodyMaterial(val)) { return null; } return val; } internal static Material BuildRaceShadedMaterial(Material original, Material raceBodyMaterial) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if ((Object)(object)original == (Object)null && (Object)(object)raceBodyMaterial == (Object)null) { return null; } Material val = ((!((Object)(object)raceBodyMaterial != (Object)null)) ? new Material(original) : new Material(raceBodyMaterial)); if ((Object)(object)raceBodyMaterial != (Object)null && (Object)(object)raceBodyMaterial.shader != (Object)null) { val.shader = raceBodyMaterial.shader; } string text = (((Object)(object)original != (Object)null) ? ((Object)original).name.Replace(" (Instance)", "") : (((Object)(object)raceBodyMaterial != (Object)null) ? ((Object)raceBodyMaterial).name.Replace(" (Instance)", "") : "Shlong")); if ((Object)(object)original != (Object)null) { val.enableInstancing = original.enableInstancing; } bool flag = CopyBodyAtlasTextureToRaceShader(raceBodyMaterial, val); if (!flag && (Object)(object)original != (Object)null) { CopyOriginalVisualPropertiesToRaceShader(original, val); } else { ApplyNeutralVisualColorToDestination(val); } ((Object)val).name = text + (flag ? "_TextureOriginal_RaceShader_BodyAtlas" : "_TextureOriginal_RaceShader"); NeutralizeCharacterColorAdjustmentProperties(val); if ((Object)(object)raceBodyMaterial != (Object)null) { val.renderQueue = raceBodyMaterial.renderQueue; } else if ((Object)(object)original != (Object)null) { val.renderQueue = original.renderQueue; } return val; } private static bool CopyBodyAtlasTextureToRaceShader(Material raceBodyMaterial, Material dst) { //IL_00b7: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)raceBodyMaterial == (Object)null || (Object)(object)dst == (Object)null) { return false; } if (!TryGetBestVisualTexture(raceBodyMaterial, out var texture, out var scale, out var offset, out var propertyName) || (Object)(object)texture == (Object)null) { return false; } for (int i = 0; i < DestinationMainTextureProperties.Length; i++) { string text = DestinationMainTextureProperties[i]; try { if (dst.HasProperty(text)) { dst.SetTexture(text, texture); dst.SetTextureScale(text, scale); dst.SetTextureOffset(text, offset); } } catch { } } try { dst.mainTexture = texture; dst.mainTextureScale = scale; dst.mainTextureOffset = offset; } catch { } if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][BodyAtlasBase] dst=" + ((Object)dst).name + " raceBody=" + ((Object)raceBodyMaterial).name + " tex=" + ((Object)texture).name + " prop=" + (propertyName ?? "") + " frame=" + Time.frameCount); } return true; } private static void ApplyNeutralVisualColorToDestination(Material dst) { //IL_0028: 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_007c: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)dst == (Object)null) { return; } try { if (dst.HasProperty("_ColorTint")) { dst.SetColor("_ColorTint", Color.white); } } catch { } try { if (dst.HasProperty("_Tint")) { dst.SetColor("_Tint", Color.white); } } catch { } try { if (dst.HasProperty("_TintColor")) { dst.SetColor("_TintColor", Color.white); } } catch { } try { if (dst.HasProperty("_Color")) { dst.SetColor("_Color", Color.white); } } catch { } try { if (dst.HasProperty("_BaseColor")) { dst.SetColor("_BaseColor", Color.white); } } catch { } try { if (dst.HasProperty("_EmissionColor")) { dst.SetColor("_EmissionColor", Color.black); } } catch { } } private static void CopyOriginalVisualPropertiesToRaceShader(Material original, Material dst) { if (!((Object)(object)original == (Object)null) && !((Object)(object)dst == (Object)null)) { CopyMainTextureLikeProperties(original, dst); CopyMainColorLikeProperties(original, dst); CopyAllSameNamedTextureProperties(original, dst); if (!CopyBestSourceTextureToMainSlots(original, dst)) { ApplyBlankTextureToMainSlots(dst); } ApplySourceVisualColorToDestination(original, dst); } } private static void CopyAllSameNamedTextureProperties(Material src, Material dst) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_00be: 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) if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null) { return; } try { Shader shader = src.shader; if ((Object)(object)shader == (Object)null) { return; } int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if ((int)shader.GetPropertyType(i) != 4) { continue; } string propertyName = shader.GetPropertyName(i); if (!string.IsNullOrEmpty(propertyName) && src.HasProperty(propertyName) && dst.HasProperty(propertyName)) { Texture texture = src.GetTexture(propertyName); if ((Object)(object)texture != (Object)null) { dst.SetTexture(propertyName, texture); } dst.SetTextureScale(propertyName, src.GetTextureScale(propertyName)); dst.SetTextureOffset(propertyName, src.GetTextureOffset(propertyName)); } } } catch { } } private static bool CopyBestSourceTextureToMainSlots(Material src, Material dst) { //IL_00b7: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null) { return false; } if (!TryFindBestSourceTexture(src, out var texture, out var scale, out var offset, out var propertyName) || (Object)(object)texture == (Object)null) { return false; } for (int i = 0; i < DestinationMainTextureProperties.Length; i++) { string text = DestinationMainTextureProperties[i]; try { if (dst.HasProperty(text)) { dst.SetTexture(text, texture); dst.SetTextureScale(text, scale); dst.SetTextureOffset(text, offset); } } catch { } } try { dst.mainTexture = texture; dst.mainTextureScale = scale; dst.mainTextureOffset = offset; } catch { } if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin] Copied best source texture src=" + ((Object)src).name + " prop=" + propertyName + " tex=" + ((Object)texture).name + " dst=" + ((Object)dst).name); } return true; } internal static void ApplyBlankTextureToMainSlots(Material dst) { //IL_0082: 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_0042: 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)dst == (Object)null) { return; } Texture whiteTexture = (Texture)(object)Texture2D.whiteTexture; for (int i = 0; i < DestinationMainTextureProperties.Length; i++) { string text = DestinationMainTextureProperties[i]; try { if (dst.HasProperty(text)) { dst.SetTexture(text, whiteTexture); dst.SetTextureScale(text, Vector2.one); dst.SetTextureOffset(text, Vector2.zero); } } catch { } } try { dst.mainTexture = whiteTexture; dst.mainTextureScale = Vector2.one; dst.mainTextureOffset = Vector2.zero; } catch { } } internal static Color GetBestSourceVisualColor(Material src) { //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_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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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_00c4: 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_00d1: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00a1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)src == (Object)null) { return Color.white; } Color c = Color.white; bool flag = false; string[] array = new string[5] { "_ColorTint", "_Tint", "_TintColor", "_Color", "_BaseColor" }; foreach (string text in array) { try { if (src.HasProperty(text)) { Color color = src.GetColor(text); if (!flag) { c = color; flag = true; } if (!ApproximatelyWhite(color)) { return NormalizeAlpha(color); } } } catch { } } return flag ? NormalizeAlpha(c) : Color.white; } private static bool ApproximatelyWhite(Color c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) return Mathf.Abs(c.r - 1f) < 0.003f && Mathf.Abs(c.g - 1f) < 0.003f && Mathf.Abs(c.b - 1f) < 0.003f; } internal static bool ApproximatelyBlack(Color c) { //IL_0001: 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_0025: Unknown result type (might be due to invalid IL or missing references) return Mathf.Abs(c.r) < 0.003f && Mathf.Abs(c.g) < 0.003f && Mathf.Abs(c.b) < 0.003f; } internal static bool HasUsableVisualTexture(Material mat) { Texture texture; Vector2 scale; Vector2 offset; string propertyName; return TryFindBestSourceTexture(mat, out texture, out scale, out offset, out propertyName) && (Object)(object)texture != (Object)null; } internal static Texture GetBestVisualTexture(Material mat) { if (TryFindBestSourceTexture(mat, out var texture, out var _, out var _, out var _)) { return texture; } return null; } internal static bool TryGetBestVisualTexture(Material mat, out Texture texture, out Vector2 scale, out Vector2 offset, out string propertyName) { return TryFindBestSourceTexture(mat, out texture, out scale, out offset, out propertyName); } private static Color NormalizeAlpha(Color c) { //IL_0001: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) return new Color(c.r, c.g, c.b, 1f); } private static void ApplySourceVisualColorToDestination(Material src, Material dst) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null) { return; } Color val = GetBestSourceVisualColor(src); if (ApproximatelyBlack(val) && HasUsableVisualTexture(src)) { val = Color.white; } try { if (dst.HasProperty("_ColorTint")) { dst.SetColor("_ColorTint", val); } } catch { } try { if (dst.HasProperty("_Tint")) { dst.SetColor("_Tint", val); } } catch { } try { if (dst.HasProperty("_TintColor")) { dst.SetColor("_TintColor", val); } } catch { } try { if (dst.HasProperty("_Color")) { dst.SetColor("_Color", val); } } catch { } try { if (dst.HasProperty("_BaseColor")) { dst.SetColor("_BaseColor", val); } } catch { } } private static bool TryFindBestSourceTexture(Material src, out Texture texture, out Vector2 scale, out Vector2 offset, out string propertyName) { //IL_0005: 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_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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Invalid comparison between Unknown and I4 //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Invalid comparison between Unknown and I4 texture = null; scale = Vector2.one; offset = Vector2.zero; propertyName = null; if ((Object)(object)src == (Object)null) { return false; } for (int i = 0; i < PreferredSourceTextureProperties.Length; i++) { if (TryGetTextureFromProperty(src, PreferredSourceTextureProperties[i], out texture, out scale, out offset)) { propertyName = PreferredSourceTextureProperties[i]; return true; } } try { if ((Object)(object)src.mainTexture != (Object)null) { texture = src.mainTexture; scale = src.mainTextureScale; offset = src.mainTextureOffset; propertyName = "mainTexture"; return true; } } catch { } try { Shader shader = src.shader; if ((Object)(object)shader == (Object)null) { return false; } int propertyCount = shader.GetPropertyCount(); for (int j = 0; j < propertyCount; j++) { if ((int)shader.GetPropertyType(j) == 4) { string propertyName2 = shader.GetPropertyName(j); if (LooksLikeColorTextureProperty(propertyName2) && TryGetTextureFromProperty(src, propertyName2, out texture, out scale, out offset)) { propertyName = propertyName2; return true; } } } for (int k = 0; k < propertyCount; k++) { if ((int)shader.GetPropertyType(k) == 4) { string propertyName3 = shader.GetPropertyName(k); if (!LooksLikeUtilityTextureProperty(propertyName3) && TryGetTextureFromProperty(src, propertyName3, out texture, out scale, out offset)) { propertyName = propertyName3; return true; } } } } catch { } return false; } private static bool TryGetTextureFromProperty(Material mat, string prop, out Texture texture, out Vector2 scale, out Vector2 offset) { //IL_0005: 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_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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_0091: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) texture = null; scale = Vector2.one; offset = Vector2.zero; try { if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(prop) || !mat.HasProperty(prop)) { return false; } texture = mat.GetTexture(prop); if ((Object)(object)texture == (Object)null) { return false; } scale = mat.GetTextureScale(prop); offset = mat.GetTextureOffset(prop); return true; } catch { texture = null; scale = Vector2.one; offset = Vector2.zero; return false; } } private static bool LooksLikeColorTextureProperty(string prop) { if (string.IsNullOrEmpty(prop)) { return false; } string text = prop.ToLowerInvariant(); if (LooksLikeUtilityTextureProperty(text)) { return false; } return text.IndexOf("main", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("base", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("albedo", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("diffuse", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("color", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("body", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("skin", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("tex", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool LooksLikeUtilityTextureProperty(string prop) { if (string.IsNullOrEmpty(prop)) { return false; } string text = prop.ToLowerInvariant(); return text.IndexOf("normal", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("bump", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("metal", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("rough", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("smooth", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("mask", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("occlusion", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("emission", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("spec", StringComparison.OrdinalIgnoreCase) >= 0; } internal static bool ShouldCopyCharacterColorAdjustments() { return true; } internal static void CopyCharacterColorAdjustmentProperties(Material src, Material dst) { if (ShouldCopyCharacterColorAdjustments()) { CopyCharacterColorAdjustmentPropertiesForced(src, dst); } } internal static void CopyCharacterColorAdjustmentPropertiesForced(Material src, Material dst) { if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null) { return; } for (int i = 0; i < CommonCharacterAdjustmentProperties.Length; i++) { CopyMaterialPropertyIfPresent(src, dst, CommonCharacterAdjustmentProperties[i]); } try { Shader shader = src.shader; if ((Object)(object)shader == (Object)null) { return; } int propertyCount = shader.GetPropertyCount(); for (int j = 0; j < propertyCount; j++) { string propertyName = shader.GetPropertyName(j); if (LooksLikeCharacterAdjustmentProperty(propertyName)) { CopyMaterialPropertyIfPresent(src, dst, propertyName); } } } catch { } } internal static void NeutralizeCharacterColorAdjustmentProperties(Material dst) { if ((Object)(object)dst == (Object)null) { return; } for (int i = 0; i < CommonCharacterAdjustmentProperties.Length; i++) { NeutralizeCharacterAdjustmentPropertyIfPresent(dst, CommonCharacterAdjustmentProperties[i]); } try { Shader shader = dst.shader; if ((Object)(object)shader == (Object)null) { return; } int propertyCount = shader.GetPropertyCount(); for (int j = 0; j < propertyCount; j++) { string propertyName = shader.GetPropertyName(j); if (LooksLikeCharacterAdjustmentProperty(propertyName)) { NeutralizeCharacterAdjustmentPropertyIfPresent(dst, propertyName); } } } catch { } } internal static string GetCharacterColorAdjustmentSignature(Material src) { if ((Object)(object)src == (Object)null) { return "hbc:null"; } bool flag = ShouldCopyCharacterColorAdjustments(); StringBuilder stringBuilder = new StringBuilder(160); stringBuilder.Append(flag ? "hbc:on;" : "hbc:disabled;"); AppendBodyTintSignature(src, stringBuilder); if (!flag) { return stringBuilder.ToString(); } for (int i = 0; i < CommonCharacterAdjustmentProperties.Length; i++) { AppendMaterialPropertySignature(src, CommonCharacterAdjustmentProperties[i], stringBuilder); } try { Shader shader = src.shader; if ((Object)(object)shader != (Object)null) { int propertyCount = shader.GetPropertyCount(); for (int j = 0; j < propertyCount; j++) { string propertyName = shader.GetPropertyName(j); if (LooksLikeCharacterAdjustmentProperty(propertyName)) { AppendMaterialPropertySignature(src, propertyName, stringBuilder); } } } } catch { } return stringBuilder.ToString(); } private static bool LooksLikeCharacterAdjustmentProperty(string propName) { if (string.IsNullOrEmpty(propName)) { return false; } string text = propName.ToLowerInvariant(); if (text == "_color" || text == "_basecolor" || text == "_tintcolor") { return false; } for (int i = 0; i < CharacterAdjustmentTokens.Length; i++) { if (text.IndexOf(CharacterAdjustmentTokens[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static void CopyMaterialPropertyIfPresent(Material src, Material dst, string propName) { //IL_0051: 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_0055: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected I4, but got Unknown //IL_00a1: 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_00e4: 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) if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null || string.IsNullOrEmpty(propName) || !TryGetDeclaredPropertyType(src, propName, out var type) || !TryGetDeclaredPropertyType(dst, propName, out var type2) || (type != type2 && (!IsScalarPropertyType(type) || !IsScalarPropertyType(type2)))) { return; } try { ShaderPropertyType val = type; ShaderPropertyType val2 = val; switch ((int)val2) { case 0: dst.SetColor(propName, src.GetColor(propName)); break; case 1: dst.SetVector(propName, src.GetVector(propName)); break; case 4: { Texture texture = src.GetTexture(propName); if ((Object)(object)texture != (Object)null) { dst.SetTexture(propName, texture); } dst.SetTextureScale(propName, src.GetTextureScale(propName)); dst.SetTextureOffset(propName, src.GetTextureOffset(propName)); break; } default: dst.SetFloat(propName, src.GetFloat(propName)); break; } } catch { } } private static void NeutralizeCharacterAdjustmentPropertyIfPresent(Material mat, string propName) { //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_0030: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected I4, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(propName) || !TryGetDeclaredPropertyType(mat, propName, out var type)) { return; } try { ShaderPropertyType val = type; ShaderPropertyType val2 = val; switch ((int)val2) { case 0: mat.SetColor(propName, GetNeutralAdjustmentColor(propName)); break; case 1: mat.SetVector(propName, GetNeutralAdjustmentVector(propName)); break; case 4: break; default: mat.SetFloat(propName, GetNeutralAdjustmentFloat(propName)); break; } } catch { } } private static Color GetNeutralAdjustmentColor(string propName) { //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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ba: Unknown result type (might be due to invalid IL or missing references) Vector4 neutralAdjustmentVector = GetNeutralAdjustmentVector(propName); string text = (propName ?? string.Empty).ToLowerInvariant(); if (text.IndexOf("hbc", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("hsv", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("coloradjust", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("coloradjustment", StringComparison.OrdinalIgnoreCase) >= 0) { return new Color(neutralAdjustmentVector.x, neutralAdjustmentVector.y, neutralAdjustmentVector.z, neutralAdjustmentVector.w); } if (text.IndexOf("hue", StringComparison.OrdinalIgnoreCase) >= 0) { return new Color(0f, 0f, 0f, 1f); } return Color.white; } private static float GetNeutralAdjustmentFloat(string propName) { string text = (propName ?? string.Empty).ToLowerInvariant(); if (text.IndexOf("hue", StringComparison.OrdinalIgnoreCase) >= 0) { return 0f; } if (text.IndexOf("bright", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("contrast", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("saturat", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("sat", StringComparison.OrdinalIgnoreCase) >= 0) { return 1f; } return 0f; } private static Vector4 GetNeutralAdjustmentVector(string propName) { //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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) string text = (propName ?? string.Empty).ToLowerInvariant(); if (text.IndexOf("hbc", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("hsv", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("coloradjust", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("coloradjustment", StringComparison.OrdinalIgnoreCase) >= 0) { return new Vector4(0f, 1f, 1f, 1f); } return Vector4.zero; } private static bool TryGetDeclaredPropertyType(Material mat, string propName, out ShaderPropertyType type) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected I4, but got Unknown type = (ShaderPropertyType)2; if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(propName)) { return false; } Shader shader = mat.shader; if ((Object)(object)shader == (Object)null) { return false; } int num; try { num = shader.FindPropertyIndex(propName); } catch { return false; } if (num < 0) { return false; } try { type = (ShaderPropertyType)(int)shader.GetPropertyType(num); } catch { return false; } return true; } private static bool IsScalarPropertyType(ShaderPropertyType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)type == 2 || (int)type == 3; } private static void AppendMaterialPropertySignature(Material src, string propName, StringBuilder sb) { //IL_0042: 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_0047: 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_0064: Expected I4, but got Unknown //IL_006c: 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_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) if ((Object)(object)src == (Object)null || string.IsNullOrEmpty(propName) || !TryGetDeclaredPropertyType(src, propName, out var type)) { return; } try { sb.Append(propName).Append('='); ShaderPropertyType val = type; ShaderPropertyType val2 = val; switch ((int)val2) { case 0: sb.Append(src.GetColor(propName)); break; case 1: sb.Append(src.GetVector(propName)); break; case 4: { Texture texture = src.GetTexture(propName); sb.Append(((Object)(object)texture != (Object)null) ? ((Object)texture).GetInstanceID().ToString() : "null"); sb.Append('@').Append(src.GetTextureScale(propName)); sb.Append('/').Append(src.GetTextureOffset(propName)); break; } default: sb.Append(src.GetFloat(propName).ToString("R", CultureInfo.InvariantCulture)); break; } sb.Append(';'); } catch { } } internal static bool ApplyRaceShadingToRendererMaterials(SkinnedMeshRenderer smr, Material raceBodyMaterial, string debugGroupName, string debugPresetId) { if ((Object)(object)smr == (Object)null || (Object)(object)raceBodyMaterial == (Object)null) { return false; } Material[] sharedMaterials = ((Renderer)smr).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int i = 0; i < sharedMaterials.Length; i++) { array[i] = BuildRaceShadedMaterial(sharedMaterials[i], raceBodyMaterial); if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin] group=" + debugGroupName + " preset=" + debugPresetId + " renderer=" + ((Object)smr).name + " slot=" + i + " original=" + (((Object)(object)sharedMaterials[i] != (Object)null) ? ((Object)sharedMaterials[i]).name : "") + " appliedShader=" + (((Object)(object)array[i] != (Object)null && (Object)(object)array[i].shader != (Object)null) ? ((Object)array[i].shader).name : "") + " appliedTex=" + (((Object)(object)array[i] != (Object)null && (Object)(object)array[i].mainTexture != (Object)null) ? ((Object)array[i].mainTexture).name : "") + " frame=" + Time.frameCount); } } ((Renderer)smr).sharedMaterials = array; return true; } internal static bool ApplyTextureAssetIfTextureMissing(Material dst, Texture fallbackTexture, string debugSource) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)dst == (Object)null || (Object)(object)fallbackTexture == (Object)null) { return false; } if (!IsMissingOrFallbackTexture(dst)) { return false; } for (int i = 0; i < DestinationMainTextureProperties.Length; i++) { string text = DestinationMainTextureProperties[i]; try { if (dst.HasProperty(text)) { dst.SetTexture(text, fallbackTexture); dst.SetTextureScale(text, Vector2.one); dst.SetTextureOffset(text, Vector2.zero); } } catch { } } try { dst.mainTexture = fallbackTexture; dst.mainTextureScale = Vector2.one; dst.mainTextureOffset = Vector2.zero; } catch { } try { if (dst.HasProperty("_ColorTint") && ApproximatelyBlack(dst.GetColor("_ColorTint"))) { dst.SetColor("_ColorTint", Color.white); } } catch { } if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][TextureAssetFallback] dst=" + ((Object)dst).name + " texture=" + ((Object)fallbackTexture).name + " source=" + (debugSource ?? "") + " frame=" + Time.frameCount); } return true; } internal static bool ApplyBodyAtlasVisuals(Material dst, Material raceBodyMaterial, string debugSource, bool copyColorAdjustments) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_009f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)dst == (Object)null || (Object)(object)raceBodyMaterial == (Object)null) { return false; } bool flag = false; if (TryGetBestVisualTexture(raceBodyMaterial, out var texture, out var scale, out var offset, out var propertyName) && (Object)(object)texture != (Object)null) { for (int i = 0; i < DestinationMainTextureProperties.Length; i++) { string text = DestinationMainTextureProperties[i]; try { if (dst.HasProperty(text)) { Texture texture2 = dst.GetTexture(text); if ((Object)(object)texture2 != (Object)(object)texture) { dst.SetTexture(text, texture); flag = true; } dst.SetTextureScale(text, scale); dst.SetTextureOffset(text, offset); } } catch { } } try { if ((Object)(object)dst.mainTexture != (Object)(object)texture) { dst.mainTexture = texture; flag = true; } dst.mainTextureScale = scale; dst.mainTextureOffset = offset; } catch { } } if (copyColorAdjustments) { CopyCharacterColorAdjustmentPropertiesForced(raceBodyMaterial, dst); CopyBodyTintLikeProperties(raceBodyMaterial, dst); } else { NeutralizeCharacterColorAdjustmentProperties(dst); } flag = true; if (((Object)dst).name != null && ((Object)dst).name.IndexOf("_BodyAtlas", StringComparison.OrdinalIgnoreCase) < 0) { ((Object)dst).name = ((Object)dst).name.Replace("_ShlongColorRuntime", "") + "_BodyAtlas"; } if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][BodyAtlasVisuals] dst=" + ((Object)dst).name + " tex=" + (((Object)(object)texture != (Object)null) ? ((Object)texture).name : "") + " prop=" + (propertyName ?? "") + " source=" + (debugSource ?? "") + " hbc=" + (copyColorAdjustments ? "body" : "neutral") + " frame=" + Time.frameCount); } return flag; } internal unsafe static bool ApplyFallbackVisualsIfTextureMissing(Material dst, Material fallbackSrc) { //IL_003f: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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) if ((Object)(object)dst == (Object)null || (Object)(object)fallbackSrc == (Object)null) { return false; } if (!IsMissingOrFallbackTexture(dst)) { return false; } bool flag = HasUsableVisualTexture(fallbackSrc); Color bestSourceVisualColor = GetBestSourceVisualColor(fallbackSrc); if (!flag && ApproximatelyWhite(bestSourceVisualColor)) { return false; } bool flag2 = false; if (flag) { flag2 |= CopyBestSourceTextureToMainSlots(fallbackSrc, dst); } ApplySourceVisualColorToDestination(fallbackSrc, dst); flag2 = true; if (Plugin.IsDebug) { Texture texture = null; TryFindBestSourceTexture(dst, out texture, out var _, out var _, out var propertyName); string[] obj = new string[14] { "[MaterialSkin][FallbackVisuals] dst=", ((Object)dst).name, " fallback=", ((Object)fallbackSrc).name, " fallbackHasTexture=", flag.ToString(), " finalTex=", ((Object)(object)texture != (Object)null) ? ((Object)texture).name : "", " finalProp=", propertyName ?? "", " fallbackColor=", null, null, null }; Color val = bestSourceVisualColor; obj[11] = ((object)(*(Color*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[12] = " frame="; obj[13] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } return flag2; } internal static bool IsMissingOrFallbackTexture(Material mat) { if ((Object)(object)mat == (Object)null) { return true; } if (!TryFindBestSourceTexture(mat, out var texture, out var _, out var _, out var _) || (Object)(object)texture == (Object)null) { return true; } return IsFallbackWhiteTexture(texture); } internal static bool IsFallbackWhiteTexture(Texture tex) { if ((Object)(object)tex == (Object)null) { return true; } string text = ((Object)tex).name ?? string.Empty; if (text.IndexOf("UnityWhite", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (text.Equals("white", StringComparison.OrdinalIgnoreCase) || text.Equals("White", StringComparison.OrdinalIgnoreCase)) { return true; } Texture2D val = (Texture2D)(object)((tex is Texture2D) ? tex : null); if ((Object)(object)val != (Object)null && ((Texture)val).width <= 4 && ((Texture)val).height <= 4 && text.IndexOf("white", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return false; } internal static Material PickFallbackMaterialForSlot(Material current, Material[] fallbackMats, int slot) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) if (fallbackMats == null || fallbackMats.Length == 0) { return null; } if (slot >= 0 && slot < fallbackMats.Length && (Object)(object)fallbackMats[slot] != (Object)null && (HasUsableVisualTexture(fallbackMats[slot]) || !ApproximatelyWhite(GetBestSourceVisualColor(fallbackMats[slot])))) { return fallbackMats[slot]; } bool flag = IsBallsSheathMaterial(current); foreach (Material val in fallbackMats) { if (!((Object)(object)val == (Object)null) && IsBallsSheathMaterial(val) == flag && (HasUsableVisualTexture(val) || !ApproximatelyWhite(GetBestSourceVisualColor(val)))) { return val; } } foreach (Material val2 in fallbackMats) { if (!((Object)(object)val2 == (Object)null) && (HasUsableVisualTexture(val2) || !ApproximatelyWhite(GetBestSourceVisualColor(val2)))) { return val2; } } for (int k = 0; k < fallbackMats.Length; k++) { if ((Object)(object)fallbackMats[k] != (Object)null) { return fallbackMats[k]; } } return null; } internal static Material[] FindBestPrefabRendererMaterials(GameObject prefab, string meshName) { //IL_01c1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { return null; } SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return null; } SkinnedMeshRenderer val = null; int num = int.MinValue; foreach (SkinnedMeshRenderer val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null) { continue; } int num2 = 0; string text = ((Object)val2).name ?? string.Empty; string text2 = (((Object)(object)val2.sharedMesh != (Object)null) ? (((Object)val2.sharedMesh).name ?? string.Empty) : string.Empty); if (!string.IsNullOrEmpty(meshName)) { if (string.Equals(text, meshName, StringComparison.OrdinalIgnoreCase)) { num2 += 1000; } if (string.Equals(text2, meshName, StringComparison.OrdinalIgnoreCase)) { num2 += 1000; } if (text.IndexOf(meshName, StringComparison.OrdinalIgnoreCase) >= 0) { num2 += 300; } if (text2.IndexOf(meshName, StringComparison.OrdinalIgnoreCase) >= 0) { num2 += 300; } } string text3 = text.ToLowerInvariant(); if (text3.IndexOf("dick", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("penis", StringComparison.OrdinalIgnoreCase) >= 0 || text3.IndexOf("peen", StringComparison.OrdinalIgnoreCase) >= 0) { num2 += 100; } Material[] sharedMaterials = ((Renderer)val2).sharedMaterials; if (sharedMaterials != null) { num2 += sharedMaterials.Length; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null)) { if (HasUsableVisualTexture(sharedMaterials[j])) { num2 += 25; } if (!ApproximatelyWhite(GetBestSourceVisualColor(sharedMaterials[j]))) { num2 += 10; } } } } if (num2 > num) { num = num2; val = val2; } } if ((Object)(object)val == (Object)null || ((Renderer)val).sharedMaterials == null) { return null; } return (Material[])((Renderer)val).sharedMaterials.Clone(); } internal static void CopyMainTextureLikeProperties(Material src, Material dst) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null) { return; } CopyTextureProperty(src, dst, "_MainTex"); CopyTextureProperty(src, dst, "_BaseMap"); CopyTextureProperty(src, dst, "_BaseColorMap"); CopyTextureProperty(src, dst, "_Albedo"); CopyTextureProperty(src, dst, "_AlbedoTex"); CopyTextureProperty(src, dst, "_Diffuse"); CopyTextureProperty(src, dst, "_DiffuseTex"); try { if ((Object)(object)src.mainTexture != (Object)null) { dst.mainTexture = src.mainTexture; } dst.mainTextureScale = src.mainTextureScale; dst.mainTextureOffset = src.mainTextureOffset; } catch { } } internal static void CopyTextureProperty(Material src, Material dst, string prop) { //IL_0056: 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) if (!((Object)(object)src == (Object)null) && !((Object)(object)dst == (Object)null) && src.HasProperty(prop) && dst.HasProperty(prop)) { Texture texture = src.GetTexture(prop); if ((Object)(object)texture != (Object)null) { dst.SetTexture(prop, texture); } dst.SetTextureScale(prop, src.GetTextureScale(prop)); dst.SetTextureOffset(prop, src.GetTextureOffset(prop)); } } internal static void CopyMainColorLikeProperties(Material src, Material dst) { CopyColorProperty(src, dst, "_Color"); CopyColorProperty(src, dst, "_BaseColor"); } internal static void CopyBodyTintLikeProperties(Material src, Material dst) { if (!((Object)(object)src == (Object)null) && !((Object)(object)dst == (Object)null)) { for (int i = 0; i < CommonBodyTintProperties.Length; i++) { CopyColorProperty(src, dst, CommonBodyTintProperties[i]); } } } internal static void NeutralizeBodyTintLikeProperties(Material mat) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mat == (Object)null) { return; } for (int i = 0; i < CommonBodyTintProperties.Length; i++) { string text = CommonBodyTintProperties[i]; if (mat.HasProperty(text)) { mat.SetColor(text, Color.white); } } } private static void AppendBodyTintSignature(Material src, StringBuilder sb) { if (!((Object)(object)src == (Object)null) && sb != null) { for (int i = 0; i < CommonBodyTintProperties.Length; i++) { AppendMaterialPropertySignature(src, CommonBodyTintProperties[i], sb); } } } internal static void CopyColorProperty(Material src, Material dst, string prop) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)src == (Object)null) && !((Object)(object)dst == (Object)null) && src.HasProperty(prop) && dst.HasProperty(prop)) { dst.SetColor(prop, src.GetColor(prop)); } } } public struct SpawnResult { public bool Success; public GameObject InstanceRoot; public Transform AttachBone; public GameObject SizeBone; public GameObject BallBone; public Transform PelvisBone; public SkinnedMeshRenderer DickMesh; public SkinnedMeshRenderer[] BallMeshes; public DynamicBone[] ShaftDynamicBones; public bool ArousalControlsShaftJiggle; public Vector2 InitialOffset; public Vector3 InitialRotation; public Material[] TemplateDickMaterials; public Dictionary TemplateMaterialsByRenderer; public Vector3 ClipPresetRotation; } public static class ModelAttacher { private static readonly HashSet s_warnedMissingPreset = new HashSet(); private static readonly HashSet s_warnedMissingPresetCosmetic = new HashSet(); internal static bool ClipEnabled = true; internal static int ClipAxis = -1; internal static bool ClipFlipDirection = false; internal static float ClipMarginRatio = 0.1f; internal static Vector3 ClipDirOverride = Vector3.zero; internal static Vector3 LastClipDir; internal static float LastClipMaxProj; internal static readonly HashSet ActiveDickMeshObjects = new HashSet(); public static void ResetMissingPresetWarnings() { s_warnedMissingPreset.Clear(); s_warnedMissingPresetCosmetic.Clear(); } private static Material[] CloneMaterialArray(Material[] source) { return (source != null) ? ((Material[])source.Clone()) : null; } private static int ApplySoloStyleDynamicBones(GameObject instance, PresetData preset, ref SpawnResult result, string context) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)instance == (Object)null || preset == null || preset.DynamicBones == null) { return 0; } int num = 0; int num2 = 0; bool flag = false; List list = new List(); string[] dynamicBones = preset.DynamicBones; foreach (string text in dynamicBones) { if (string.IsNullOrEmpty(text)) { continue; } Transform val = instance.transform.RecursiveFindChild(text); if (!((Object)(object)val == (Object)null)) { num2++; DynamicBone val2 = ((Component)val).GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).gameObject.AddComponent(); num++; } bool flag2 = text.Contains("Balls"); val2.m_Root = val; val2.m_Elasticity = 0.1f; val2.m_Gravity = Vector3.zero; val2.m_Force = Vector3.zero; val2.m_Radius = 0f; val2.m_UpdateRate = 60f; val2.m_UpdateMode = (UpdateMode)0; val2.m_FreezeAxis = (FreezeAxis)0; if (flag2) { flag = true; result.BallBone = ((Component)val).gameObject; val2.m_Stiffness = 0.4f; val2.m_Damping = 0.2f; val2.m_Inert = 0.15f; } else { val2.m_Stiffness = 0.85f; val2.m_Damping = 0.33f; val2.m_Inert = 0.37f; list.Add(val2); } } } result.ShaftDynamicBones = ((list.Count > 0) ? list.ToArray() : null); result.ArousalControlsShaftJiggle = preset.AssetSource == PresetAssetSource.Test; if (Plugin.IsDebug) { Plugin.LogDebug("[NativeDynamicBone][" + context + "] preset=" + preset.Id + " found=" + num2 + " added=" + num + " foundBalls=" + flag); } return num; } internal static void PurgeDestroyedEntries() { int count = ActiveDickMeshObjects.Count; ActiveDickMeshObjects.RemoveWhere((GameObject go) => (Object)(object)go == (Object)null); int num = count - ActiveDickMeshObjects.Count; if (num > 0 && Plugin.IsDebug) { Plugin.LogDebug("[Fix67g] PurgeDestroyedEntries: removed " + num + " zombies"); } } public static SpawnResult Spawn(int presetIndex, int raceIndex, Transform ownerTransform, PresetRegistry presets, ManualLogSource log) { //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_0391: 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_0491: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) SpawnResult result = default(SpawnResult); if (presets != null) { presetIndex = presets.ResolvePresetForLocalAssets(presetIndex); } PresetData preset = presets.GetPreset(presetIndex); RaceData race = presets.GetRace(raceIndex); if (preset == null || (Object)(object)preset.LoadedPrefab == (Object)null) { if (s_warnedMissingPreset.Add(presetIndex)) { string text = ((preset != null) ? preset.Id : ""); Plugin.LogWarningLimited("spawn.preset_missing." + presetIndex, "Spawn: preset " + presetIndex + " (" + text + ") is null or prefab missing — further warnings suppressed for this preset"); } return result; } if (race == null) { Plugin.LogWarningLimited("spawn.race_null." + raceIndex, "Spawn: race " + raceIndex + " is null"); return result; } GameObject val = Object.Instantiate(preset.LoadedPrefab); ((Object)val).name = preset.PrefabName; result.InstanceRoot = val; List list = new List(); string[] dynamicBones = preset.DynamicBones; foreach (string text2 in dynamicBones) { Transform val2 = val.transform.RecursiveFindChild(text2); if ((Object)(object)val2 != (Object)null) { DynamicBone val3 = ((Component)val2).gameObject.AddComponent(); val3.m_Root = val2; val3.m_Stiffness = 0.85f; val3.m_Damping = 0.33f; val3.m_Inert = 0.37f; if (text2.Contains("Balls")) { result.BallBone = ((Component)val2).gameObject; val3.m_Stiffness = 0.4f; val3.m_Damping = 0.2f; val3.m_Inert = 0.15f; } else { list.Add(val3); } } } result.ShaftDynamicBones = ((list.Count > 0) ? list.ToArray() : null); result.ArousalControlsShaftJiggle = preset.AssetSource == PresetAssetSource.Test; val.transform.parent = null; val.transform.position = ownerTransform.position; Transform val4 = val.transform.RecursiveFindChild(preset.ArmatureBone); if ((Object)(object)val4 == (Object)null) { Plugin.LogWarningLimited("spawn.armature_missing." + presetIndex, "Armature bone not found: " + preset.ArmatureBone); Object.Destroy((Object)(object)val); return result; } Transform val5 = ownerTransform.RecursiveFindChild(race.AttachBone); if ((Object)(object)val5 == (Object)null) { Plugin.LogWarningLimited("spawn.attach_bone_missing." + raceIndex, "Attach bone not found: " + race.AttachBone); Object.Destroy((Object)(object)val); return result; } result.AttachBone = val5; val.transform.SetPositionAndRotation(val5.position, val5.rotation); val.transform.localScale = val5.lossyScale; val4.SetParent(val5, false); val4.localScale = preset.Scale; val4.localPosition = preset.Position; result.PelvisBone = val4; result.SizeBone = ((Component)val4).gameObject; result.InitialOffset = new Vector2(preset.Position.z, preset.Position.y); result.InitialRotation = preset.Rotation; Transform val6 = ownerTransform.RecursiveFindChild(race.BodyMesh); Transform val7 = val.transform.RecursiveFindChild(preset.MeshName); if ((Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null) { Plugin.LogWarningLimited("spawn.mesh_missing." + presetIndex + "." + raceIndex, "Mesh not found: body=" + race.BodyMesh + " dick=" + preset.MeshName); result.SizeBone = null; return result; } ((Object)val7).name = "DickMesh"; SkinnedMeshRenderer component = ((Component)val7).GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.LogWarningLimited("spawn.smr_missing." + presetIndex, "SkinnedMeshRenderer not found on " + ((Object)val7).name); result.SizeBone = null; return result; } component.updateWhenOffscreen = true; result.ClipPresetRotation = preset.Rotation; result.DickMesh = component; ActiveDickMeshObjects.Add(((Component)component).gameObject); result.TemplateDickMaterials = CloneMaterialArray(((Renderer)component).sharedMaterials); bool flag = preset.AssetSource == PresetAssetSource.Test; SkinnedMeshRenderer component2 = ((Component)val6).GetComponent(); Material raceBodyMaterial = GetRaceBodyMaterial(component2, race); if (!flag && (Object)(object)raceBodyMaterial != (Object)null) { ((Renderer)component).sharedMaterial = raceBodyMaterial; } SkinnedMeshRenderer[] componentsInChildren = val.GetComponentsInChildren(true); List list2 = new List(); SkinnedMeshRenderer[] array = componentsInChildren; foreach (SkinnedMeshRenderer val8 in array) { if (!((Object)(object)val8 == (Object)(object)component)) { val8.updateWhenOffscreen = true; if (result.TemplateMaterialsByRenderer == null) { result.TemplateMaterialsByRenderer = new Dictionary(); } result.TemplateMaterialsByRenderer[val8] = CloneMaterialArray(((Renderer)val8).sharedMaterials); if (!flag && (Object)(object)raceBodyMaterial != (Object)null) { ((Renderer)val8).sharedMaterial = raceBodyMaterial; } list2.Add(val8); } } result.BallMeshes = ((list2.Count > 0) ? list2.ToArray() : null); if (flag) { Material raceBodyMaterial2 = GetRaceBodyMaterial(component2, race); if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin] preset=" + preset.Id + " race=" + race.BodyMesh + " sourceSlot=" + race.MaterialSlot + " sourceMat=" + (((Object)(object)raceBodyMaterial2 != (Object)null) ? ((Object)raceBodyMaterial2).name : "") + " sourceShader=" + (((Object)(object)raceBodyMaterial2 != (Object)null && (Object)(object)raceBodyMaterial2.shader != (Object)null) ? ((Object)raceBodyMaterial2.shader).name : "")); } ApplyRaceShadingToRendererMaterials(component, raceBodyMaterial2, "Dick", preset.Id); if (result.BallMeshes != null) { for (int k = 0; k < result.BallMeshes.Length; k++) { ApplyRaceShadingToRendererMaterials(result.BallMeshes[k], raceBodyMaterial2, "Ball", preset.Id); } } } result.Success = true; return result; } public static void Destroy(GameObject instanceRoot, SkinnedMeshRenderer dickMesh, Transform pelvisBone) { if (Plugin.IsDebug) { Plugin.LogDebug("[ModelAttacher.Destroy] dickMesh=" + ((Object)(object)dickMesh != (Object)null) + " pelvisBone=" + ((Object)(object)pelvisBone != (Object)null) + " instanceRoot=" + ((Object)(object)instanceRoot != (Object)null)); } if ((Object)(object)dickMesh != (Object)null && (Object)(object)((Component)dickMesh).gameObject != (Object)null) { ActiveDickMeshObjects.Remove(((Component)dickMesh).gameObject); } bool flag = (Object)(object)pelvisBone != (Object)null && (Object)(object)instanceRoot != (Object)null && pelvisBone.IsChildOf(instanceRoot.transform); if ((Object)(object)pelvisBone != (Object)null && !flag) { if (Plugin.IsDebug) { Plugin.LogDebug("[ModelAttacher.Destroy] Destroying PelvisBone: " + ((Object)pelvisBone).name + " parent=" + (((Object)(object)pelvisBone.parent != (Object)null) ? ((Object)pelvisBone.parent).name : "NULL")); } pelvisBone.SetParent((Transform)null, false); Object.Destroy((Object)(object)((Component)pelvisBone).gameObject); } if ((Object)(object)instanceRoot != (Object)null) { Object.Destroy((Object)(object)instanceRoot); } } public static SpawnResult SpawnCosmeticLocal(int presetIndex, int raceIndex, Transform ownerTransform, PresetRegistry presets, ManualLogSource log, int diagnosticStage = 0) { //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026e: 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_028f: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0568: Unknown result type (might be due to invalid IL or missing references) //IL_056d: Unknown result type (might be due to invalid IL or missing references) //IL_07f0: Unknown result type (might be due to invalid IL or missing references) //IL_07f5: Unknown result type (might be due to invalid IL or missing references) SpawnResult result = default(SpawnResult); if (presets != null) { presetIndex = presets.ResolvePresetForLocalAssets(presetIndex); } PresetData preset = presets.GetPreset(presetIndex); RaceData race = presets.GetRace(raceIndex); if (preset == null || (Object)(object)preset.LoadedPrefab == (Object)null) { if (s_warnedMissingPresetCosmetic.Add(presetIndex)) { string text = ((preset != null) ? preset.Id : ""); Plugin.LogWarningLimited("cosmetic.preset_missing." + presetIndex, "[CosmeticLocal] preset " + presetIndex + " (" + text + ") is null or prefab missing — further warnings suppressed for this preset"); } return result; } if (race == null) { Plugin.LogWarningLimited("cosmetic.race_null." + raceIndex, "[CosmeticLocal] race " + raceIndex + " is null"); return result; } result.ArousalControlsShaftJiggle = preset.AssetSource == PresetAssetSource.Test; GameObject val = Object.Instantiate(preset.LoadedPrefab); ((Object)val).name = preset.PrefabName + "_cosmetic"; result.InstanceRoot = val; val.transform.parent = null; val.transform.position = ownerTransform.position; Scene scene; if (diagnosticStage == 1) { if (Plugin.IsDebug) { string text2 = presetIndex.ToString(); scene = val.scene; Plugin.LogDebug("[CosmeticLocal] InstantiateOnly: preset=" + text2 + " scene=" + ((Scene)(ref scene)).name); } result.Success = true; return result; } Transform val2 = val.transform.RecursiveFindChild(preset.ArmatureBone); if ((Object)(object)val2 == (Object)null) { Plugin.LogWarningLimited("cosmetic.armature_missing." + presetIndex, "[CosmeticLocal] Armature bone not found: " + preset.ArmatureBone); Object.Destroy((Object)(object)val); return result; } Transform val3 = ownerTransform.RecursiveFindChild(race.AttachBone); if ((Object)(object)val3 == (Object)null) { Plugin.LogWarningLimited("cosmetic.attach_bone_missing." + raceIndex, "[CosmeticLocal] Attach bone not found: " + race.AttachBone); Object.Destroy((Object)(object)val); return result; } result.AttachBone = val3; val.transform.SetPositionAndRotation(val3.position, val3.rotation); val.transform.localScale = val3.lossyScale; val2.localScale = preset.Scale; val2.localPosition = preset.Position; result.PelvisBone = val2; result.SizeBone = ((Component)val2).gameObject; result.InitialOffset = new Vector2(preset.Position.z, preset.Position.y); result.InitialRotation = preset.Rotation; switch (diagnosticStage) { case 2: if (Plugin.IsDebug) { string[] obj2 = new string[6] { "[CosmeticLocal] WithBones: preset=", presetIndex.ToString(), " scene=", null, null, null }; scene = val.scene; obj2[3] = ((Scene)(ref scene)).name; obj2[4] = " hipBone="; obj2[5] = ((Object)val3).name; Plugin.LogDebug(string.Concat(obj2)); } result.Success = true; return result; case 3: { Transform val7 = val.transform.RecursiveFindChild(preset.MeshName); if ((Object)(object)val7 != (Object)null) { ((Object)val7).name = "DickMesh"; SkinnedMeshRenderer component3 = ((Component)val7).GetComponent(); if ((Object)(object)component3 != (Object)null) { component3.updateWhenOffscreen = true; result.DickMesh = component3; } } if (Plugin.IsDebug) { string[] obj3 = new string[8] { "[CosmeticLocal] WithDickMesh: preset=", presetIndex.ToString(), " scene=", null, null, null, null, null }; scene = val.scene; obj3[3] = ((Scene)(ref scene)).name; obj3[4] = " hipBone="; obj3[5] = ((Object)val3).name; obj3[6] = " dickMesh="; obj3[7] = ((Object)(object)result.DickMesh != (Object)null).ToString(); Plugin.LogDebug(string.Concat(obj3)); } result.Success = true; return result; } default: { if (PluginConfig.UseNativeRemoteDynamicBone) { ApplySoloStyleDynamicBones(val, preset, ref result, "CosmeticLocal"); } Transform val4 = ownerTransform.RecursiveFindChild(race.BodyMesh); Transform val5 = val.transform.RecursiveFindChild(preset.MeshName); if ((Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null) { Plugin.LogWarningLimited("cosmetic.mesh_missing." + presetIndex + "." + raceIndex, "[CosmeticLocal] Mesh not found: body=" + race.BodyMesh + " dick=" + preset.MeshName); result.SizeBone = null; return result; } ((Object)val5).name = "DickMesh"; SkinnedMeshRenderer component = ((Component)val5).GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.LogWarningLimited("cosmetic.smr_missing." + presetIndex, "[CosmeticLocal] SkinnedMeshRenderer not found on " + ((Object)val5).name); result.SizeBone = null; return result; } component.updateWhenOffscreen = true; result.ClipPresetRotation = preset.Rotation; result.DickMesh = component; result.TemplateDickMaterials = CloneMaterialArray(((Renderer)component).sharedMaterials); bool flag = preset.AssetSource == PresetAssetSource.Test; SkinnedMeshRenderer component2 = ((Component)val4).GetComponent(); Material raceBodyMaterial = GetRaceBodyMaterial(component2, race); if (!flag && (Object)(object)raceBodyMaterial != (Object)null) { ((Renderer)component).sharedMaterial = raceBodyMaterial; } SkinnedMeshRenderer[] componentsInChildren = val.GetComponentsInChildren(true); List list = new List(); SkinnedMeshRenderer[] array = componentsInChildren; foreach (SkinnedMeshRenderer val6 in array) { if (!((Object)(object)val6 == (Object)(object)component)) { val6.updateWhenOffscreen = true; if (result.TemplateMaterialsByRenderer == null) { result.TemplateMaterialsByRenderer = new Dictionary(); } result.TemplateMaterialsByRenderer[val6] = CloneMaterialArray(((Renderer)val6).sharedMaterials); if (!flag && (Object)(object)raceBodyMaterial != (Object)null) { ((Renderer)val6).sharedMaterial = raceBodyMaterial; } list.Add(val6); } } result.BallMeshes = ((list.Count > 0) ? list.ToArray() : null); if (flag) { Material raceBodyMaterial2 = GetRaceBodyMaterial(component2, race); if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][Cosmetic] preset=" + preset.Id + " race=" + race.BodyMesh + " sourceSlot=" + race.MaterialSlot + " sourceMat=" + (((Object)(object)raceBodyMaterial2 != (Object)null) ? ((Object)raceBodyMaterial2).name : "") + " sourceShader=" + (((Object)(object)raceBodyMaterial2 != (Object)null && (Object)(object)raceBodyMaterial2.shader != (Object)null) ? ((Object)raceBodyMaterial2.shader).name : "")); } ApplyRaceShadingToRendererMaterials(component, raceBodyMaterial2, "Dick", preset.Id); if (result.BallMeshes != null) { for (int j = 0; j < result.BallMeshes.Length; j++) { ApplyRaceShadingToRendererMaterials(result.BallMeshes[j], raceBodyMaterial2, "Ball", preset.Id); } } } if (Plugin.IsDebug) { string[] obj = new string[6] { "[CosmeticLocal] Spawned: preset=", presetIndex.ToString(), " scene=", null, null, null }; scene = val.scene; obj[3] = ((Scene)(ref scene)).name; obj[4] = " hipBone="; obj[5] = ((Object)val3).name; Plugin.LogDebug(string.Concat(obj)); } result.Success = true; return result; } } } internal static void ClipMeshBehindOrigin(SkinnedMeshRenderer smr, Vector3 presetRotation) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!ClipEnabled || (Object)(object)smr == (Object)null || (Object)(object)smr.sharedMesh == (Object)null) { return; } Mesh sharedMesh = smr.sharedMesh; if (sharedMesh.vertexCount != 0) { if (sharedMesh.isReadable) { ClipReadableMesh(smr, sharedMesh, presetRotation); } else { CopyAndClipViaGpuBuffers(smr, sharedMesh, presetRotation); } } } private static bool ComputeClipParams(Bounds bounds, Vector3 presetRotation, out Vector3 clipDir, out float clipThreshold) { //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_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_0127: 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) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) clipDir = Vector3.up; clipThreshold = 0f; Vector3 val; if (((Vector3)(ref ClipDirOverride)).sqrMagnitude > 0.0001f) { clipDir = ((Vector3)(ref ClipDirOverride)).normalized; } else if (ClipAxis >= 0 && ClipAxis <= 2) { clipDir = Vector3.zero; int clipAxis = ClipAxis; val = ((Bounds)(ref bounds)).center; ((Vector3)(ref clipDir))[clipAxis] = ((((Vector3)(ref val))[ClipAxis] >= 0f) ? 1f : (-1f)); } else { Vector3 val2 = -((Bounds)(ref bounds)).center; if (((Vector3)(ref val2)).sqrMagnitude < 1E-07f) { Quaternion val3 = Quaternion.Euler(presetRotation); val = val3 * new Vector3(0f, 0f, -1f); clipDir = ((Vector3)(ref val)).normalized; } else { clipDir = ((Vector3)(ref val2)).normalized; } } if (ClipFlipDirection) { clipDir = -clipDir; } float num = Vector3.Dot(((Bounds)(ref bounds)).center, clipDir); Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(Mathf.Abs(clipDir.x), Mathf.Abs(clipDir.y), Mathf.Abs(clipDir.z)); float num2 = Vector3.Dot(((Bounds)(ref bounds)).extents, val4); float num3 = num + num2; if (num3 < 1E-05f) { return false; } clipThreshold = num3 * (1f - ClipMarginRatio); LastClipDir = clipDir; LastClipMaxProj = num3; if (Plugin.IsDebug) { string[] obj = new string[12] { "[ClipMesh] Params: clipDir=", ((Vector3)(ref clipDir)).ToString("F4"), " maxProj=", num3.ToString("F6"), " threshold=", clipThreshold.ToString("F6"), " margin=", ClipMarginRatio.ToString("F2"), " center=", null, null, null }; val = ((Bounds)(ref bounds)).center; obj[9] = ((Vector3)(ref val)).ToString("F4"); obj[10] = " extents="; val = ((Bounds)(ref bounds)).extents; obj[11] = ((Vector3)(ref val)).ToString("F4"); Plugin.LogDebug(string.Concat(obj)); } return true; } private static void ClipReadableMesh(SkinnedMeshRenderer smr, Mesh original, Vector3 presetRotation) { //IL_003f: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) Mesh val = Object.Instantiate(original); ((Object)val).name = ((Object)original).name + "_clipped"; Vector3[] vertices = val.vertices; if (vertices.Length == 0) { Object.Destroy((Object)(object)val); return; } if (!ComputeClipParams(val.bounds, presetRotation, out var clipDir, out var clipThreshold)) { Object.Destroy((Object)(object)val); return; } int num = 0; for (int i = 0; i < vertices.Length; i++) { Vector3 val2 = vertices[i]; float num2 = Vector3.Dot(val2, clipDir); if (num2 > clipThreshold) { float num3 = num2 - clipThreshold; vertices[i] = val2 - num3 * clipDir; num++; } } if (num > 0) { val.vertices = vertices; val.RecalculateBounds(); } smr.sharedMesh = val; if (Plugin.IsDebug) { Bounds bounds = val.bounds; Plugin.LogDebug("[ClipMesh] Readable: " + ((Object)original).name + " dir=" + ((Vector3)(ref clipDir)).ToString("F4") + " clipped=" + num + "/" + vertices.Length + " threshold=" + clipThreshold.ToString("F6") + " bounds=[X:" + ((Bounds)(ref bounds)).min.x.ToString("F4") + "~" + ((Bounds)(ref bounds)).max.x.ToString("F4") + " Y:" + ((Bounds)(ref bounds)).min.y.ToString("F4") + "~" + ((Bounds)(ref bounds)).max.y.ToString("F4") + " Z:" + ((Bounds)(ref bounds)).min.z.ToString("F4") + "~" + ((Bounds)(ref bounds)).max.z.ToString("F4") + "] blendShapes=" + val.blendShapeCount); } } private static void CopyAndClipViaGpuBuffers(SkinnedMeshRenderer smr, Mesh original, Vector3 presetRotation) { //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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: 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_0507: Unknown result type (might be due to invalid IL or missing references) //IL_050c: Unknown result type (might be due to invalid IL or missing references) //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0555: Unknown result type (might be due to invalid IL or missing references) //IL_055a: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) try { int vertexCount = original.vertexCount; if (vertexCount == 0) { return; } Mesh val = Object.Instantiate(original); ((Object)val).name = ((Object)original).name + "_clipped"; if (!ComputeClipParams(val.bounds, presetRotation, out var clipDir, out var clipThreshold)) { Object.Destroy((Object)(object)val); return; } VertexAttributeDescriptor[] vertexAttributes = val.GetVertexAttributes(); if (!FindPositionAttribute(vertexAttributes, out var stream, out var byteOffset)) { if (Plugin.IsDebug) { Plugin.LogDebug("[ClipMesh] Position attribute not found: " + ((Object)original).name); } Object.Destroy((Object)(object)val); return; } GraphicsBuffer vertexBuffer = val.GetVertexBuffer(stream); if (vertexBuffer == null) { if (Plugin.IsDebug) { Plugin.LogDebug("[ClipMesh] Vertex buffer null on clone: " + ((Object)original).name); } Object.Destroy((Object)(object)val); return; } try { int stride = vertexBuffer.stride; byte[] array = new byte[vertexBuffer.count * stride]; vertexBuffer.GetData((Array)array); float x = clipDir.x; float y = clipDir.y; float z = clipDir.z; if (Plugin.IsDebug) { Plugin.LogDebug("[ClipMesh] GPU clone OK: " + ((Object)original).name + " verts=" + vertexCount + " stride=" + stride + " streams=" + val.vertexBufferCount + " blendShapes=" + val.blendShapeCount); } int num = 0; for (int i = 0; i < vertexCount; i++) { int num2 = i * stride + byteOffset; float num3 = BitConverter.ToSingle(array, num2); float num4 = BitConverter.ToSingle(array, num2 + 4); float num5 = BitConverter.ToSingle(array, num2 + 8); float num6 = num3 * x + num4 * y + num5 * z; if (num6 > clipThreshold) { float num7 = num6 - clipThreshold; byte[] bytes = BitConverter.GetBytes(num3 - num7 * x); byte[] bytes2 = BitConverter.GetBytes(num4 - num7 * y); byte[] bytes3 = BitConverter.GetBytes(num5 - num7 * z); Buffer.BlockCopy(bytes, 0, array, num2, 4); Buffer.BlockCopy(bytes2, 0, array, num2 + 4, 4); Buffer.BlockCopy(bytes3, 0, array, num2 + 8, 4); num++; } } vertexBuffer.SetData((Array)array); if (num > 0) { Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(float.MaxValue, float.MaxValue, float.MaxValue); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(float.MinValue, float.MinValue, float.MinValue); for (int j = 0; j < vertexCount; j++) { int num8 = j * stride + byteOffset; float num9 = BitConverter.ToSingle(array, num8); float num10 = BitConverter.ToSingle(array, num8 + 4); float num11 = BitConverter.ToSingle(array, num8 + 8); if (num9 < val2.x) { val2.x = num9; } if (num10 < val2.y) { val2.y = num10; } if (num11 < val2.z) { val2.z = num11; } if (num9 > val3.x) { val3.x = num9; } if (num10 > val3.y) { val3.y = num10; } if (num11 > val3.z) { val3.z = num11; } } val.bounds = new Bounds((val2 + val3) * 0.5f, val3 - val2); } smr.sharedMesh = val; if (Plugin.IsDebug) { Bounds bounds = val.bounds; Plugin.LogDebug("[ClipMesh] " + ((num > 0) ? "Clipped" : "No clip needed") + ": " + ((Object)original).name + " dir=" + ((Vector3)(ref clipDir)).ToString("F4") + " clipped=" + num + "/" + vertexCount + " threshold=" + clipThreshold.ToString("F6") + " bounds=[X:" + ((Bounds)(ref bounds)).min.x.ToString("F4") + "~" + ((Bounds)(ref bounds)).max.x.ToString("F4") + " Y:" + ((Bounds)(ref bounds)).min.y.ToString("F4") + "~" + ((Bounds)(ref bounds)).max.y.ToString("F4") + " Z:" + ((Bounds)(ref bounds)).min.z.ToString("F4") + "~" + ((Bounds)(ref bounds)).max.z.ToString("F4") + "] blendShapes=" + val.blendShapeCount); } } finally { vertexBuffer.Dispose(); } } catch (Exception ex) { if (Plugin.IsDebug) { Plugin.LogDebug("[ClipMesh] GPU clip error: " + ex); } } } private static bool FindPositionAttribute(VertexAttributeDescriptor[] attrs, out int stream, out int byteOffset) { //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) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 //IL_0090: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); stream = 0; byteOffset = 0; for (int i = 0; i < attrs.Length; i++) { VertexAttributeDescriptor val = attrs[i]; if (!dictionary.ContainsKey(((VertexAttributeDescriptor)(ref val)).stream)) { dictionary[((VertexAttributeDescriptor)(ref val)).stream] = 0; } if ((int)((VertexAttributeDescriptor)(ref val)).attribute == 0) { stream = ((VertexAttributeDescriptor)(ref val)).stream; byteOffset = dictionary[((VertexAttributeDescriptor)(ref val)).stream]; return true; } dictionary[((VertexAttributeDescriptor)(ref val)).stream] += ((VertexAttributeDescriptor)(ref val)).dimension * VertexFormatByteSize(((VertexAttributeDescriptor)(ref val)).format); } return false; } private static int VertexFormatByteSize(VertexAttributeFormat fmt) { //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_0003: 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_003b: Expected I4, but got Unknown return (int)fmt switch { 0 => 4, 1 => 2, 2 => 1, 3 => 1, 4 => 2, 5 => 2, 6 => 1, 7 => 1, 8 => 2, 9 => 2, 10 => 4, 11 => 4, _ => 4, }; } private static Material GetRaceBodyMaterial(SkinnedMeshRenderer bodySMR, RaceData race) { return MaterialSkinUtility.GetRaceBodyMaterial(bodySMR, race); } private static void ApplyRaceShadingToRendererMaterials(SkinnedMeshRenderer smr, Material raceBodyMaterial, string debugGroupName, string debugPresetId) { MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(smr, raceBodyMaterial, debugGroupName, debugPresetId); } } public class PresetRegistry { private const string TestIdSuffix = "_bulge_test"; private const string TestDisplaySuffix = " Bulge Test"; private readonly PresetData[] _presets; private readonly RaceData[] _races; public int PresetCount => _presets.Length; public int RaceCount => _races.Length; public PresetRegistry() { _presets = Defaults.Presets; _races = Defaults.Races; } public PresetData GetPreset(int index) { if (index < 0 || index >= _presets.Length) { return null; } return _presets[index]; } public PresetData[] GetAllPresets() { return _presets; } public RaceData GetRace(int index) { if (index < 0 || index >= _races.Length) { return null; } return _races[index]; } public RaceData[] GetAllRaces() { return _races; } public int DetectRace(string modelName) { return Defaults.DetectRace(modelName); } public int FindPresetIndexById(string id) { if (string.IsNullOrEmpty(id)) { return -1; } for (int i = 0; i < _presets.Length; i++) { if (_presets[i] != null && _presets[i].Id == id) { return i; } } return -1; } public bool IsTestPresetUsableLocally(int index) { PresetData preset = GetPreset(index); if (preset == null || preset.AssetSource != PresetAssetSource.Test) { return false; } if ((Object)(object)preset.LoadedPrefab == (Object)null) { return false; } return Plugin.Assets != null && Plugin.Assets.HasExactTestBundleFile; } public bool HasUsableTestPresets() { for (int i = 0; i < _presets.Length; i++) { if (IsTestPresetUsableLocally(i)) { return true; } } return false; } public int ResolvePresetForLocalAssets(int index) { PresetData preset = GetPreset(index); if (preset == null) { return index; } if (preset.AssetSource != PresetAssetSource.Test) { return index; } if (IsTestPresetUsableLocally(index)) { return index; } int num = FindOriginalCounterpartIndex(preset); if (num >= 0) { return num; } num = FindFirstMainPresetIndex(); return (num >= 0) ? num : index; } public int FindOriginalCounterpartIndex(PresetData testPreset) { if (testPreset == null) { return -1; } if (!string.IsNullOrEmpty(testPreset.Id) && testPreset.Id.EndsWith("_bulge_test", StringComparison.OrdinalIgnoreCase)) { string id = testPreset.Id.Substring(0, testPreset.Id.Length - "_bulge_test".Length); int num = FindPresetIndexById(id); if (num >= 0) { PresetData preset = GetPreset(num); if (preset != null && preset.AssetSource != PresetAssetSource.Test) { return num; } } } string friendlyName = testPreset.FriendlyName; string text = testPreset.DisplayName; if (!string.IsNullOrEmpty(text) && text.EndsWith(" Bulge Test", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - " Bulge Test".Length); } for (int i = 0; i < _presets.Length; i++) { PresetData presetData = _presets[i]; if (presetData != null && presetData.AssetSource != PresetAssetSource.Test) { if (!string.IsNullOrEmpty(friendlyName) && string.Equals(presetData.FriendlyName, friendlyName, StringComparison.OrdinalIgnoreCase)) { return i; } if (!string.IsNullOrEmpty(text) && string.Equals(presetData.DisplayName, text, StringComparison.OrdinalIgnoreCase)) { return i; } } } return -1; } private int FindFirstMainPresetIndex() { for (int i = 0; i < _presets.Length; i++) { PresetData presetData = _presets[i]; if (presetData != null && presetData.AssetSource != PresetAssetSource.Test && (Object)(object)presetData.LoadedPrefab != (Object)null) { return i; } } for (int j = 0; j < _presets.Length; j++) { PresetData presetData2 = _presets[j]; if (presetData2 != null && presetData2.AssetSource != PresetAssetSource.Test) { return j; } } return -1; } } public class ShlongController : MonoBehaviour { public const int TextureSourceCharacter = 0; public const int TextureSourceBlank = 1; public int CharacterSelectPreviewMode = 0; public float ArousalTarget; public float BallsSizeOffset; public Vector2 PositionOffset; public Vector3 BaseRotation; public float ErectAngleOffset; public bool FutaToggle; public bool ClothingOverride; public bool HideToggle; public Vector3 ScaleOffset; public Color ColorTint = Color.white; public int ColorMode; public bool MatchBody = true; public int TextureSourceMode = 0; public float ArousalLerpSpeed = 2f; public Color BallColorTint = Color.white; public int BallColorMode; public bool BallMatchBody = true; public int BallTextureSourceMode = 0; public float BulgeAmount; public float BulgePosition; public float BulgeWidth = 1f; public float BulgeSharpness = 1f; public float BulgeLerpSpeed = 2f; internal readonly BlendShapeDriver BlendShapes = new BlendShapeDriver(); internal static Func OnApplySolidColor; private static Texture2D _whiteTex; private Dictionary _presetMemory = new Dictionary(); internal SkinnedMeshRenderer DickMesh; internal SkinnedMeshRenderer[] BallMeshes; private DynamicBone[] _shaftDynamicBones; private bool _arousalControlsShaftJiggle; private bool _shaftJiggleStateKnown; private bool _shaftJiggleActive; internal GameObject InstanceRoot; internal GameObject SizeBone; internal GameObject BallBone; internal Transform PelvisBone; internal RaceModelEquipDisplay RaceModelEquipDisplay; internal bool SyncDirty; private float _lastSyncTime; private float _lastHeartbeatTime; internal bool WasKeyAdjusting; internal bool HasReceivedRemoteVisualState; private PlayerRaceModel _cachedPlayerRaceModel; private PlayerClimbing _cachedPlayerClimbing; private bool _cachedComponentsDone; private int _materialResyncCount; private bool _registeredInDict; private bool _deferRegistration; private bool _hasPlayerInParent; private Transform _cachedHipBone; private Material _cachedOriginalBodyMaterial; private Shader _lastRaceBodyShader; private Texture _lastRaceBodyTexture; private string _lastRaceBodyAdjustmentSignature; private string _lastRaceBodySourceKey; private bool _testPresetMaterialReady = true; private string _cachedSteamId; private bool _respawnAfterTransition; private int _deferredSpawnPreset = -1; private int _queuedInteractivePreset = -1; private int _queuedInteractivePresetFrame = -1; private ProfileSaveData _pendingUserProfile; private float _lastAutoSaveTime; private Material _cachedDickMaterial; private Color _cachedDickColor; private bool _cachedDickMatchBody; private int _cachedDickTextureSourceMode; private Material _cachedBallMaterial; private Color _cachedBallColor; private bool _cachedBallMatchBody; private int _cachedBallTextureSourceMode; private Material[] _originalDickMaterials; private readonly Dictionary _originalMaterialsByRenderer = new Dictionary(); private Material[] _templateDickMaterials; private readonly Dictionary _templateMaterialsByRenderer = new Dictionary(); private bool _visAppliedShow = true; private bool _visPendingShow = true; private float _visPendingSince; private const float VisibilityDebounceSeconds = 0.2f; private bool _camHideStable; private bool _camHidePending; private float _camHidePendingSince; private const float CameraHideDebounceSeconds = 0.05f; public static ShlongController OurDick; internal static HashSet AllInstances = new HashSet(); internal static int TransitionCount; private static int _spawnBudgetFrame = -1; private static int _spawnBudgetUsed; private const int MaxSpawnsPerFrame = 2; private const int InteractivePresetApplyDelayFrames = 8; private static string _pendingCensusPreLog; private static string _pendingCensusPostLog; private SkinnedMeshRenderer _cachedBodySourceSMR; private int _cachedBodySourceRaceIndex = -1; public Player PlayerObj { get; set; } public bool IsLocal { get; set; } public int RaceIndex { get; set; } public int PresetIndex { get; set; } internal PlayerRaceModel CachedPlayerRaceModel => _cachedPlayerRaceModel; internal bool HasPlayerParent => _hasPlayerInParent; internal bool HasDeferredSpawn => _deferredSpawnPreset >= 0; internal bool HasRuntimeRig => (Object)(object)InstanceRoot != (Object)null || (Object)(object)DickMesh != (Object)null || (Object)(object)PelvisBone != (Object)null || (Object)(object)SizeBone != (Object)null; internal bool HasBallsSheathSlots { get { if (MaterialSkinUtility.HasBallsSheathMaterialSlot(_originalDickMaterials)) { return true; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(_templateDickMaterials)) { return true; } if ((Object)(object)DickMesh != (Object)null && MaterialSkinUtility.HasBallsSheathMaterialSlot(((Renderer)DickMesh).sharedMaterials)) { return true; } return false; } } internal static int NormalizeTextureSourceMode(int mode) { return (mode == 1) ? 1 : 0; } internal static string FormatTextureSourceMode(int mode) { return (NormalizeTextureSourceMode(mode) == 1) ? "Plain Color" : "Body Texture"; } internal static ShlongController ResolveLocalAuthoritative() { if ((Object)(object)Player._mainPlayer != (Object)null) { ShlongController componentInChildren = ((Component)Player._mainPlayer).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.IsLocal && componentInChildren.HasPlayerParent) { return componentInChildren; } } if ((Object)(object)OurDick != (Object)null && OurDick.IsLocal && OurDick.HasPlayerParent) { return OurDick; } foreach (ShlongController allInstance in AllInstances) { if ((Object)(object)allInstance != (Object)null && allInstance.IsLocal && allInstance.HasPlayerParent) { return allInstance; } } return null; } private static bool TryConsumeSpawnBudget() { int frameCount = Time.frameCount; if (_spawnBudgetFrame != frameCount) { _spawnBudgetFrame = frameCount; _spawnBudgetUsed = 0; } if (_spawnBudgetUsed >= 2) { return false; } _spawnBudgetUsed++; return true; } private string ClassifyBranch() { if (_hasPlayerInParent) { return "playerParented"; } if (((Object)((Component)this).gameObject).name.Contains("equipDisplay")) { return "equipDisplay"; } return "other"; } private static void CaptureCensus() { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = 0; int num10 = 0; int num11 = 0; int num12 = 0; int num13 = 0; foreach (ShlongController allInstance in AllInstances) { if ((Object)(object)allInstance == (Object)null) { num13++; continue; } string text = allInstance.ClassifyBranch(); bool flag = allInstance.ShouldTeardownForTransition(); switch (text) { case "equipDisplay": num++; break; case "localCosmetic": num2++; break; case "playerParented": num3++; break; default: num4++; break; } if (flag) { num10++; } else { num11++; } if (allInstance.HasRuntimeRig) { num12++; } if ((Object)(object)allInstance.SizeBone != (Object)null) { num5++; } if ((Object)(object)allInstance.PelvisBone != (Object)null) { num6++; } if ((Object)(object)allInstance.BallBone != (Object)null) { num7++; } if ((Object)(object)allInstance.InstanceRoot != (Object)null) { num8++; } if ((Object)(object)allInstance.DickMesh != (Object)null) { num9++; } } _pendingCensusPreLog = "[TransitionCensus] t=" + TransitionCount + " total=" + AllInstances.Count + " null=" + num13 + " equip=" + num + " cosmetic=" + num2 + " player=" + num3 + " other=" + num4 + " teardownY=" + num10 + " teardownN=" + num11 + " rigs=" + num12 + " liveSizeBone=" + num5 + " livePelvisBone=" + num6 + " liveBallBone=" + num7 + " liveInstRoot=" + num8 + " liveDickMesh=" + num9 + " loadBuf=" + RaceModelPatch.LoadingAttachBuffered + " frame=" + Time.frameCount; } internal static void FlushPendingCensusLog() { if (_pendingCensusPreLog != null) { if (Plugin.IsDebug) { Plugin.LogDebug(_pendingCensusPreLog); } _pendingCensusPreLog = null; } if (_pendingCensusPostLog != null) { if (Plugin.IsDebug) { Plugin.LogDebug(_pendingCensusPostLog); } _pendingCensusPostLog = null; } } internal static void QuickDeactivateAllRigs() { foreach (ShlongController allInstance in AllInstances) { if (!((Object)(object)allInstance == (Object)null) && (Object)(object)allInstance.InstanceRoot != (Object)null) { allInstance.InstanceRoot.SetActive(false); } } } internal static void BeginTransitionTeardownLocal() { if (Plugin.IsDebug) { CaptureCensus(); } ShlongController[] array = new ShlongController[AllInstances.Count]; AllInstances.CopyTo(array); int num = 0; foreach (ShlongController shlongController in array) { if ((Object)(object)shlongController != (Object)null && shlongController.ShouldTeardownForTransition()) { shlongController.BeginTransitionTeardown(); num++; } } if (!Plugin.IsDebug) { return; } int num2 = 0; int num3 = 0; int num4 = 0; foreach (ShlongController allInstance in AllInstances) { if (!((Object)(object)allInstance == (Object)null)) { if (allInstance.HasRuntimeRig) { num2++; } if ((Object)(object)allInstance.SizeBone != (Object)null) { num3++; } if ((Object)(object)allInstance.PelvisBone != (Object)null) { num4++; } } } _pendingCensusPostLog = "[TransitionCensus] POST-teardown: teardownRan=" + num + " survivingRigs=" + num2 + " survivingSizeBone=" + num3 + " survivingPelvis=" + num4 + " frame=" + Time.frameCount; } private bool ShouldTeardownForTransition() { return _hasPlayerInParent; } private void BeginTransitionTeardown() { if (_hasPlayerInParent && !_respawnAfterTransition && (!((Object)(object)InstanceRoot == (Object)null) || !((Object)(object)PelvisBone == (Object)null) || !((Object)(object)DickMesh == (Object)null))) { LifecycleDiagnostics.OnTransitionTeardown(); if (Plugin.IsDebug) { Plugin.LogDebug("[TransitionTeardown] " + ((Object)((Component)this).gameObject).name + " local=" + IsLocal + " preset=" + PresetIndex + " frame=" + Time.frameCount); } ModelAttacher.Destroy(InstanceRoot, DickMesh, PelvisBone); InstanceRoot = null; SizeBone = null; DickMesh = null; BallMeshes = null; PelvisBone = null; BallBone = null; _shaftDynamicBones = null; _arousalControlsShaftJiggle = false; _shaftJiggleStateKnown = false; _cachedOriginalBodyMaterial = null; _cachedHipBone = null; _originalDickMaterials = null; _originalMaterialsByRenderer.Clear(); _templateDickMaterials = null; _templateMaterialsByRenderer.Clear(); _respawnAfterTransition = true; } } private void Start() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 AllInstances.Add(this); InitializeOwnershipFromHierarchy(); if ((Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 0) { _deferRegistration = true; LifecycleDiagnostics.OnLoadingStartCall(); } else { TryRegisterInDict(); } } internal void InitializeOwnershipFromHierarchy() { RaceModelEquipDisplay = ((Component)this).GetComponent(); Player componentInParent = ((Component)this).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { PlayerObj = componentInParent; IsLocal = (Object)(object)Player._mainPlayer != (Object)null && (Object)(object)componentInParent == (Object)(object)Player._mainPlayer; _hasPlayerInParent = true; HasReceivedRemoteVisualState = IsLocal; return; } _hasPlayerInParent = false; IsLocal = true; HasReceivedRemoteVisualState = true; if ((Object)(object)Player._mainPlayer != (Object)null) { PlayerObj = Player._mainPlayer; } } internal bool ShouldApplyLocalSavedProfile() { return !_hasPlayerInParent || IsLocal; } internal string GetKnownSteamId() { if (!string.IsNullOrEmpty(_cachedSteamId)) { return _cachedSteamId; } if ((Object)(object)PlayerObj != (Object)null) { try { string network_steamID = PlayerObj.Network_steamID; if (!string.IsNullOrEmpty(network_steamID)) { return network_steamID; } } catch { } } return null; } internal bool IsCharacterPreviewController() { if ((Object)(object)((Component)this).gameObject == (Object)null) { return false; } try { PlayerRaceModel component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null && RaceModelPatch.IsKnownCharacterPreviewRaceModel(component)) { return true; } } catch { } return ((Object)((Component)this).gameObject).name.IndexOf("equipDisplay", StringComparison.OrdinalIgnoreCase) >= 0; } internal void RememberPresetSettings(int presetIndex, PresetSettings settings) { if (presetIndex >= 0) { _presetMemory[presetIndex] = settings; } } internal void RememberPresetSettings(Dictionary settings) { if (settings == null) { return; } foreach (KeyValuePair setting in settings) { if (setting.Key >= 0) { _presetMemory[setting.Key] = setting.Value; } } } private unsafe void UpdateCurrentPresetMemory(string reason) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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) if (PresetIndex >= 0) { _presetMemory[PresetIndex] = CaptureSettings(); PersistCurrentProfileSettings(reason); if (Plugin.IsDebug) { string[] obj = new string[16] { "[PresetMemorySave] reason=", reason, " controller=", ((Object)((Component)this).gameObject).name, " preset=", PresetIndex.ToString(), " color=", null, null, null, null, null, null, null, null, null }; Color colorTint = ColorTint; obj[7] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; colorTint = BallColorTint; obj[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[12] = " ballMatchBody="; obj[13] = BallMatchBody.ToString(); obj[14] = " frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } } internal bool IsOwnerForceHidden() { try { Player val = (((Object)(object)PlayerObj != (Object)null) ? PlayerObj : ((Component)this).GetComponentInParent()); if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)val._pVisual != (Object)null && val._pVisual._forceHidden) { return true; } if (val._isHidden) { return true; } } catch { } return false; } private int GetCurrentCharacterSlotIndex() { return RaceModelPatch.GetCurrentProfileIndex(); } private string GetCurrentCharacterName() { try { if ((Object)(object)ProfileDataManager._current != (Object)null && ProfileDataManager._current._characterFile != null) { return ProfileDataManager._current._characterFile._nickName ?? string.Empty; } } catch { } return string.Empty; } private string GetCurrentCharacterRaceTag() { try { if ((Object)(object)ProfileDataManager._current != (Object)null && ProfileDataManager._current._characterFile != null && ProfileDataManager._current._characterFile._appearanceProfile != null) { return ProfileDataManager._current._characterFile._appearanceProfile._setRaceTag ?? string.Empty; } } catch { } return string.Empty; } private bool TryLoadCharacterSettings(out ProfileSaveData profile, out Dictionary perPreset) { profile = null; perPreset = null; if (Plugin.UserPresets == null) { return false; } int currentCharacterSlotIndex = GetCurrentCharacterSlotIndex(); if (currentCharacterSlotIndex < 0) { return false; } CharacterSettingsEntry characterSettingsEntry = Plugin.UserPresets.LoadCharacterSettings(currentCharacterSlotIndex); if (characterSettingsEntry == null) { return false; } profile = characterSettingsEntry.LastUsed; perPreset = Plugin.UserPresets.ExtractPerPresetSettings(characterSettingsEntry); return profile != null || (perPreset != null && perPreset.Count > 0); } private void PersistCurrentProfileSettings(string reason) { if (!IsLocal || Plugin.UserPresets == null || PresetIndex < 0) { return; } int currentCharacterSlotIndex = GetCurrentCharacterSlotIndex(); ProfileSaveData profileSaveData = UserPresetManager.CaptureFromController(this); if (currentCharacterSlotIndex >= 0) { Plugin.UserPresets.SaveCharacterSettings(currentCharacterSlotIndex, GetCurrentCharacterName(), GetCurrentCharacterRaceTag(), profileSaveData, _presetMemory); if (Plugin.IsDebug) { Plugin.LogDebug("[CharacterProfileSave] reason=" + reason + " slot=" + currentCharacterSlotIndex + " character=" + GetCurrentCharacterName() + " preset=" + PresetIndex + " memoryCount=" + _presetMemory.Count + " frame=" + Time.frameCount); } } else { Plugin.UserPresets.SaveLastUsed(profileSaveData); Plugin.UserPresets.SavePerPresetSettings(_presetMemory); } } internal void QueueInitialSpawn(int presetIndex) { presetIndex = ResolvePresetForLocalAssets(presetIndex); _deferredSpawnPreset = presetIndex; LifecycleDiagnostics.OnQueueInitialSpawn(); if (Plugin.IsDebug) { Plugin.LogDebug("[QueueInitialSpawn] " + ((Object)((Component)this).gameObject).name + " preset=" + presetIndex + " frame=" + Time.frameCount); } } internal void QueueInteractivePresetChange(int presetIndex) { if (presetIndex < 0 || Plugin.Presets == null || presetIndex >= Plugin.Presets.PresetCount) { return; } presetIndex = ResolvePresetForLocalAssets(presetIndex); if (presetIndex >= 0 && presetIndex < Plugin.Presets.PresetCount && _queuedInteractivePreset != presetIndex && (_queuedInteractivePreset >= 0 || PresetIndex != presetIndex)) { _queuedInteractivePreset = presetIndex; _queuedInteractivePresetFrame = Time.frameCount; LifecycleDiagnostics.OnPresetQueued(); if (Plugin.IsDebug) { Plugin.LogDebug("[QueuePresetChange] " + ((Object)((Component)this).gameObject).name + " preset=" + presetIndex + " frame=" + Time.frameCount); } } } private static int ResolvePresetForLocalAssets(int presetIndex) { if (Plugin.Presets == null) { return presetIndex; } return Plugin.Presets.ResolvePresetForLocalAssets(presetIndex); } private bool IsPlayerCloneModel() { return ((Object)((Component)this).gameObject).name.Contains("(Clone)") && !IsCharacterPreviewController(); } private bool IsLocalPlayerController() { if (this == OurDick) { return true; } if (IsLocal) { return true; } if ((Object)(object)Player._mainPlayer != (Object)null) { ShlongController componentInChildren = ((Component)Player._mainPlayer).GetComponentInChildren(true); if (this == componentInChildren) { return true; } } return false; } private void CleanupOrphanedController(string reason, bool destroyComponent) { LifecycleDiagnostics.OnOrphanCleanup(); if (Plugin.IsDebug) { Plugin.LogDebug("[ControllerCleanup] " + reason + " target=" + ((Object)((Component)this).gameObject).name + " local=" + IsLocal + " frame=" + Time.frameCount); } ModelAttacher.Destroy(InstanceRoot, DickMesh, PelvisBone); InstanceRoot = null; SizeBone = null; DickMesh = null; BallMeshes = null; PelvisBone = null; BallBone = null; _shaftDynamicBones = null; _arousalControlsShaftJiggle = false; _shaftJiggleStateKnown = false; _cachedOriginalBodyMaterial = null; _cachedHipBone = null; _originalDickMaterials = null; _originalMaterialsByRenderer.Clear(); _templateDickMaterials = null; _templateMaterialsByRenderer.Clear(); _respawnAfterTransition = false; _deferredSpawnPreset = -1; _queuedInteractivePreset = -1; _queuedInteractivePresetFrame = -1; _registeredInDict = false; if (destroyComponent) { ((Behaviour)this).enabled = false; Object.Destroy((Object)(object)this); } } private bool ShouldBlockCloneRuntimeSpawnForDiagnostics() { return PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value && IsPlayerCloneModel() && !IsLocalPlayerController(); } private void ClearMaterialTemplateAndRuntimeCaches() { _templateDickMaterials = null; _templateMaterialsByRenderer.Clear(); _originalDickMaterials = null; _originalMaterialsByRenderer.Clear(); _cachedDickMaterial = null; _cachedBallMaterial = null; _cachedOriginalBodyMaterial = null; _testPresetMaterialReady = true; } private bool TryHandleBlockedCloneRuntimeSpawn(int presetIndex) { if (!ShouldBlockCloneRuntimeSpawnForDiagnostics()) { return false; } if ((Object)(object)InstanceRoot != (Object)null || (Object)(object)PelvisBone != (Object)null || (Object)(object)DickMesh != (Object)null) { ModelAttacher.Destroy(InstanceRoot, DickMesh, PelvisBone); InstanceRoot = null; SizeBone = null; DickMesh = null; BallMeshes = null; PelvisBone = null; BallBone = null; _shaftDynamicBones = null; _arousalControlsShaftJiggle = false; _shaftJiggleStateKnown = false; _cachedOriginalBodyMaterial = null; _cachedHipBone = null; _originalDickMaterials = null; _originalMaterialsByRenderer.Clear(); _templateDickMaterials = null; _templateMaterialsByRenderer.Clear(); } _deferredSpawnPreset = -1; PresetIndex = presetIndex; LifecycleDiagnostics.OnSpawnBlockedForDiagnostics(); if (Plugin.IsDebug) { Plugin.LogDebug("[Diag] Clone runtime spawn blocked: " + ((Object)((Component)this).gameObject).name + " preset=" + presetIndex + " frame=" + Time.frameCount); } TryRegisterInDict(); return true; } private bool CanExecuteDeferredCloneSpawn() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if (!IsPlayerCloneModel()) { return true; } if ((Object)(object)Player._mainPlayer == (Object)null || (int)Player._mainPlayer._currentGameCondition != 1) { return false; } InitializeOwnershipFromHierarchy(); if (!_hasPlayerInParent || (Object)(object)PlayerObj == (Object)null) { return false; } string network_steamID = PlayerObj.Network_steamID; if (!string.IsNullOrEmpty(network_steamID) && !IsLocal && !string.IsNullOrEmpty(Plugin.LocalSteamId) && network_steamID == Plugin.LocalSteamId) { LifecycleDiagnostics.OnRegisterRejected(); if (Plugin.IsDebug) { Plugin.LogDebug("[DeferredSpawnReject] Non-local clone resolved to local identity on " + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } CleanupOrphanedController("DeferredSpawnReject", destroyComponent: true); return false; } return !string.IsNullOrEmpty(network_steamID); } private void TryRegisterInDict() { if (_registeredInDict) { return; } InitializeOwnershipFromHierarchy(); if (IsPlayerCloneModel() && _deferredSpawnPreset >= 0) { return; } if ((Object)(object)PlayerObj == (Object)null) { if (IsLocal && (Object)(object)Player._mainPlayer != (Object)null) { PlayerObj = Player._mainPlayer; } else { Player componentInParent = ((Component)this).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { PlayerObj = componentInParent; IsLocal = (Object)(object)Player._mainPlayer != (Object)null && (Object)(object)componentInParent == (Object)(object)Player._mainPlayer; _hasPlayerInParent = true; } } } if ((Object)(object)PlayerObj == (Object)null || Plugin.Controllers == null || !_hasPlayerInParent) { return; } try { string network_steamID = PlayerObj.Network_steamID; if (string.IsNullOrEmpty(network_steamID)) { return; } if (!IsLocal && !string.IsNullOrEmpty(Plugin.LocalSteamId) && network_steamID == Plugin.LocalSteamId) { LifecycleDiagnostics.OnRegisterRejected(); if (Plugin.IsDebug) { Plugin.LogDebug("[TryRegisterInDict] Skipping non-local registration for " + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } CleanupOrphanedController("RegisterReject", destroyComponent: true); return; } if (Plugin.Controllers.TryGetValue(network_steamID, out var value) && (Object)(object)value != (Object)null && (Object)(object)value != (Object)(object)this) { bool flag = value.PresetIndex >= 0 || (Object)(object)value.DickMesh != (Object)null || value._registeredInDict; bool flag2 = PresetIndex < 0; bool flag3 = TransitionCount > 0; if (!IsLocal && flag && flag2 && flag3) { LifecycleDiagnostics.OnRegister(overwrite: false); if (Plugin.IsDebug) { Plugin.LogDebug("[TryRegisterInDict] Transient clone deferred overwrite — keeping stable: stable=" + ((Object)((Component)value).gameObject).name + " transient=" + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } return; } LifecycleDiagnostics.OnRegister(overwrite: true); if (Plugin.IsDebug) { Plugin.LogDebug("[TryRegisterInDict] Overwriting controller old=" + ((Object)((Component)value).gameObject).name + " new=" + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } CosmeticDisplayManager.TransferRig(value, this); value.CleanupOrphanedController("OverwrittenBy:" + ((Object)((Component)this).gameObject).name, destroyComponent: true); } else { LifecycleDiagnostics.OnRegister(overwrite: false); } Plugin.Controllers[network_steamID] = this; _registeredInDict = true; _cachedSteamId = network_steamID; if (Plugin.IsDebug) { Plugin.LogDebug("Registered: local=" + IsLocal + " on " + ((Object)((Component)this).gameObject).name); } if (IsLocal) { ((MonoBehaviour)this).Invoke("DelayedSync", Random.Range(5f, 10f)); } } catch (Exception ex) { Plugin.LogErrorLimited("sc.register_in_dict", "TryRegisterInDict: " + ex.Message); } } private void DelayedSync() { if (IsLocal) { RequestSyncImmediate(); } } private void ApplyCurrentBlendShapeStateImmediate() { if (!((Object)(object)DickMesh == (Object)null) && !((Object)(object)DickMesh.sharedMesh == (Object)null) && DickMesh.sharedMesh.blendShapeCount != 0) { BlendShapes.ApplyArousedImmediate(DickMesh, ArousalTarget); BlendShapes.ApplyBulgeImmediate(DickMesh, BulgeAmount, BulgePosition, BulgeWidth, BulgeSharpness); UpdateShaftJiggleForArousal(); } } private void UpdateShaftJiggleForArousal() { if (!_arousalControlsShaftJiggle || _shaftDynamicBones == null || _shaftDynamicBones.Length == 0) { return; } bool flag = ArousalTarget > 0.001f; if (_shaftJiggleStateKnown && _shaftJiggleActive == flag) { return; } _shaftJiggleStateKnown = true; _shaftJiggleActive = flag; float weight = (flag ? 1f : 0f); for (int i = 0; i < _shaftDynamicBones.Length; i++) { DynamicBone val = _shaftDynamicBones[i]; if ((Object)(object)val != (Object)null) { val.SetWeight(weight); } } } private void Update() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Invalid comparison between Unknown and I4 //IL_096e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 0) { return; } if (_deferRegistration && (Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 1) { _deferRegistration = false; TryRegisterInDict(); if (Plugin.IsDebug) { Plugin.LogDebug("[Fix114] Deferred registration flushed: " + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } } if (_respawnAfterTransition) { if ((Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 1 && ((Component)this).gameObject.activeInHierarchy) { if (Plugin.IsDebug) { Plugin.LogDebug("[TransitionRespawn] " + ((Object)((Component)this).gameObject).name + " preset=" + PresetIndex + " frame=" + Time.frameCount); } LifecycleDiagnostics.OnTransitionRespawn(); _respawnAfterTransition = false; Spawn(PresetIndex); } return; } if (_deferredSpawnPreset >= 0) { if (!((Component)this).gameObject.activeInHierarchy || !CanExecuteDeferredCloneSpawn()) { return; } int presetIndex = _deferredSpawnPreset; _deferredSpawnPreset = -1; if (!IsLocal && _hasPlayerInParent) { PresetIndex = -1; TryRegisterInDict(); if (Plugin.IsDebug) { Plugin.LogDebug("[DeferredSpawn] Skipped for remote (no mod sync yet): " + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } return; } ProfileSaveData profile = null; if (_presetMemory.Count == 0) { Dictionary perPreset = null; if (TryLoadCharacterSettings(out profile, out perPreset)) { RememberPresetSettings(perPreset); if (Plugin.IsDebug && perPreset != null && perPreset.Count > 0) { Plugin.LogDebug("[CharacterPresetLoad] Loaded " + perPreset.Count + " per-character preset entries on " + ((Object)((Component)this).gameObject).name); } } else { if (Plugin.UserPresets != null) { perPreset = Plugin.UserPresets.LoadPerPresetSettings(); RememberPresetSettings(perPreset); if (Plugin.IsDebug && perPreset.Count > 0) { Plugin.LogDebug("[PerPresetLoad] Loaded legacy " + perPreset.Count + " per-preset entries on " + ((Object)((Component)this).gameObject).name); } } if (Plugin.UserPresets != null) { profile = Plugin.UserPresets.LoadLastUsed(); } } if (profile == null) { int currentProfileIndex = RaceModelPatch.GetCurrentProfileIndex(); if (currentProfileIndex >= 0 && currentProfileIndex < Plugin.LoadedProfiles.Length) { profile = Plugin.LoadedProfiles[currentProfileIndex]; } } if (profile != null) { presetIndex = ResolvePresetForLocalAssets(profile.DickNumber); } } if (Plugin.IsDebug) { Plugin.LogDebug("[DeferredSpawn] " + ((Object)((Component)this).gameObject).name + " local=" + IsLocal + " preset=" + presetIndex + " profile=" + (profile != null) + " frame=" + Time.frameCount); } Spawn(presetIndex); if (profile != null) { ApplyLoadedProfile(profile); } if ((Object)(object)SizeBone != (Object)null) { LifecycleDiagnostics.OnDeferredSpawnSuccess(); } return; } if (_queuedInteractivePreset >= 0) { if (_queuedInteractivePresetFrame >= 0 && Time.frameCount - _queuedInteractivePresetFrame < 8) { return; } int num = ResolvePresetForLocalAssets(_queuedInteractivePreset); _queuedInteractivePreset = -1; _queuedInteractivePresetFrame = -1; if (Plugin.IsDebug) { Plugin.LogDebug("[ApplyQueuedPresetChange] " + ((Object)((Component)this).gameObject).name + " preset=" + num + " frame=" + Time.frameCount); } Spawn(num); if (PresetIndex == num) { if (_pendingUserProfile != null) { ApplyLoadedProfile(_pendingUserProfile); _pendingUserProfile = null; } LifecycleDiagnostics.OnPresetApplied(); if (IsLocal) { RequestSyncImmediate(forceSave: true, SyncField.Position | SyncField.Scale | SyncField.BallsSize | SyncField.Futa | SyncField.Clothing | SyncField.Rotation | SyncField.ErectAngle | SyncField.Color | SyncField.BallColor | SyncField.Hide | SyncField.Bulge); } } return; } if ((Object)(object)SizeBone == (Object)null && (Object)(object)PelvisBone != (Object)null) { if (Plugin.IsDebug) { Plugin.LogDebug("[Update] Stale state detected: SizeBone=null PelvisBone=" + ((Object)PelvisBone).name + " InstanceRoot=" + ((Object)(object)InstanceRoot != (Object)null) + " DickMesh=" + ((Object)(object)DickMesh != (Object)null) + " frame=" + Time.frameCount); } LoadingDiagnostics.DumpStatus("StaleDetected"); if ((Object)(object)PelvisBone != (Object)null) { PelvisBone.SetParent((Transform)null, false); Object.Destroy((Object)(object)((Component)PelvisBone).gameObject); PelvisBone = null; } SizeBone = null; BallBone = null; _shaftDynamicBones = null; _arousalControlsShaftJiggle = false; _shaftJiggleStateKnown = false; InstanceRoot = null; DickMesh = null; _cachedHipBone = null; Spawn(PresetIndex); return; } if ((Object)(object)SizeBone == (Object)null) { if (!IsLocal || !_hasPlayerInParent) { return; } OurDick = this; if (!_cachedComponentsDone) { _cachedPlayerRaceModel = (((Object)(object)RaceModelEquipDisplay != (Object)null) ? ((Component)RaceModelEquipDisplay).GetComponent() : ((Component)this).GetComponent()); _cachedPlayerClimbing = ((Component)this).GetComponentInParent(); _cachedComponentsDone = true; } if ((Object)(object)_cachedPlayerClimbing != (Object)null && !((Behaviour)_cachedPlayerClimbing).enabled) { return; } } else { if ((Object)(object)InstanceRoot == (Object)null && (Object)(object)DickMesh == (Object)null) { if (Plugin.IsDebug) { Plugin.LogDebug("[Update] InstanceRoot+DickMesh null but SizeBone alive — respawning frame=" + Time.frameCount); } LoadingDiagnostics.DumpStatus("StaleDetected2"); if ((Object)(object)PelvisBone != (Object)null) { PelvisBone.SetParent((Transform)null, false); Object.Destroy((Object)(object)((Component)PelvisBone).gameObject); PelvisBone = null; } SizeBone = null; BallBone = null; _shaftDynamicBones = null; _arousalControlsShaftJiggle = false; _shaftJiggleStateKnown = false; _cachedHipBone = null; Spawn(PresetIndex); return; } if (!_registeredInDict && Time.frameCount % 30 == 0) { TryRegisterInDict(); } if (!IsLocal && (Object)(object)Player._mainPlayer != (Object)null && (Object)(object)PlayerObj != (Object)null && (Object)(object)PlayerObj == (Object)(object)Player._mainPlayer) { IsLocal = true; } if (!_cachedComponentsDone) { _cachedPlayerRaceModel = (((Object)(object)RaceModelEquipDisplay != (Object)null) ? ((Component)RaceModelEquipDisplay).GetComponent() : ((Component)this).GetComponent()); _cachedPlayerClimbing = ((Component)this).GetComponentInParent(); _cachedComponentsDone = true; } if ((Object)(object)DickMesh != (Object)null) { int num2 = ((Object)this).GetInstanceID() & 0x7FFFFFFF; if ((!_testPresetMaterialReady && (Time.frameCount + num2) % 3 == 0) || (Time.frameCount + num2) % 300 == 0) { TryResyncMaterial(); } } if ((Object)(object)InstanceRoot != (Object)null) { InstanceRoot.transform.position = ((Component)this).transform.position; } UpdateShaftJiggleForArousal(); if ((Object)(object)DickMesh != (Object)null && (Object)(object)DickMesh.sharedMesh != (Object)null && DickMesh.sharedMesh.blendShapeCount > 0) { BlendShapes.ApplyAroused(DickMesh, ArousalTarget, ArousalLerpSpeed); BlendShapes.ApplyBulge(DickMesh, BulgeAmount, BulgePosition, BulgeWidth, BulgeSharpness, BulgeLerpSpeed); } if (IsLocal || Time.frameCount % 3 == 0) { UpdateVisibility(); } if (!IsLocal) { return; } if (!_hasPlayerInParent) { if (Plugin.IsDebug && Time.frameCount % 300 == 0) { Plugin.LogDebug("[Update] Skipping local input/sync — no player parent: " + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } return; } if ((Object)(object)_cachedPlayerClimbing != (Object)null && !((Behaviour)_cachedPlayerClimbing).enabled) { return; } OurDick = this; } if (SettingsWindow.IsHovered) { return; } bool flag = false; flag |= InputManager.ProcessKeyboardInput(this); if (flag) { SyncDirty = true; } if (!flag && WasKeyAdjusting) { RequestSyncImmediate(); } WasKeyAdjusting = flag; if (SyncDirty && Time.unscaledTime - _lastSyncTime >= 0.5f) { SyncDirty = false; Plugin.Network.SendSync(this); _lastSyncTime = Time.unscaledTime; } if (Time.unscaledTime - _lastHeartbeatTime >= 10f) { _lastHeartbeatTime = Time.unscaledTime; if (Plugin.Network != null) { Plugin.Network.SendFullSync(this); } } } private void UpdateVisibility() { if ((Object)(object)DickMesh == (Object)null) { return; } try { bool displayBoobs = (Object)(object)_cachedPlayerRaceModel != (Object)null && _cachedPlayerRaceModel._displayBoobs; bool hideLeggingsVisual = (Object)(object)RaceModelEquipDisplay != (Object)null && RaceModelEquipDisplay._hideLeggingsVisual; bool noLeggingsEquipped = LeggingsChecker.HasNoLeggingsEquipped(RaceModelEquipDisplay); bool flag = Plugin.CharMenuON || IsCharacterPreviewController() || RaceModelPatch.IsCharacterPreviewContext(); bool playerBodyVisible = flag || (Object)(object)_cachedPlayerRaceModel == (Object)null || (Object)(object)_cachedPlayerRaceModel._baseBodyMesh == (Object)null || ((Renderer)_cachedPlayerRaceModel._baseBodyMesh).enabled; bool flag2 = IsOwnerForceHidden(); bool testPresetMaterialReady = _testPresetMaterialReady; bool flag3 = testPresetMaterialReady && VisibilityResolver.ShouldShowDick(IsLocal, flag, ((Component)this).gameObject.activeInHierarchy, displayBoobs, FutaToggle, ClothingOverride, hideLeggingsVisual, noLeggingsEquipped, playerBodyVisible, HideToggle, flag2, flag ? CharacterSelectPreviewMode : 0, PluginConfig.HideOtherPlayersShlongs != null && PluginConfig.HideOtherPlayersShlongs.Value); if (flag3 != _visPendingShow) { _visPendingShow = flag3; _visPendingSince = Time.unscaledTime; } if ((flag3 == _visAppliedShow || Time.unscaledTime - _visPendingSince >= 0.2f || flag || flag2 || !testPresetMaterialReady) && flag3 != _visAppliedShow) { _visAppliedShow = flag3; } ((Renderer)DickMesh).enabled = _visAppliedShow; if (BallMeshes != null) { for (int i = 0; i < BallMeshes.Length; i++) { if ((Object)(object)BallMeshes[i] != (Object)null) { ((Renderer)BallMeshes[i]).enabled = _visAppliedShow; } } } if (!IsLocal || Plugin.CharMenuON || !_visAppliedShow || !((Object)(object)CameraCollision._current != (Object)null)) { return; } bool flag4 = VisibilityResolver.ShouldHideForCamera(CameraCollision._current._unhidePlayerModel); if (flag4 != _camHidePending) { _camHidePending = flag4; _camHidePendingSince = Time.unscaledTime; } if (Time.unscaledTime - _camHidePendingSince >= 0.05f || flag4 == _camHideStable) { _camHideStable = flag4; } if (!_camHideStable) { return; } ((Renderer)DickMesh).enabled = false; if (BallMeshes == null) { return; } for (int j = 0; j < BallMeshes.Length; j++) { if ((Object)(object)BallMeshes[j] != (Object)null) { ((Renderer)BallMeshes[j]).enabled = false; } } } catch { } } public void CycleArousal() { float[] array = new float[4] { 0f, 30f, 60f, 100f }; int num = Array.FindIndex(array, (float s) => s >= ArousalTarget); if (num < 0) { num = 0; } num = (num + 1) % array.Length; ArousalTarget = array[num]; RequestSyncImmediate(); } public PresetSettings CaptureSettings() { //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_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_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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) return new PresetSettings { ScaleOffset = ScaleOffset, BallsSizeOffset = BallsSizeOffset, PositionOffset = PositionOffset, BaseRotation = BaseRotation, ErectAngleOffset = ErectAngleOffset, ArousalTarget = ArousalTarget, BulgeAmount = BulgeAmount, BulgePosition = BulgePosition, BulgeWidth = BulgeWidth, BulgeSharpness = BulgeSharpness, BulgeLerpSpeed = BulgeLerpSpeed, ColorTint = ColorTint, ColorMode = ColorMode, MatchBody = MatchBody, TextureSourceMode = NormalizeTextureSourceMode(TextureSourceMode), BallColorTint = BallColorTint, BallColorMode = BallColorMode, BallMatchBody = BallMatchBody, BallTextureSourceMode = NormalizeTextureSourceMode(BallTextureSourceMode), FutaToggle = FutaToggle, ClothingOverride = ClothingOverride, HideToggle = HideToggle }; } public unsafe void ApplySettings(PresetSettings s) { //IL_0003: 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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: 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_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) ScaleOffset = s.ScaleOffset; BallsSizeOffset = s.BallsSizeOffset; PositionOffset = s.PositionOffset; BaseRotation = s.BaseRotation; ErectAngleOffset = s.ErectAngleOffset; ArousalTarget = s.ArousalTarget; BulgeAmount = Mathf.Clamp(s.BulgeAmount, 0f, 100f); BulgePosition = Mathf.Clamp(s.BulgePosition, 0f, 6f); BulgeWidth = ((s.BulgeWidth > 0.001f) ? s.BulgeWidth : 1f); BulgeSharpness = ((s.BulgeSharpness > 0.001f) ? s.BulgeSharpness : 1f); BulgeLerpSpeed = ((s.BulgeLerpSpeed > 0.001f) ? s.BulgeLerpSpeed : 2f); ColorTint = s.ColorTint; ColorMode = s.ColorMode; MatchBody = s.MatchBody; TextureSourceMode = NormalizeTextureSourceMode(s.TextureSourceMode); BallColorTint = s.BallColorTint; BallColorMode = s.BallColorMode; BallMatchBody = s.BallMatchBody; BallTextureSourceMode = NormalizeTextureSourceMode(s.BallTextureSourceMode); FutaToggle = s.FutaToggle; ClothingOverride = s.ClothingOverride; HideToggle = s.HideToggle; InvalidateColorMaterialCache(dick: true, balls: true); ApplyColorTint(); ApplyBallColorTint(); if (Plugin.IsDebug) { string[] obj = new string[14] { "[PresetMemoryRestore] preset=", PresetIndex.ToString(), " controller=", ((Object)((Component)this).gameObject).name, " restoresColor=true color=", null, null, null, null, null, null, null, null, null }; Color colorTint = s.ColorTint; obj[5] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[6] = " matchBody="; obj[7] = s.MatchBody.ToString(); obj[8] = " ballColor="; colorTint = s.BallColorTint; obj[9] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[10] = " ballMatchBody="; obj[11] = s.BallMatchBody.ToString(); obj[12] = " frame="; obj[13] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } internal unsafe void ApplyLoadedProfile(ProfileSaveData data, bool sync = true) { //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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) FutaToggle = data.FutaToggle; ClothingOverride = data.ClothingOverride; HideToggle = data.HideToggle; BallsSizeOffset = data.BallsSizeOffset; PositionOffset = new Vector2(data.DickOffsetX, data.DickOffsetY); BaseRotation = data.AngleOffset; ErectAngleOffset = data.ErectAngle; ScaleOffset = data.ScaleOffset; ColorTint = new Color(data.ColorR, data.ColorG, data.ColorB); ColorMode = data.ColorMode; MatchBody = data.MatchBody; bool flag = data.TextureSourceContractVersion >= 1; TextureSourceMode = (flag ? NormalizeTextureSourceMode(data.TextureSourceMode) : 0); ArousalLerpSpeed = data.ArousalLerpSpeed; BulgeAmount = Mathf.Clamp(data.BulgeAmount, 0f, 100f); BulgePosition = Mathf.Clamp(data.BulgePosition, 0f, 6f); BulgeWidth = ((data.BulgeWidth > 0.001f) ? data.BulgeWidth : 1f); BulgeSharpness = ((data.BulgeSharpness > 0.001f) ? data.BulgeSharpness : 1f); BulgeLerpSpeed = ((data.BulgeLerpSpeed > 0.001f) ? data.BulgeLerpSpeed : 2f); BallColorTint = new Color(data.BallColorR, data.BallColorG, data.BallColorB); BallColorMode = data.BallColorMode; BallMatchBody = data.BallMatchBody; BallTextureSourceMode = (flag ? NormalizeTextureSourceMode(data.BallTextureSourceMode) : 0); if (Plugin.IsDebug) { string[] obj = new string[18] { "[ProfileLoadApply] controller=", ((Object)((Component)this).gameObject).name, " preset=", data.DickNumber.ToString(), " color=", null, null, null, null, null, null, null, null, null, null, null, null, null }; Color colorTint = ColorTint; obj[5] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[6] = " colorMode="; obj[7] = ColorMode.ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; colorTint = BallColorTint; obj[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[12] = " ballColorMode="; obj[13] = BallColorMode.ToString(); obj[14] = " ballMatchBody="; obj[15] = BallMatchBody.ToString(); obj[16] = " frame="; obj[17] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } ApplyCurrentBlendShapeStateImmediate(); RefreshTransform(); ApplyColorTint(); ApplyBallColorTint(); if (sync && IsLocal && _hasPlayerInParent) { RequestSyncImmediate(forceSave: false, SyncField.Position | SyncField.Scale | SyncField.BallsSize | SyncField.Futa | SyncField.Clothing | SyncField.Rotation | SyncField.ErectAngle | SyncField.Color | SyncField.BallColor | SyncField.Hide | SyncField.Bulge); } } public void Spawn(int presetIndex, bool resetNetworkDelta = true, bool saveBeforeSwitch = true) { //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_053b: Unknown result type (might be due to invalid IL or missing references) //IL_0542: Unknown result type (might be due to invalid IL or missing references) //IL_0547: Unknown result type (might be due to invalid IL or missing references) //IL_0626: Unknown result type (might be due to invalid IL or missing references) //IL_062b: Unknown result type (might be due to invalid IL or missing references) presetIndex = ResolvePresetForLocalAssets(presetIndex); if (ShouldDeferSpawnDuringLoading()) { _deferredSpawnPreset = presetIndex; if (Plugin.IsDebug) { Plugin.LogDebug("[Spawn] Deferred during LOADING_GAME: preset=" + presetIndex + " race=" + RaceIndex + " on " + ((Object)((Component)this).gameObject).name + " local=" + IsLocal + " frame=" + Time.frameCount); } } else { if (TryHandleBlockedCloneRuntimeSpawn(presetIndex)) { return; } if (!IsCharacterPreviewController() && !TryConsumeSpawnBudget()) { _deferredSpawnPreset = presetIndex; if (Plugin.IsDebug) { Plugin.LogDebug("[Spawn] Staggered: preset=" + presetIndex + " on " + ((Object)((Component)this).gameObject).name + " frame=" + Time.frameCount); } return; } _deferredSpawnPreset = -1; LifecycleDiagnostics.OnSpawnCall(); LoadingDiagnostics.SpawnCallCount++; if (Plugin.IsDebug) { Plugin.LogDebug("[Spawn] preset=" + presetIndex + " race=" + RaceIndex + " on " + ((Object)((Component)this).gameObject).name + " spawnCount=" + LoadingDiagnostics.SpawnCallCount + " transition=" + TransitionCount + " frame=" + Time.frameCount); } if (saveBeforeSwitch && ((Object)(object)InstanceRoot != (Object)null || (Object)(object)DickMesh != (Object)null || (Object)(object)SizeBone != (Object)null)) { UpdateCurrentPresetMemory("SpawnBeforeSwitch"); } if ((Object)(object)InstanceRoot != (Object)null || (Object)(object)PelvisBone != (Object)null) { if (Plugin.IsDebug) { Plugin.LogDebug("[Spawn] Destroying old: InstanceRoot=" + ((Object)(object)InstanceRoot != (Object)null) + " DickMesh=" + ((Object)(object)DickMesh != (Object)null) + " PelvisBone=" + ((Object)(object)PelvisBone != (Object)null)); } ModelAttacher.Destroy(InstanceRoot, DickMesh, PelvisBone); InstanceRoot = null; SizeBone = null; DickMesh = null; BallMeshes = null; PelvisBone = null; BallBone = null; _shaftDynamicBones = null; _arousalControlsShaftJiggle = false; _shaftJiggleStateKnown = false; _cachedOriginalBodyMaterial = null; ClearMaterialTemplateAndRuntimeCaches(); } SpawnResult spawnResult = ModelAttacher.Spawn(presetIndex, RaceIndex, ((Component)this).transform, Plugin.Presets, Plugin.Log); if (!spawnResult.Success) { if (Plugin.IsDebug) { Plugin.LogDebug("[Spawn] FAILED for preset=" + presetIndex); } return; } InstanceRoot = spawnResult.InstanceRoot; SizeBone = spawnResult.SizeBone; BallBone = spawnResult.BallBone; PelvisBone = spawnResult.PelvisBone; _cachedHipBone = (((Object)(object)PelvisBone != (Object)null) ? PelvisBone.parent : null); DickMesh = spawnResult.DickMesh; BallMeshes = spawnResult.BallMeshes; _shaftDynamicBones = spawnResult.ShaftDynamicBones; _arousalControlsShaftJiggle = spawnResult.ArousalControlsShaftJiggle; _shaftJiggleStateKnown = false; _templateDickMaterials = ((spawnResult.TemplateDickMaterials != null) ? ((Material[])spawnResult.TemplateDickMaterials.Clone()) : null); _templateMaterialsByRenderer.Clear(); if (spawnResult.TemplateMaterialsByRenderer != null) { foreach (KeyValuePair item in spawnResult.TemplateMaterialsByRenderer) { if ((Object)(object)item.Key != (Object)null && item.Value != null) { _templateMaterialsByRenderer[item.Key] = (Material[])item.Value.Clone(); } } } BlendShapes.Reset(); BulgeAmount = 0f; BulgePosition = 0f; BulgeWidth = 1f; BulgeSharpness = 1f; BulgeLerpSpeed = 2f; PositionOffset = spawnResult.InitialOffset; BaseRotation = spawnResult.InitialRotation; PresetIndex = presetIndex; PresetData presetData = Plugin.Presets?.GetPreset(presetIndex); _testPresetMaterialReady = presetData == null || presetData.AssetSource != PresetAssetSource.Test; if (Plugin.IsDebug) { string[] obj = new string[10] { "[Spawn] OK: InstanceRoot=", ((Object)InstanceRoot).name, " DickMesh=", ((Object)(object)DickMesh != (Object)null).ToString(), " BallMeshes=", (BallMeshes != null) ? BallMeshes.Length.ToString() : "0", " PelvisBone=", ((Object)(object)PelvisBone != (Object)null).ToString(), " scene=", null }; Scene scene = InstanceRoot.scene; obj[9] = ((Scene)(ref scene)).name; Plugin.LogDebug(string.Concat(obj)); } _materialResyncCount = 0; _lastRaceBodyShader = null; _lastRaceBodyTexture = null; _lastRaceBodyAdjustmentSignature = null; _lastRaceBodySourceKey = null; _cachedOriginalBodyMaterial = GetOriginalBodyMaterial(); CacheOriginalShlongMaterialsFromCurrentNeutralState(); if (_presetMemory.TryGetValue(presetIndex, out var value)) { ApplySettings(value); } ApplyCurrentBlendShapeStateImmediate(); ForceColorAdjustmentMaterialRefresh("SpawnPresetSwitch preset=" + presetIndex); RefreshTransform(); if (resetNetworkDelta && IsLocal && Plugin.Network != null) { Plugin.Network.ResetDelta(); } TryRegisterInDict(); } } private bool ShouldDeferSpawnDuringLoading() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if (IsCharacterPreviewController()) { return false; } if ((Object)(object)Player._mainPlayer == (Object)null) { return false; } if ((int)Player._mainPlayer._currentGameCondition > 0) { return false; } Player val = PlayerObj ?? ((Component)this).GetComponentInParent(); if ((Object)(object)val == (Object)null) { return ((Object)((Component)this).gameObject).name.Contains("(Clone)"); } return (Object)(object)val != (Object)(object)Player._mainPlayer; } private bool ShouldDeferRegistrationDuringLoading() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if (IsCharacterPreviewController()) { return false; } if ((Object)(object)Player._mainPlayer == (Object)null) { return false; } if ((int)Player._mainPlayer._currentGameCondition > 0) { return false; } Player val = PlayerObj ?? ((Component)this).GetComponentInParent(); if ((Object)(object)val == (Object)null) { return ((Object)((Component)this).gameObject).name.Contains("(Clone)"); } return (Object)(object)val != (Object)(object)Player._mainPlayer; } private bool DickMeshHasBallsSheathSlots() { if (MaterialSkinUtility.HasBallsSheathMaterialSlot(_originalDickMaterials)) { return true; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(_templateDickMaterials)) { return true; } if ((Object)(object)DickMesh != (Object)null && MaterialSkinUtility.HasBallsSheathMaterialSlot(((Renderer)DickMesh).sharedMaterials)) { return true; } return false; } private static Material[] SelectSplitMaterialSource(Material[] originals, Material[] templates, Material[] live) { if (MaterialSkinUtility.HasBallsSheathMaterialSlot(originals)) { return originals; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(templates)) { return templates; } if (MaterialSkinUtility.HasBallsSheathMaterialSlot(live)) { return live; } return originals ?? templates ?? live; } private void ApplyTestPresetTextureFallbacks(PresetData testPreset, Material raceBodyMaterial) { if (testPreset == null || testPreset.AssetSource != PresetAssetSource.Test) { return; } bool flag = false; Texture2D val = ((Plugin.Assets != null) ? Plugin.Assets.FindBestTextureForPreset(testPreset) : null); if ((Object)(object)val != (Object)null) { flag |= ApplyTextureAssetFallbacksToRenderer(DickMesh, (Texture)(object)val, testPreset.Id, "TestBundle", "Dick"); if (BallMeshes != null) { for (int i = 0; i < BallMeshes.Length; i++) { flag |= ApplyTextureAssetFallbacksToRenderer(BallMeshes[i], (Texture)(object)val, testPreset.Id, "TestBundle", "Ball" + i); } } } Texture val2 = (((Object)(object)raceBodyMaterial != (Object)null) ? MaterialSkinUtility.GetBestVisualTexture(raceBodyMaterial) : null); if ((Object)(object)val2 != (Object)null) { flag |= ApplyBodyAtlasFallbacksToRenderer(DickMesh, raceBodyMaterial, testPreset.Id, "Dick"); if (BallMeshes != null) { for (int j = 0; j < BallMeshes.Length; j++) { flag |= ApplyBodyAtlasFallbacksToRenderer(BallMeshes[j], raceBodyMaterial, testPreset.Id, "Ball" + j); } } } if (Plugin.Presets != null) { int index = Plugin.Presets.FindOriginalCounterpartIndex(testPreset); PresetData preset = Plugin.Presets.GetPreset(index); if (preset != null && (Object)(object)preset.LoadedPrefab != (Object)null) { Material[] array = MaterialSkinUtility.FindBestPrefabRendererMaterials(preset.LoadedPrefab, preset.MeshName); if (array != null && array.Length != 0) { flag |= ApplyOriginalCounterpartTextureFallbacksToRenderer(DickMesh, array, testPreset.Id, preset.Id, "Dick"); if (BallMeshes != null) { for (int k = 0; k < BallMeshes.Length; k++) { flag |= ApplyOriginalCounterpartTextureFallbacksToRenderer(BallMeshes[k], array, testPreset.Id, preset.Id, "Ball" + k); } } } } } if (flag && Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][TestTextureFallbacks] controller=" + ((Object)((Component)this).gameObject).name + " testPreset=" + testPreset.Id + " testBundleTexture=" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "") + " bodyAtlasTexture=" + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "") + " frame=" + Time.frameCount); } } private bool ApplyBodyAtlasFallbacksToRenderer(SkinnedMeshRenderer renderer, Material raceBodyMaterial, string testPresetId, string group) { if ((Object)(object)renderer == (Object)null || (Object)(object)raceBodyMaterial == (Object)null) { return false; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if ((Object)(object)val == (Object)null) { continue; } bool flag2 = MaterialSkinUtility.IsBallsSheathMaterial(val) || (group?.StartsWith("Ball", StringComparison.OrdinalIgnoreCase) ?? false); bool copyColorAdjustments = false; if (MaterialSkinUtility.ApplyBodyAtlasVisuals(val, raceBodyMaterial, "RaceBodyAtlas:" + testPresetId + ":" + group + ":" + i, copyColorAdjustments)) { flag = true; if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][BodyAtlasFallbackSlot] controller=" + ((Object)((Component)this).gameObject).name + " group=" + group + " slot=" + i + " isBallSlot=" + flag2 + " match=" + copyColorAdjustments + " testPreset=" + testPresetId + " bodyTex=" + (((Object)(object)raceBodyMaterial.mainTexture != (Object)null) ? ((Object)raceBodyMaterial.mainTexture).name : "") + " current=" + ((Object)val).name + " frame=" + Time.frameCount); } } } if (flag) { ((Renderer)renderer).sharedMaterials = sharedMaterials; } return flag; } private bool ApplyTextureAssetFallbacksToRenderer(SkinnedMeshRenderer renderer, Texture texture, string testPresetId, string sourceLabel, string group) { if ((Object)(object)renderer == (Object)null || (Object)(object)texture == (Object)null) { return false; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if (!((Object)(object)val == (Object)null) && MaterialSkinUtility.ApplyTextureAssetIfTextureMissing(val, texture, sourceLabel + ":" + testPresetId + ":" + group + ":" + i)) { flag = true; if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][TestTextureFallbackSlot] controller=" + ((Object)((Component)this).gameObject).name + " group=" + group + " slot=" + i + " testPreset=" + testPresetId + " texture=" + ((Object)texture).name + " current=" + ((Object)val).name + " frame=" + Time.frameCount); } } } if (flag) { ((Renderer)renderer).sharedMaterials = sharedMaterials; } return flag; } private bool ApplyOriginalCounterpartTextureFallbacksToRenderer(SkinnedMeshRenderer renderer, Material[] fallbackMats, string testPresetId, string originalPresetId, string group) { if ((Object)(object)renderer == (Object)null || fallbackMats == null || fallbackMats.Length == 0) { return false; } Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if ((Object)(object)val == (Object)null) { continue; } Material val2 = MaterialSkinUtility.PickFallbackMaterialForSlot(val, fallbackMats, i); if (!((Object)(object)val2 == (Object)null) && MaterialSkinUtility.ApplyFallbackVisualsIfTextureMissing(val, val2)) { flag = true; if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][OriginalCounterpartFallbackSlot] controller=" + ((Object)((Component)this).gameObject).name + " group=" + group + " slot=" + i + " testPreset=" + testPresetId + " originalPreset=" + originalPresetId + " current=" + ((Object)val).name + " fallback=" + ((Object)val2).name + " tex=" + (((Object)(object)val.mainTexture != (Object)null) ? ((Object)val.mainTexture).name : "") + " frame=" + Time.frameCount); } } } if (flag) { ((Renderer)renderer).sharedMaterials = sharedMaterials; } return flag; } private static bool IsBodyAtlasRuntimeBase(Material mat) { if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(((Object)mat).name)) { return false; } return ((Object)mat).name.IndexOf("_BodyAtlas", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)mat).name.IndexOf("RaceBodyAtlas", StringComparison.OrdinalIgnoreCase) >= 0; } private static Material BuildSlotAwareMatchBodyBase(Material raceBase, Material visibleBodyBase, Material templateBase, bool matchBody) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if (!matchBody) { return raceBase ?? templateBase; } if ((Object)(object)raceBase != (Object)null && (Object)(object)visibleBodyBase != (Object)null && IsBodyAtlasRuntimeBase(raceBase)) { Material val = new Material(raceBase); ((Object)val).name = ((Object)raceBase).name.Replace(" (Instance)", "").Replace("_MatchedBodyBase", "") + "_MatchedBodyBase"; MaterialSkinUtility.CopyCharacterColorAdjustmentPropertiesForced(visibleBodyBase, val); MaterialSkinUtility.CopyBodyTintLikeProperties(visibleBodyBase, val); return val; } return visibleBodyBase ?? raceBase ?? templateBase; } private void ApplySplitColorToDickMesh() { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)DickMesh == (Object)null) { return; } Material[] sharedMaterials = ((Renderer)DickMesh).sharedMaterials; Material[] array = SelectSplitMaterialSource(_originalDickMaterials, _templateDickMaterials, sharedMaterials); if (array != null && array.Length != 0) { bool flag = MaterialSkinUtility.HasBallsSheathMaterialSlot(array); if (Plugin.IsDebug && !flag) { Plugin.LogDebug("[SplitColorSlot][WARN] split rebuild called but selected source has no BodyMat2 originalHas=" + MaterialSkinUtility.HasBallsSheathMaterialSlot(_originalDickMaterials) + " templateHas=" + MaterialSkinUtility.HasBallsSheathMaterialSlot(_templateDickMaterials) + " liveHas=" + MaterialSkinUtility.HasBallsSheathMaterialSlot(sharedMaterials)); } Material visibleBodyBase = GetCurrentRaceBodyMaterial() ?? GetOriginalBodyMaterial(); Material[] array2 = (Material[])(object)new Material[array.Length]; for (int i = 0; i < array.Length; i++) { Material val = array[i]; bool flag2 = MaterialSkinUtility.IsBallsSheathMaterial(val); Color tint = (flag2 ? BallColorTint : ColorTint); bool matchBody = (flag2 ? BallMatchBody : MatchBody); Material templateBase = ((_templateDickMaterials != null && i < _templateDickMaterials.Length) ? _templateDickMaterials[i] : null); Material baseMat = BuildSlotAwareMatchBodyBase(val, visibleBodyBase, templateBase, matchBody); int textureSourceMode = (flag2 ? BallTextureSourceMode : TextureSourceMode); array2[i] = BuildColoredMaterial(baseMat, tint, matchBody, textureSourceMode); } ((Renderer)DickMesh).sharedMaterials = array2; _cachedDickMaterial = ((array2.Length != 0) ? array2[0] : null); _cachedDickColor = ColorTint; _cachedDickMatchBody = MatchBody; _cachedDickTextureSourceMode = NormalizeTextureSourceMode(TextureSourceMode); _cachedBallColor = BallColorTint; _cachedBallMatchBody = BallMatchBody; _cachedBallTextureSourceMode = NormalizeTextureSourceMode(BallTextureSourceMode); } } internal void InvalidateColorMaterialCache(bool dick, bool balls) { if (dick) { _cachedDickMaterial = null; } if (balls) { _cachedBallMaterial = null; } } public void ApplyColorTint() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)DickMesh == (Object)null) { return; } if (DickMeshHasBallsSheathSlots()) { ApplySplitColorToDickMesh(); } else { ApplyColorToRenderer(DickMesh, _originalDickMaterials, _templateDickMaterials, ColorTint, MatchBody, TextureSourceMode, ref _cachedDickMaterial, ref _cachedDickColor, ref _cachedDickMatchBody, ref _cachedDickTextureSourceMode); } if (!Plugin.IsDebug) { return; } PresetData presetData = Plugin.Presets?.GetPreset(PresetIndex); if (presetData == null || presetData.AssetSource != PresetAssetSource.Test) { return; } Plugin.LogDebug("[MaterialGroups] preset=" + presetData.Id); Plugin.LogDebug("[MaterialGroups] DickMesh=" + ((Object)DickMesh).name + " mesh=" + (((Object)(object)DickMesh.sharedMesh != (Object)null) ? ((Object)DickMesh.sharedMesh).name : "null")); if (((Renderer)DickMesh).sharedMaterials != null) { for (int i = 0; i < ((Renderer)DickMesh).sharedMaterials.Length; i++) { Plugin.LogDebug("[MaterialGroups] Dick slot " + i + " material=" + (((Object)(object)((Renderer)DickMesh).sharedMaterials[i] != (Object)null) ? ((Object)((Renderer)DickMesh).sharedMaterials[i]).name.Replace(" (Instance)", "") : "null")); } } } public void ApplyBallColorTint() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)DickMesh != (Object)null && DickMeshHasBallsSheathSlots()) { ApplySplitColorToDickMesh(); } if (BallMeshes == null) { return; } for (int i = 0; i < BallMeshes.Length; i++) { SkinnedMeshRenderer val = BallMeshes[i]; if ((Object)(object)val == (Object)null) { continue; } _originalMaterialsByRenderer.TryGetValue(val, out var value); _templateMaterialsByRenderer.TryGetValue(val, out var value2); ApplyColorToRenderer(val, value, value2, BallColorTint, BallMatchBody, BallTextureSourceMode, ref _cachedBallMaterial, ref _cachedBallColor, ref _cachedBallMatchBody, ref _cachedBallTextureSourceMode); if (!Plugin.IsDebug) { continue; } PresetData presetData = Plugin.Presets?.GetPreset(PresetIndex); if (presetData == null || presetData.AssetSource != PresetAssetSource.Test) { continue; } Plugin.LogDebug("[MaterialGroups] Ball/Sheath renderer=" + ((Object)val).name + " mesh=" + (((Object)(object)val.sharedMesh != (Object)null) ? ((Object)val.sharedMesh).name : "null")); if (((Renderer)val).sharedMaterials != null) { for (int j = 0; j < ((Renderer)val).sharedMaterials.Length; j++) { Plugin.LogDebug("[MaterialGroups] Ball/Sheath slot " + j + " material=" + (((Object)(object)((Renderer)val).sharedMaterials[j] != (Object)null) ? ((Object)((Renderer)val).sharedMaterials[j]).name.Replace(" (Instance)", "") : "null")); } } } } private void CacheOriginalShlongMaterials() { _originalDickMaterials = null; _originalMaterialsByRenderer.Clear(); _cachedDickMaterial = null; _cachedBallMaterial = null; if (_templateDickMaterials == null && (Object)(object)DickMesh != (Object)null && ((Renderer)DickMesh).sharedMaterials != null) { _templateDickMaterials = (Material[])((Renderer)DickMesh).sharedMaterials.Clone(); if (Plugin.IsDebug) { Plugin.LogDebug("[OriginalMaterialCache] captured templates (dick) count=" + _templateDickMaterials.Length); } } if (BallMeshes != null) { for (int i = 0; i < BallMeshes.Length; i++) { SkinnedMeshRenderer val = BallMeshes[i]; if ((Object)(object)val != (Object)null && ((Renderer)val).sharedMaterials != null && !_templateMaterialsByRenderer.ContainsKey(val)) { _templateMaterialsByRenderer[val] = (Material[])((Renderer)val).sharedMaterials.Clone(); if (Plugin.IsDebug) { Plugin.LogDebug("[OriginalMaterialCache] captured templates (ball) count=" + ((Renderer)val).sharedMaterials.Length); } } } } if (_templateDickMaterials != null && _templateDickMaterials.Length != 0) { _originalDickMaterials = (Material[])(object)new Material[_templateDickMaterials.Length]; for (int j = 0; j < _templateDickMaterials.Length; j++) { Material val2 = _templateDickMaterials[j]; if ((Object)(object)val2 != (Object)null && IsGeneratedColorMaterial(val2) && Plugin.IsDebug) { Plugin.LogDebug("[OriginalMaterialCache] prevented generated material from becoming original source=template slot=" + j + " mat=" + ((Object)val2).name); } _originalDickMaterials[j] = val2; } } else if ((Object)(object)DickMesh != (Object)null && ((Renderer)DickMesh).sharedMaterials != null) { _originalDickMaterials = (Material[])((Renderer)DickMesh).sharedMaterials.Clone(); } if (BallMeshes == null) { return; } for (int k = 0; k < BallMeshes.Length; k++) { SkinnedMeshRenderer val3 = BallMeshes[k]; if (!((Object)(object)val3 == (Object)null)) { if (_templateMaterialsByRenderer.TryGetValue(val3, out var value) && value != null) { _originalMaterialsByRenderer[val3] = (Material[])value.Clone(); } else if (((Renderer)val3).sharedMaterials != null) { _originalMaterialsByRenderer[val3] = (Material[])((Renderer)val3).sharedMaterials.Clone(); } } } } private void CacheOriginalShlongMaterialsFromCurrentNeutralState() { _originalDickMaterials = null; _originalMaterialsByRenderer.Clear(); _cachedDickMaterial = null; _cachedBallMaterial = null; if ((Object)(object)DickMesh != (Object)null && ((Renderer)DickMesh).sharedMaterials != null) { _originalDickMaterials = (Material[])((Renderer)DickMesh).sharedMaterials.Clone(); } if (BallMeshes == null) { return; } for (int i = 0; i < BallMeshes.Length; i++) { SkinnedMeshRenderer val = BallMeshes[i]; if ((Object)(object)val != (Object)null && ((Renderer)val).sharedMaterials != null) { _originalMaterialsByRenderer[val] = (Material[])((Renderer)val).sharedMaterials.Clone(); } } } private void ApplyColorToRenderer(SkinnedMeshRenderer smr, Material[] originalMaterials, Material[] templateMaterials, Color tint, bool matchBody, int textureSourceMode, ref Material cachedMat, ref Color cachedColor, ref bool cachedMatch, ref int cachedTextureSourceMode) { //IL_01a8: 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_0171: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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) textureSourceMode = NormalizeTextureSourceMode(textureSourceMode); Material val = (matchBody ? (GetCurrentRaceBodyMaterial() ?? GetOriginalBodyMaterial()) : null); if (originalMaterials == null || originalMaterials.Length <= 1) { Material val2 = ((originalMaterials != null && originalMaterials.Length == 1 && (Object)(object)originalMaterials[0] != (Object)null) ? originalMaterials[0] : (((Renderer)smr).sharedMaterial ?? GetOriginalBodyMaterial())); Material val3 = ((templateMaterials != null && templateMaterials.Length >= 1) ? templateMaterials[0] : null); Material baseMat = (matchBody ? (val ?? val2 ?? val3) : (val2 ?? val3)); if ((Object)(object)cachedMat != (Object)null && cachedColor == tint && cachedMatch == matchBody && cachedTextureSourceMode == textureSourceMode) { if ((Object)(object)((Renderer)smr).sharedMaterial != (Object)(object)cachedMat) { ((Renderer)smr).sharedMaterial = cachedMat; } } else { Material val4 = (((Renderer)smr).sharedMaterial = BuildColoredMaterial(baseMat, tint, matchBody, textureSourceMode)); cachedMat = val4; cachedColor = tint; cachedMatch = matchBody; cachedTextureSourceMode = textureSourceMode; } } else { Material[] array = (Material[])(object)new Material[originalMaterials.Length]; for (int i = 0; i < originalMaterials.Length; i++) { Material val6 = originalMaterials[i] ?? ((Renderer)smr).sharedMaterials[i]; Material val7 = ((templateMaterials != null && i < templateMaterials.Length) ? templateMaterials[i] : null); Material baseMat2 = (matchBody ? (val ?? val6 ?? val7) : (val6 ?? val7)); array[i] = BuildColoredMaterial(baseMat2, tint, matchBody, textureSourceMode); } ((Renderer)smr).sharedMaterials = array; cachedMat = ((array.Length != 0) ? array[0] : null); cachedColor = tint; cachedMatch = matchBody; cachedTextureSourceMode = textureSourceMode; } } internal unsafe static Material BuildColoredMaterial(Material baseMat, Color tint, bool matchBody, int textureSourceMode = 0) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0074: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013a: 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) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0189: 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_021d: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)baseMat == (Object)null) { return null; } textureSourceMode = NormalizeTextureSourceMode(textureSourceMode); Material val = new Material(baseMat); ((Object)val).name = ((Object)baseMat).name.Replace(" (Instance)", "").Replace("_ShlongColorRuntime", "") + "_ShlongColorRuntime"; if (textureSourceMode == 1) { MaterialSkinUtility.ApplyBlankTextureToMainSlots(val); } if (matchBody) { if (!ApplyAdditiveToProperty(val, "_Color", tint) && !ApplyAdditiveToProperty(val, "_BaseColor", tint)) { ApplyAdditiveFallback(val, tint); } } else { bool flag = ((Object)baseMat).name != null && ((Object)baseMat).name.IndexOf("_TextureOriginal_RaceShader", StringComparison.OrdinalIgnoreCase) >= 0; bool flag2 = ((Object)baseMat).name != null && ((Object)baseMat).name.IndexOf("_BodyAtlas", StringComparison.OrdinalIgnoreCase) >= 0; MaterialSkinUtility.NeutralizeCharacterColorAdjustmentProperties(val); Color val2 = ((textureSourceMode == 1) ? Color.white : (flag ? MaterialSkinUtility.GetBestSourceVisualColor(baseMat) : Color.white)); if (flag && MaterialSkinUtility.ApproximatelyBlack(val2) && MaterialSkinUtility.HasUsableVisualTexture(baseMat)) { val2 = Color.white; } Color val3 = MultiplyColor(val2, tint); bool flag3 = ApplySolidToProperty(val, "_Color", val3, forceAlphaOne: true); bool flag4 = ApplySolidToProperty(val, "_BaseColor", val3, forceAlphaOne: true); bool flag5 = flag3 || flag4; if (flag) { if (val.HasProperty("_ColorTint")) { val.SetColor("_ColorTint", val3); flag5 = true; } if (val.HasProperty("_Tint")) { val.SetColor("_Tint", val3); flag5 = true; } } else { MaterialSkinUtility.NeutralizeBodyTintLikeProperties(val); } if (!flag5) { if (val.HasProperty("_TintColor")) { val.SetColor("_TintColor", val3); flag5 = true; } else { ApplySolidFallback(val, val3); } } else if (val.HasProperty("_TintColor")) { val.SetColor("_TintColor", val3); } if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", Color.black); } if (Plugin.IsDebug) { string[] obj = new string[22] { "[ColorTexturePreserveBuild] material=", ((Object)baseMat).name, " matchBody=false textureOriginalBase=", flag.ToString(), " bodyAtlasBase=", flag2.ToString(), " sourceVisual=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null }; Color val4 = val2; obj[7] = ((object)(*(Color*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj[8] = " tint="; val4 = tint; obj[9] = ((object)(*(Color*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj[10] = " finalTint="; val4 = val3; obj[11] = ((object)(*(Color*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj[12] = " shader="; obj[13] = (((Object)(object)val.shader != (Object)null) ? ((Object)val.shader).name : ""); obj[14] = " renderQueue="; obj[15] = val.renderQueue.ToString(); obj[16] = " tex="; obj[17] = (((Object)(object)val.mainTexture != (Object)null) ? ((Object)val.mainTexture).name : ""); obj[18] = " hasColor="; obj[19] = val.HasProperty("_Color").ToString(); obj[20] = " hasBaseColor="; obj[21] = val.HasProperty("_BaseColor").ToString(); Plugin.LogDebug(string.Concat(obj)); } } return val; } private static Color MultiplyColor(Color a, Color b) { //IL_0001: 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_000e: 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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_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_0035: Unknown result type (might be due to invalid IL or missing references) return new Color(a.r * b.r, a.g * b.g, a.b * b.b, 1f); } internal static bool IsGeneratedColorMaterial(Material mat) { if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(((Object)mat).name)) { return false; } return ((Object)mat).name.IndexOf("_ShlongColorRuntime", StringComparison.OrdinalIgnoreCase) >= 0; } internal static bool ApplySolidToProperty(Material mat, string propName, Color color, bool forceAlphaOne = false) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0034: 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_0041: Unknown result type (might be due to invalid IL or missing references) if (!mat.HasProperty(propName)) { return false; } Color color2 = mat.GetColor(propName); float num = (forceAlphaOne ? 1f : color2.a); mat.SetColor(propName, new Color(color.r, color.g, color.b, num)); return true; } internal static bool ApplySolidFallback(Material mat, Color color) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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) try { Shader shader = mat.shader; int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if ((int)shader.GetPropertyType(i) == 0) { string propertyName = shader.GetPropertyName(i); mat.SetColor(propertyName, new Color(color.r, color.g, color.b, 1f)); return true; } } } catch { if (Plugin.IsDebug) { Plugin.LogDebug("[ApplyColorTint] Cannot set solid color on shader: " + ((Object)mat.shader).name); } } return false; } internal static void ForceOpaqueSolidMaterial(Material mat) { if (!((Object)(object)mat == (Object)null)) { if (mat.HasProperty("_Mode")) { mat.SetFloat("_Mode", 0f); } if (mat.HasProperty("_SrcBlend")) { mat.SetFloat("_SrcBlend", 1f); } if (mat.HasProperty("_DstBlend")) { mat.SetFloat("_DstBlend", 0f); } if (mat.HasProperty("_ZWrite")) { mat.SetFloat("_ZWrite", 1f); } if (mat.HasProperty("_Surface")) { mat.SetFloat("_Surface", 0f); } if (mat.HasProperty("_AlphaClip")) { mat.SetFloat("_AlphaClip", 0f); } if (mat.HasProperty("_Cutoff")) { mat.SetFloat("_Cutoff", 0f); } mat.DisableKeyword("_ALPHATEST_ON"); mat.DisableKeyword("_ALPHABLEND_ON"); mat.DisableKeyword("_ALPHAPREMULTIPLY_ON"); mat.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); mat.EnableKeyword("_SURFACE_TYPE_OPAQUE"); mat.renderQueue = 2000; } } internal static void NeutralizeTextures(Material mat) { Texture2D whiteTexture = GetWhiteTexture(); string[] array = new string[2] { "_MainTex", "_BaseMap" }; string[] array2 = array; foreach (string text in array2) { if (mat.HasProperty(text)) { mat.SetTexture(text, (Texture)(object)whiteTexture); } } } internal static Texture2D GetWhiteTexture() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_whiteTex != (Object)null) { return _whiteTex; } _whiteTex = new Texture2D(1, 1, (TextureFormat)4, false) { filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1 }; _whiteTex.SetPixel(0, 0, Color.white); _whiteTex.Apply(); return _whiteTex; } internal static bool ApplyAdditiveToProperty(Material mat, string propName, Color tint) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) if (!mat.HasProperty(propName)) { return false; } Color color = mat.GetColor(propName); mat.SetColor(propName, AdditiveOffsetColor(color, tint)); return true; } internal static bool ApplyAdditiveFallback(Material mat, Color tint) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //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_003c: 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) try { Shader shader = mat.shader; int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if ((int)shader.GetPropertyType(i) == 0) { string propertyName = shader.GetPropertyName(i); Color color = mat.GetColor(propertyName); mat.SetColor(propertyName, AdditiveOffsetColor(color, tint)); return true; } } } catch { if (Plugin.IsDebug) { Plugin.LogDebug("[ApplyColorTint] Cannot tint shader: " + ((Object)mat.shader).name); } } return false; } private static Color AdditiveOffsetColor(Color baseColor, Color tint) { //IL_0001: 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_0023: 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_0045: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) return new Color(Mathf.Clamp(baseColor.r + (tint.r - 1f), 0f, 2f), Mathf.Clamp(baseColor.g + (tint.g - 1f), 0f, 2f), Mathf.Clamp(baseColor.b + (tint.b - 1f), 0f, 2f), baseColor.a); } private Material GetCurrentRaceBodyMaterial() { RaceData race = Plugin.Presets.GetRace(RaceIndex); if (race == null) { return null; } if ((Object)(object)_cachedBodySourceSMR == (Object)null || _cachedBodySourceRaceIndex != RaceIndex) { Transform val = ((Component)this).transform.RecursiveFindChild(race.BodyMesh); _cachedBodySourceSMR = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : null); _cachedBodySourceRaceIndex = RaceIndex; } SkinnedMeshRenderer cachedBodySourceSMR = _cachedBodySourceSMR; if ((Object)(object)cachedBodySourceSMR == (Object)null || ((Renderer)cachedBodySourceSMR).sharedMaterials == null) { return null; } if (race.MaterialSlot < 0 || race.MaterialSlot >= ((Renderer)cachedBodySourceSMR).sharedMaterials.Length) { return null; } Material val2 = ((Renderer)cachedBodySourceSMR).sharedMaterials[race.MaterialSlot]; if (MaterialSkinUtility.IsMaskOrInvalidBodyMaterial(val2)) { if ((Object)(object)_cachedOriginalBodyMaterial != (Object)null && !MaterialSkinUtility.IsMaskOrInvalidBodyMaterial(_cachedOriginalBodyMaterial)) { return _cachedOriginalBodyMaterial; } return null; } return val2; } private Material GetOriginalBodyMaterial() { if ((Object)(object)_cachedOriginalBodyMaterial != (Object)null) { return _cachedOriginalBodyMaterial; } _cachedOriginalBodyMaterial = GetCurrentRaceBodyMaterial(); return _cachedOriginalBodyMaterial; } private static string BuildRaceBodySourceKey(Material mat) { if ((Object)(object)mat == (Object)null) { return "mat:null"; } string text = (((Object)(object)mat.shader != (Object)null) ? ((Object)mat.shader).name : "shader:null"); string text2 = (((Object)(object)mat.mainTexture != (Object)null) ? ((Object)mat.mainTexture).GetInstanceID().ToString() : "tex:null"); return text + "|" + text2 + "|" + ((Object)mat).GetInstanceID(); } public void RefreshTransform() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)SizeBone == (Object)null) { return; } PresetData preset = Plugin.Presets.GetPreset(PresetIndex); if (preset != null) { SizeBone.transform.localScale = new Vector3(preset.Scale.x + ScaleOffset.x, preset.Scale.y + ScaleOffset.y, preset.Scale.z + ScaleOffset.z); Quaternion localRotation = Quaternion.Euler(BaseRotation.x + ErectAngleOffset, BaseRotation.y, BaseRotation.z); SizeBone.transform.localRotation = localRotation; Vector3 localPosition = default(Vector3); ((Vector3)(ref localPosition))..ctor(0f, PositionOffset.y, PositionOffset.x); SizeBone.transform.localPosition = localPosition; if ((Object)(object)BallBone != (Object)null) { BallBone.transform.localScale = Vector3.one + Vector3.one * BallsSizeOffset; } } } public void RequestSyncImmediate(bool forceSave = false, SyncField forceFields = SyncField.None) { SyncDirty = false; _lastSyncTime = Time.unscaledTime; if (Plugin.Network != null && _hasPlayerInParent) { Plugin.Network.SendSync(this, forceFields); } if (IsLocal) { if (forceSave) { ForceSaveSettings(); } else { AutoSaveSettings(); } } } internal unsafe void ForceSaveSettings() { //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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if (IsLocal && Plugin.UserPresets != null) { _lastAutoSaveTime = Time.unscaledTime; SaveCurrentPresetMemoryToDisk("ForceSaveSettings"); if (Plugin.IsDebug) { string[] obj = new string[18] { "[ProfileAutoSave] source=ForceSaveSettings controller=", ((Object)((Component)this).gameObject).name, " preset=", PresetIndex.ToString(), " color=", null, null, null, null, null, null, null, null, null, null, null, null, null }; Color colorTint = ColorTint; obj[5] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[6] = " colorMode="; obj[7] = ColorMode.ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; colorTint = BallColorTint; obj[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[12] = " ballColorMode="; obj[13] = BallColorMode.ToString(); obj[14] = " ballMatchBody="; obj[15] = BallMatchBody.ToString(); obj[16] = " frame="; obj[17] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } } private unsafe void SaveCurrentPresetMemoryToDisk(string reason) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) if (IsLocal && PresetIndex >= 0 && Plugin.UserPresets != null) { _presetMemory[PresetIndex] = CaptureSettings(); PersistCurrentProfileSettings(reason); if (Plugin.IsDebug) { string[] obj = new string[16] { "[PresetMemorySave] reason=", reason, " controller=", ((Object)((Component)this).gameObject).name, " preset=", PresetIndex.ToString(), " color=", null, null, null, null, null, null, null, null, null }; Color colorTint = ColorTint; obj[7] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; colorTint = BallColorTint; obj[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[12] = " ballMatchBody="; obj[13] = BallMatchBody.ToString(); obj[14] = " frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } } internal void SetPendingUserProfile(ProfileSaveData profile) { _pendingUserProfile = profile; } private void AutoSaveSettings() { if (Plugin.UserPresets != null && !(Time.unscaledTime - _lastAutoSaveTime < 1f)) { _lastAutoSaveTime = Time.unscaledTime; SaveCurrentPresetMemoryToDisk("AutoSaveSettings"); } } private void TryResyncMaterial(bool force = false) { if ((Object)(object)DickMesh == (Object)null) { return; } PresetData presetData = Plugin.Presets?.GetPreset(PresetIndex); if (presetData != null && presetData.AssetSource == PresetAssetSource.Test) { Material currentRaceBodyMaterial = GetCurrentRaceBodyMaterial(); if ((Object)(object)currentRaceBodyMaterial == (Object)null) { _testPresetMaterialReady = false; return; } Shader shader = currentRaceBodyMaterial.shader; Texture mainTexture = currentRaceBodyMaterial.mainTexture; string characterColorAdjustmentSignature = MaterialSkinUtility.GetCharacterColorAdjustmentSignature(currentRaceBodyMaterial); string text = BuildRaceBodySourceKey(currentRaceBodyMaterial); if (!force && (Object)(object)_lastRaceBodyShader == (Object)(object)shader && (Object)(object)_lastRaceBodyTexture == (Object)(object)mainTexture && _lastRaceBodyAdjustmentSignature == characterColorAdjustmentSignature && _lastRaceBodySourceKey == text && _materialResyncCount > 0 && _testPresetMaterialReady) { if (_materialResyncCount < 60) { _materialResyncCount = 60; } return; } bool flag = false; if (_templateDickMaterials != null && _templateDickMaterials.Length != 0) { ((Renderer)DickMesh).sharedMaterials = (Material[])_templateDickMaterials.Clone(); } if (BallMeshes != null) { for (int i = 0; i < BallMeshes.Length; i++) { SkinnedMeshRenderer val = BallMeshes[i]; if (!((Object)(object)val == (Object)null) && _templateMaterialsByRenderer.TryGetValue(val, out var value) && value != null) { ((Renderer)val).sharedMaterials = (Material[])value.Clone(); } } } flag |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(DickMesh, currentRaceBodyMaterial, "Dick", presetData.Id); if (BallMeshes != null) { for (int j = 0; j < BallMeshes.Length; j++) { if ((Object)(object)BallMeshes[j] != (Object)null) { flag |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(BallMeshes[j], currentRaceBodyMaterial, "Ball", presetData.Id); } } } ApplyTestPresetTextureFallbacks(presetData, currentRaceBodyMaterial); _lastRaceBodyShader = shader; _lastRaceBodyTexture = mainTexture; _lastRaceBodyAdjustmentSignature = characterColorAdjustmentSignature; _lastRaceBodySourceKey = text; _materialResyncCount++; _testPresetMaterialReady = true; _cachedOriginalBodyMaterial = currentRaceBodyMaterial; CacheOriginalShlongMaterialsFromCurrentNeutralState(); InvalidateColorMaterialCache(dick: true, balls: true); ApplyColorTint(); ApplyBallColorTint(); if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][LocalResyncApplied] controller=" + ((Object)((Component)this).gameObject).name + " preset=" + presetData.Id + " changed=" + flag + " hbc=" + characterColorAdjustmentSignature + " force=" + force + " frame=" + Time.frameCount); } } else { if (!force && _materialResyncCount >= 3) { return; } Material currentRaceBodyMaterial2 = GetCurrentRaceBodyMaterial(); if ((Object)(object)currentRaceBodyMaterial2 == (Object)null) { return; } bool flag2 = false; if (_templateDickMaterials != null && _templateDickMaterials.Length != 0) { ((Renderer)DickMesh).sharedMaterials = (Material[])_templateDickMaterials.Clone(); } flag2 |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(DickMesh, currentRaceBodyMaterial2, "Dick", (presetData != null) ? presetData.Id : "original"); if (BallMeshes != null) { for (int k = 0; k < BallMeshes.Length; k++) { SkinnedMeshRenderer val2 = BallMeshes[k]; if (!((Object)(object)val2 == (Object)null)) { if (_templateMaterialsByRenderer.TryGetValue(val2, out var value2) && value2 != null) { ((Renderer)val2).sharedMaterials = (Material[])value2.Clone(); } flag2 |= MaterialSkinUtility.ApplyRaceShadingToRendererMaterials(val2, currentRaceBodyMaterial2, "Ball", (presetData != null) ? presetData.Id : "original"); } } } if (flag2 || force) { _materialResyncCount++; _testPresetMaterialReady = true; _cachedOriginalBodyMaterial = currentRaceBodyMaterial2; _lastRaceBodyShader = null; _lastRaceBodyTexture = null; _lastRaceBodyAdjustmentSignature = null; _lastRaceBodySourceKey = null; CacheOriginalShlongMaterialsFromCurrentNeutralState(); InvalidateColorMaterialCache(dick: true, balls: true); ApplyColorTint(); ApplyBallColorTint(); } } } internal unsafe void ForceColorAdjustmentMaterialRefresh(string reason) { //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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) ResetMaterialResyncTracking(); InvalidateColorMaterialCache(dick: true, balls: true); TryResyncMaterial(force: true); PresetData presetData = Plugin.Presets?.GetPreset(PresetIndex); if (presetData == null || presetData.AssetSource != PresetAssetSource.Test || _testPresetMaterialReady) { ApplyColorTint(); ApplyBallColorTint(); CosmeticDisplayManager.ForceRefreshColorsFor(this, dick: true, balls: true); } if (Plugin.IsDebug) { string[] obj = new string[16] { "[ColorHBC][LocalRefresh] controller=", ((Object)((Component)this).gameObject).name, " reason=", reason, " preset=", PresetIndex.ToString(), " color=", null, null, null, null, null, null, null, null, null }; Color colorTint = ColorTint; obj[7] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; colorTint = BallColorTint; obj[11] = ((object)(*(Color*)(&colorTint))/*cast due to .constrained prefix*/).ToString(); obj[12] = " ballMatchBody="; obj[13] = BallMatchBody.ToString(); obj[14] = " frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } private void ResetMaterialResyncTracking() { _materialResyncCount = 0; _lastRaceBodyShader = null; _lastRaceBodyTexture = null; _lastRaceBodyAdjustmentSignature = null; _lastRaceBodySourceKey = null; _cachedOriginalBodyMaterial = null; _cachedDickMaterial = null; _cachedBallMaterial = null; PresetData presetData = Plugin.Presets?.GetPreset(PresetIndex); _testPresetMaterialReady = presetData == null || presetData.AssetSource != PresetAssetSource.Test; } private void OnEnable() { _cachedComponentsDone = false; if (Plugin.IsDebug) { Plugin.LogDebug("[OnEnable] " + ((Object)((Component)this).gameObject).name + " DickMesh=" + ((Object)(object)DickMesh != (Object)null) + " InstanceRoot=" + ((Object)(object)InstanceRoot != (Object)null) + " PelvisBone=" + ((Object)(object)PelvisBone != (Object)null) + " hip=" + ((Object)(object)_cachedHipBone != (Object)null) + " transition=" + TransitionCount + " frame=" + Time.frameCount); } } private void OnDisable() { if (Plugin.IsDebug) { Plugin.LogDebug("[OnDisable] " + ((Object)((Component)this).gameObject).name + " DickMesh=" + ((Object)(object)DickMesh != (Object)null) + " InstanceRoot=" + ((Object)(object)InstanceRoot != (Object)null) + " PelvisBone=" + ((Object)(object)PelvisBone != (Object)null) + " transition=" + TransitionCount + " frame=" + Time.frameCount); } if ((Object)(object)DickMesh != (Object)null) { ((Renderer)DickMesh).enabled = false; } } private void LateUpdate() { } private void OnDestroy() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 bool flag = (Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 0; if (flag) { LifecycleDiagnostics.OnLoadingOnDestroy(); } if (flag) { if ((Object)(object)InstanceRoot != (Object)null) { if ((Object)(object)DickMesh != (Object)null && (Object)(object)((Component)DickMesh).gameObject != (Object)null) { ModelAttacher.ActiveDickMeshObjects.Remove(((Component)DickMesh).gameObject); } Object.Destroy((Object)(object)InstanceRoot); } AllInstances.Remove(this); if (Plugin.Controllers == null) { return; } try { string text = _cachedSteamId; if (string.IsNullOrEmpty(text) && (Object)(object)PlayerObj != (Object)null) { text = PlayerObj.Network_steamID; } if (!string.IsNullOrEmpty(text) && Plugin.Controllers.ContainsKey(text) && (Object)(object)Plugin.Controllers[text] == (Object)(object)this) { Plugin.Controllers.Remove(text); LifecycleDiagnostics.OnUnregister(); } return; } catch { return; } } try { if (Plugin.IsDebug) { Plugin.LogDebug("[OnDestroy] " + ((Object)((Component)this).gameObject).name + " DickMesh=" + ((Object)(object)DickMesh != (Object)null) + " PelvisBone=" + ((Object)(object)PelvisBone != (Object)null) + " InstanceRoot=" + ((Object)(object)InstanceRoot != (Object)null) + " transition=" + TransitionCount + " loading=" + flag + " frame=" + Time.frameCount); } if ((Object)(object)DickMesh != (Object)null && (Object)(object)((Component)DickMesh).gameObject != (Object)null) { ModelAttacher.ActiveDickMeshObjects.Remove(((Component)DickMesh).gameObject); } _cachedHipBone = null; CosmeticDisplayManager.RemoveRig(this); if ((Object)(object)InstanceRoot != (Object)null) { Object.Destroy((Object)(object)InstanceRoot); } } catch { } AllInstances.Remove(this); if (Plugin.Controllers == null) { return; } try { string text2 = _cachedSteamId; if (string.IsNullOrEmpty(text2) && (Object)(object)PlayerObj != (Object)null) { text2 = PlayerObj.Network_steamID; } if (!string.IsNullOrEmpty(text2) && Plugin.Controllers.ContainsKey(text2) && (Object)(object)Plugin.Controllers[text2] == (Object)(object)this) { Plugin.Controllers.Remove(text2); LifecycleDiagnostics.OnUnregister(); } } catch { } } } public static class VisibilityResolver { public static bool ShouldShowDick(bool isLocalPlayer, bool isCharMenu, bool gameObjectActive, bool displayBoobs, bool futaToggle, bool clothingOverride, bool hideLeggingsVisual, bool noLeggingsEquipped, bool playerBodyVisible = true, bool hideToggle = false, bool playerForceHidden = false, int characterSelectPreviewMode = 0, bool hideOtherPlayers = false) { if (!gameObjectActive) { return false; } if (!playerBodyVisible) { return false; } if (playerForceHidden) { return false; } if (hideToggle) { return false; } if (displayBoobs && !futaToggle) { return false; } if (isCharMenu) { characterSelectPreviewMode = UserPresetManager.NormalizeCharacterSelectPreviewMode(characterSelectPreviewMode); return characterSelectPreviewMode switch { 1 => true, 2 => false, _ => PluginConfig.ShowShlongInCharacterSelect != null && PluginConfig.ShowShlongInCharacterSelect.Value, }; } if (!isLocalPlayer && hideOtherPlayers) { return false; } if (!clothingOverride && !hideLeggingsVisual && !noLeggingsEquipped) { return false; } return true; } public static bool ShouldHideForCamera(bool cameraUnhidePlayerModel) { return cameraUnhidePlayerModel; } } }