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.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.0.2.0")] [assembly: AssemblyInformationalVersion("3.0.2")] [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.0.2.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 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 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 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.0.2")] 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)(GameCondition)(ref Player._mainPlayer._currentGameCondition)).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 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."); 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, "When enabled, matched-body shlong materials copy character hue/brightness/contrast/saturation-style shader properties from the player's body material. Disable for more texture-original color variety."); 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; private static readonly CultureInfo Cult; private static bool[] _pendingColorSync; private static float[] _lastColorChangeTime; private const int TARGET_DICK = 0; private const int TARGET_BALL = 1; private static int _editTarget; private static readonly string[] TargetLabels; private static readonly string[] _hexInputs; private static readonly float[] _hues; private static readonly float[] _sats; private static readonly float[] _vals; private static Texture2D _previewTex; private static Texture2D _svTex; private static Texture2D _hueTex; private static float _svTexHue; private static int _svSize; 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 static void DrawColorUI(ShlongController sc) { //IL_00a7: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_0147: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: 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_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: 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_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: 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) 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); } if (flag2) { val = Color.white; } else { ((Color)(ref val))..ctor(Mathf.Clamp01(0.5f + (val.r - 1f)), Mathf.Clamp01(0.5f + (val.g - 1f)), Mathf.Clamp01(0.5f + (val.b - 1f))); } 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 }; int num2 = 9; Color val2 = sc.ColorTint; obj[num2] = ((object)(Color)(ref val2)).ToString(); obj[10] = " ballColor="; int num3 = 11; val2 = sc.BallColorTint; obj[num3] = ((object)(Color)(ref val2)).ToString(); obj[12] = " ballMatch="; obj[13] = sc.BallMatchBody.ToString(); obj[14] = " frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } _pendingColorSync[(!flag) ? 1 : 0] = false; sc.RequestSyncImmediate(forceSave: true, forceFields); } if (num < 0 || num >= TabLabels.Length) { num = 0; } int num4 = num; int num5 = GUILayout.Toolbar(num, TabLabels, Array.Empty()); if (num5 != num4) { val = ConvertColorForModeSwitch(val, num4, num5); num = num5; WriteTargetState(sc, flag, val, num, flag2); SyncHSVFromColor(val); SyncHexFromColor(val); ApplyTarget(sc, flag); SyncField forceFields2 = (flag ? SyncField.Color : SyncField.BallColor); _pendingColorSync[(!flag) ? 1 : 0] = false; sc.RequestSyncImmediate(forceSave: true, forceFields2); } 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); if (GUILayout.Button(flag ? "Reset Shlong / Shaft Color" : "Reset Balls & Sheath Color", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { sc.InvalidateColorMaterialCache(flag, !flag); WriteTargetState(sc, flag, Color.white, 0, matchBody: true); _hexInputs[_editTarget] = "#FFFFFF"; _hues[_editTarget] = 0f; _sats[_editTarget] = 0f; _vals[_editTarget] = 1f; ApplyTarget(sc, flag); CosmeticDisplayManager.ForceRefreshColorsFor(sc, flag, !flag); SyncField forceFields3 = (flag ? SyncField.Color : SyncField.BallColor); _pendingColorSync[(!flag) ? 1 : 0] = false; if (Plugin.IsDebug) { string[] obj2 = new string[8] { "[ColorReset] group=", flag ? "shaft" : "balls", " color=", null, null, null, null, null }; Color white = Color.white; obj2[3] = ((object)(Color)(ref white)).ToString(); obj2[4] = " mode="; obj2[5] = 0.ToString(); obj2[6] = " matchBody=true forceFields="; obj2[7] = forceFields3.ToString(); Plugin.LogDebug(string.Concat(obj2)); } sc.RequestSyncImmediate(forceSave: true, forceFields3); } 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 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_0058: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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 Color.white; } 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_0096: 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_00e6: 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_0061: 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) EnsurePreviewTexture(); Color targetColor = GetTargetColor(sc, isDick); bool flag = (isDick ? sc.MatchBody : sc.BallMatchBody); int num = (isDick ? sc.ColorMode : sc.BallColorMode); if (flag && num == 0) { ((Color)(ref targetColor))..ctor(Mathf.Clamp01(0.5f + (targetColor.r - 1f)), Mathf.Clamp01(0.5f + (targetColor.g - 1f)), Mathf.Clamp01(0.5f + (targetColor.b - 1f))); } _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(); } static ColorModeExtension() { TabLabels = new string[5] { "Tint", "RGB", "Hex", "Picker", "HSV" }; Cult = new CultureInfo("en-US"); _pendingColorSync = new bool[2]; _lastColorChangeTime = new float[2]; TargetLabels = new string[2] { "Shlong / Shaft", "Balls & Sheath" }; _hexInputs = new string[2] { "#FFFFFF", "#FFFFFF" }; _hues = new float[2]; _sats = new float[2] { 1f, 1f }; _vals = new float[2] { 1f, 1f }; _svTexHue = -1f; _svSize = 128; } } public class SettingsWindow { private enum ShortcutCapturePart { None, MainKey } private enum ShlongModelCategory { Original, Updated } [CompilerGenerated] private sealed class d__88 : IEnumerable>, IEnumerable, IEnumerator>, IEnumerator, IDisposable { private int <>1__state; private ConfigEntry <>2__current; private int <>l__initialThreadId; public SettingsWindow <>4__this; ConfigEntry IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__88(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = InputManager.GetPrevDick(); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = InputManager.GetNextDick(); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = InputManager.GetToggleHide(); <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = InputManager.GetToggleFuta(); <>1__state = 4; return true; case 4: <>1__state = -1; <>2__current = InputManager.GetToggleClothing(); <>1__state = 5; return true; case 5: <>1__state = -1; <>2__current = InputManager.GetCycleArousal(); <>1__state = 6; return true; case 6: <>1__state = -1; <>2__current = InputManager.GetToggleArousal(); <>1__state = 7; return true; case 7: <>1__state = -1; <>2__current = InputManager.GetIncreaseDick(); <>1__state = 8; return true; case 8: <>1__state = -1; <>2__current = InputManager.GetDecreaseDick(); <>1__state = 9; return true; case 9: <>1__state = -1; <>2__current = InputManager.GetIncreaseBalls(); <>1__state = 10; return true; case 10: <>1__state = -1; <>2__current = InputManager.GetDecreaseBalls(); <>1__state = 11; return true; case 11: <>1__state = -1; <>2__current = InputManager.GetManualSync(); <>1__state = 12; return true; case 12: <>1__state = -1; <>2__current = InputManager.GetAdjustOffset(); <>1__state = 13; return true; case 13: <>1__state = -1; <>2__current = InputManager.GetToggleGui(); <>1__state = 14; return true; case 14: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__88 result; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__88(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__79 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ShlongController sc; public int presetIndex; public string expectedId; private int 5__1; private PresetData 5__2; private string 5__3; private string 5__4; private StringBuilder 5__5; private bool 5__6; private bool 5__7; private SkinnedMeshRenderer[] 5__8; private int 5__9; private SkinnedMeshRenderer 5__10; private Exception 5__11; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__79(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; 5__3 = null; 5__4 = null; 5__5 = null; 5__8 = null; 5__10 = null; 5__11 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = 0; break; case 1: <>1__state = -1; 5__1++; break; } if (5__1 < 30) { if ((Object)(object)sc == (Object)null) { return false; } if (sc.PresetIndex != presetIndex || !((Object)(object)sc.InstanceRoot != (Object)null)) { <>2__current = null; <>1__state = 1; return true; } } if ((Object)(object)sc == (Object)null) { return false; } try { 5__2 = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(presetIndex) : null); 5__3 = ((5__2 != null) ? 5__2.MeshName : ""); 5__4 = (((Object)(object)sc.InstanceRoot != (Object)null) ? ((Object)sc.InstanceRoot).name : ""); 5__5 = new StringBuilder(); 5__5.Append("[BulgeTest] Spawn result:"); 5__5.Append(" expectedId=").Append(expectedId); 5__5.Append(" presetIndex=").Append(sc.PresetIndex); 5__5.Append(" controller=").Append(((Object)((Component)sc).gameObject).name); 5__6 = ((Object)((Component)sc).gameObject).name.Contains("(Clone)") && !((Object)((Component)sc).gameObject).name.Contains("equipDisplay"); 5__7 = PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value; 5__5.Append(" clone=").Append(5__6); 5__5.Append(" cloneSpawnBlock=").Append(5__7); 5__5.Append(" instanceRoot=").Append(5__4); 5__5.Append(" expectedMesh=").Append(5__3); 5__5.Append(" dickMesh="); if ((Object)(object)sc.DickMesh != (Object)null) { 5__5.Append(((Object)sc.DickMesh).name); 5__5.Append(" sharedMesh="); 5__5.Append(((Object)(object)sc.DickMesh.sharedMesh != (Object)null) ? ((Object)sc.DickMesh.sharedMesh).name : ""); } else { 5__5.Append(""); } if ((Object)(object)sc.InstanceRoot != (Object)null) { 5__8 = sc.InstanceRoot.GetComponentsInChildren(true); 5__5.Append(" renderers=").Append(5__8.Length); 5__9 = 0; while (5__9 < 5__8.Length) { 5__10 = 5__8[5__9]; 5__5.Append(" ["); 5__5.Append(5__9); 5__5.Append("] name="); 5__5.Append(((Object)(object)5__10 != (Object)null) ? ((Object)5__10).name : ""); 5__5.Append(" mesh="); 5__5.Append(((Object)(object)5__10 != (Object)null && (Object)(object)5__10.sharedMesh != (Object)null) ? ((Object)5__10.sharedMesh).name : ""); 5__10 = null; 5__9++; } 5__8 = null; } Plugin.LogDebug(5__5.ToString()); 5__2 = null; 5__3 = null; 5__4 = null; 5__5 = null; } catch (Exception ex) { 5__11 = ex; Plugin.LogWarningLimited("bulge.spawn_result", "[BulgeTest] LogBulgeTestSpawnResult: " + 5__11.Message); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly string[] ModifierOptionLabels; private static readonly KeyCode[] ModifierOptionKeys; public static bool IsHovered; internal static Action OnDrawColorUI; 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 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 _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; 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"); _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 Bulge Test Lab 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_019b: 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 (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 DrawModelPresetSection(ShlongController sc) { DrawModelCategoryTabsOnly(); if ((Object)(object)sc == (Object)null) { GUILayout.Label("No active ShlongController found.", Array.Empty()); } else { DrawModelPresetGrid(sc); } } private void DrawModelCategoryTabsOnly() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0088: 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_00d1: Unknown result type (might be due to invalid IL or missing references) 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) })) { _selectedModelCategory = 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) })) { _selectedModelCategory = 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_028a: 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_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: 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 presetIndex = sc.PresetIndex; 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 num3 = string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase); return (num3 != 0) ? num3 : 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 j = 0; j < list.Count; j += 4) { GUILayout.BeginHorizontal(Array.Empty()); for (int k = 0; k < 4; k++) { int num = j + k; if (num >= list.Count) { GUILayout.Label("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(24f) }); continue; } int num2 = list[num]; PresetData presetData2 = all[num2]; bool flag3 = num2 == presetIndex; 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(num2); } } 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.0.2", (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_0741: Unknown result type (might be due to invalid IL or missing references) //IL_0746: Unknown result type (might be due to invalid IL or missing references) //IL_076f: Unknown result type (might be due to invalid IL or missing references) //IL_0774: Unknown result type (might be due to invalid IL or missing references) //IL_0785: Unknown result type (might be due to invalid IL or missing references) //IL_078a: 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("Angle X: " + rot.x.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(defRotW.x, rot.y, rot.z); sc.RefreshTransform(); sc.RequestSyncImmediate(); }); float num8 = GUILayout.HorizontalSlider(rot.x, 0f, 360f, Array.Empty()); GUILayout.Space(6f); DrawResetRow("Angle Y: " + 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 num9 = GUILayout.HorizontalSlider(rot.y, 0f, 360f, Array.Empty()); GUILayout.Space(6f); DrawResetRow("Angle Z: " + 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 num10 = 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.x) > 0.01f || Mathf.Abs(num9 - rot.y) > 0.01f || Mathf.Abs(num10 - 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(num8, num9, num10); 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) { return; } bool value = PluginConfig.ApplyCharacterHbcToMatchedShlongs.Value; bool flag = GUILayout.Toggle(value, " Apply Character Hue/Brightness/Contrast", Array.Empty()); if (flag != value) { PluginConfig.ApplyCharacterHbcToMatchedShlongs.Value = flag; if ((Object)(object)sc != (Object)null) { sc.ForceColorAdjustmentMaterialRefresh("ApplyCharacterHBC=" + flag); } CosmeticDisplayManager.RecreateAllDisplayRigsForConfigChange("ApplyCharacterHBC=" + flag); if (Plugin.IsDebug) { Plugin.LogDebug("[ColorHBC] ApplyCharacterHBC=" + flag + " frame=" + Time.frameCount); } } } private void DrawColorSliders(ShlongController sc) { //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: 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_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_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04d0: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Unknown result type (might be due to invalid IL or missing references) //IL_0554: 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); 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(); Color white; 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.ApplyColorTint(); CosmeticDisplayManager.ForceRefreshColorsFor(sc, dick: true, balls: false); if (Plugin.IsDebug) { white = Color.white; Plugin.LogDebug("[ColorReset] group=shaft color=" + ((object)(Color)(ref white)).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; } 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.ApplyBallColorTint(); CosmeticDisplayManager.ForceRefreshColorsFor(sc, dick: false, balls: true); if (Plugin.IsDebug) { white = Color.white; Plugin.LogDebug("[ColorReset] group=balls color=" + ((object)(Color)(ref white)).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_0440: Unknown result type (might be due to invalid IL or missing references) //IL_0445: 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_0481: 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); } 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) { PresetData preset = Plugin.Presets.GetPreset(sc.PresetIndex); 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(); }); 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); 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 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(); 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("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_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_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_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_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_00b4: 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) sc.FutaToggle = data.FutaToggle; 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; sc.ArousalLerpSpeed = data.ArousalLerpSpeed; sc.BallColorTint = new Color(data.BallColorR, data.BallColorG, data.BallColorB); sc.BallColorMode = data.BallColorMode; sc.BallMatchBody = data.BallMatchBody; sc.ApplyColorTint(); sc.ApplyBallColorTint(); sc.RefreshTransform(); sc.RequestSyncImmediate(forceSave: true, SyncField.Position | SyncField.Scale | SyncField.BallsSize | SyncField.Futa | SyncField.Rotation | SyncField.ErectAngle | SyncField.Color | SyncField.BallColor | SyncField.Hide); } private void DrawDebugControls(ShlongController sc) { //IL_0305: 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_035d: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_048e: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_0504: Unknown result type (might be due to invalid IL or missing references) //IL_0509: Unknown result type (might be due to invalid IL or missing references) //IL_04da: Unknown result type (might be due to invalid IL or missing references) //IL_04df: Unknown result type (might be due to invalid IL or missing references) //IL_05c9: Unknown result type (might be due to invalid IL or missing references) //IL_05ce: Unknown result type (might be due to invalid IL or missing references) //IL_05e3: Unknown result type (might be due to invalid IL or missing references) //IL_05e8: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Unknown result type (might be due to invalid IL or missing references) //IL_0611: Unknown result type (might be due to invalid IL or missing references) //IL_0652: Unknown result type (might be due to invalid IL or missing references) //IL_0657: 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_0680: Unknown result type (might be due to invalid IL or missing references) //IL_06c1: Unknown result type (might be due to invalid IL or missing references) //IL_06c6: Unknown result type (might be due to invalid IL or missing references) //IL_06ea: Unknown result type (might be due to invalid IL or missing references) //IL_06ef: 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_0846: 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("--- 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 }; int num5 = 1; val2 = ((Bounds)(ref bounds)).min; obj[num5] = val2.x.ToString("F4"); obj[2] = ", "; int num6 = 3; val2 = ((Bounds)(ref bounds)).max; obj[num6] = val2.x.ToString("F4"); obj[4] = "]"; GUILayout.Label(string.Concat(obj), Array.Empty()); string[] obj2 = new string[5] { "Bounds Y:[", null, null, null, null }; int num7 = 1; val2 = ((Bounds)(ref bounds)).min; obj2[num7] = val2.y.ToString("F4"); obj2[2] = ", "; int num8 = 3; val2 = ((Bounds)(ref bounds)).max; obj2[num8] = val2.y.ToString("F4"); obj2[4] = "]"; GUILayout.Label(string.Concat(obj2), Array.Empty()); string[] obj3 = new string[5] { "Bounds Z:[", null, null, null, null }; int num9 = 1; val2 = ((Bounds)(ref bounds)).min; obj3[num9] = val2.z.ToString("F4"); obj3[2] = ", "; int num10 = 3; val2 = ((Bounds)(ref bounds)).max; obj3[num10] = 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"); string text2 = " Color="; Color colorTint = sc.ColorTint; GUILayout.Label("Scale=" + text + text2 + ((object)(Color)(ref colorTint)).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; 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.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 }; int num11 = 1; ConfigEntry enableRemoteJiggleExperimental = PluginConfig.EnableRemoteJiggleExperimental; obj4[num11] = ((enableRemoteJiggleExperimental != null && enableRemoteJiggleExperimental.Value) ? "true" : "false"); obj4[2] = " Debug Pulse: "; int num12 = 3; ConfigEntry remoteJiggleDebugPulse = PluginConfig.RemoteJiggleDebugPulse; obj4[num12] = ((remoteJiggleDebugPulse != null && remoteJiggleDebugPulse.Value) ? "true" : "false"); obj4[4] = " Pulse Root: "; int num13 = 5; ConfigEntry remoteJiggleDebugPulseRoot = PluginConfig.RemoteJiggleDebugPulseRoot; obj4[num13] = ((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 num14 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleStrength.Value, 0f, 6f, Array.Empty()); if (Mathf.Abs(num14 - PluginConfig.RemoteJiggleStrength.Value) > 0.001f) { PluginConfig.RemoteJiggleStrength.Value = num14; } } if (PluginConfig.RemoteJiggleStiffness != null) { GUILayout.Label("Stiffness: " + PluginConfig.RemoteJiggleStiffness.Value.ToString("F1") + " [0.1..40]", Array.Empty()); float num15 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleStiffness.Value, 0.1f, 40f, Array.Empty()); if (Mathf.Abs(num15 - PluginConfig.RemoteJiggleStiffness.Value) > 0.05f) { PluginConfig.RemoteJiggleStiffness.Value = num15; } } if (PluginConfig.RemoteJiggleDamping != null) { GUILayout.Label("Damping: " + PluginConfig.RemoteJiggleDamping.Value.ToString("F2") + " [0..1]", Array.Empty()); float num16 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleDamping.Value, 0f, 1f, Array.Empty()); if (Mathf.Abs(num16 - PluginConfig.RemoteJiggleDamping.Value) > 0.001f) { PluginConfig.RemoteJiggleDamping.Value = num16; } } if (PluginConfig.RemoteJiggleMaxDegrees != null) { GUILayout.Label("Max Degrees: " + PluginConfig.RemoteJiggleMaxDegrees.Value.ToString("F1") + " [0..45]", Array.Empty()); float num17 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleMaxDegrees.Value, 0f, 45f, Array.Empty()); if (Mathf.Abs(num17 - PluginConfig.RemoteJiggleMaxDegrees.Value) > 0.05f) { PluginConfig.RemoteJiggleMaxDegrees.Value = num17; } } if (PluginConfig.RemoteJiggleVelocityToDegrees != null) { GUILayout.Label("Vel→Deg: " + PluginConfig.RemoteJiggleVelocityToDegrees.Value.ToString("F2") + " [0..8]", Array.Empty()); float num18 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleVelocityToDegrees.Value, 0f, 8f, Array.Empty()); if (Mathf.Abs(num18 - PluginConfig.RemoteJiggleVelocityToDegrees.Value) > 0.01f) { PluginConfig.RemoteJiggleVelocityToDegrees.Value = num18; } } if (PluginConfig.RemoteJiggleAngularToDegrees != null) { GUILayout.Label("Angular→Deg: " + PluginConfig.RemoteJiggleAngularToDegrees.Value.ToString("F2") + " [0..4]", Array.Empty()); float num19 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleAngularToDegrees.Value, 0f, 4f, Array.Empty()); if (Mathf.Abs(num19 - PluginConfig.RemoteJiggleAngularToDegrees.Value) > 0.005f) { PluginConfig.RemoteJiggleAngularToDegrees.Value = num19; } } if (PluginConfig.RemoteJiggleMinimumKick != null) { GUILayout.Label("Min Kick: " + PluginConfig.RemoteJiggleMinimumKick.Value.ToString("F2") + " [0..3]", Array.Empty()); float num20 = GUILayout.HorizontalSlider(PluginConfig.RemoteJiggleMinimumKick.Value, 0f, 3f, Array.Empty()); if (Mathf.Abs(num20 - PluginConfig.RemoteJiggleMinimumKick.Value) > 0.005f) { PluginConfig.RemoteJiggleMinimumKick.Value = num20; } } } GUILayout.Space(4f); if (DrawSection("Model Diagnostics (Bulge Test Lab)", _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 sc = ResolveBulgeTestController(scIn, out retargeted); if ((Object)(object)scIn != (Object)null && retargeted && (Object)(object)sc != (Object)null && sc != scIn) { GUILayout.Label("Bulge Test Lab targeting local player controller: " + ((Object)((Component)sc).gameObject).name, Array.Empty()); } if (GUILayout.Button("Log Controllers (BulgeTest 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)sc != (Object)null) { PresetData presetData = ((Plugin.Presets != null) ? Plugin.Presets.GetPreset(sc.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)sc).gameObject).name.Contains("(Clone)") && !((Object)((Component)sc).gameObject).name.Contains("equipDisplay"); bool flag4 = PluginConfig.BlockCloneRuntimeSpawnForDiagnostics != null && PluginConfig.BlockCloneRuntimeSpawnForDiagnostics.Value; GUILayout.Label("Controller: " + ((Object)((Component)sc).gameObject).name + " clone=" + flag3 + " cloneSpawnBlock=" + flag4, Array.Empty()); if ((Object)(object)sc.DickMesh == (Object)null) { GUILayout.Label("No active mesh bound. Cannot inspect BlendShapes.", Array.Empty()); } else { sc.BlendShapes.EnsureCached(sc.DickMesh); if (sc.BlendShapes.BulgeKeysFound == 0) { GUILayout.Label("Active mesh has no Bulge_* BlendShapes.", Array.Empty()); } else { GUILayout.Label("BlendShapes: Aroused=" + ((!sc.BlendShapes.HasAroused) ? "no" : (sc.BlendShapes.ArousedIsLegacyFallback ? "fallback(0)" : "yes")) + ", Bulge keys " + sc.BlendShapes.BulgeKeysFound + "/" + sc.BlendShapes.BulgeKeyTotal, Array.Empty()); } } } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); GUI.enabled = (Object)(object)sc != (Object)null && num >= 0 && flag; if (GUILayout.Button("Switch to Equine Bulge Test", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { LogBulgeTestSwitchRequest(sc, num, "equine_bulge_test"); sc.QueueInteractivePresetChange(num); } GUI.enabled = (Object)(object)sc != (Object)null && num2 >= 0; if (GUILayout.Button("Return to Equine", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) })) { LogBulgeTestSwitchRequest(sc, num2, "equine"); sc.QueueInteractivePresetChange(num2); } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.Space(6f); if ((Object)(object)sc == (Object)null) { GUILayout.Label("No active controller.", Array.Empty()); return; } bool flag5 = (Object)(object)sc.DickMesh != (Object)null && sc.BlendShapes.HasAnyBulge; if (!flag5) { GUILayout.Label("Active mesh has no Bulge_* BlendShapes.", Array.Empty()); } GUI.enabled = flag5; DrawResetRow("Bulge Amount: " + sc.BulgeAmount.ToString("0.0", Cult), delegate { sc.BulgeAmount = 0f; sc.RequestSyncImmediate(forceSave: false, SyncField.Bulge); }); float num3 = 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: false, SyncField.Bulge); }); float num4 = 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: false, SyncField.Bulge); }); float num5 = 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: false, SyncField.Bulge); }); float num6 = GUILayout.HorizontalSlider(sc.BulgeSharpness, 0.25f, 4f, Array.Empty()); GUILayout.Space(4f); bool flag6 = flag5 && !_cursorStateChanged && (Mathf.Abs(num3 - sc.BulgeAmount) > 0.001f || Mathf.Abs(num4 - sc.BulgePosition) > 0.001f || Mathf.Abs(num5 - sc.BulgeWidth) > 0.001f || Mathf.Abs(num6 - sc.BulgeSharpness) > 0.001f); bool flag7 = GUIUtility.hotControl != 0; if (flag6) { sc.BulgeAmount = num3; sc.BulgePosition = num4; sc.BulgeWidth = num5; sc.BulgeSharpness = num6; } else if (_bulgeSliderWasActive && !flag7) { sc.RequestSyncImmediate(forceSave: false, SyncField.Bulge); } _bulgeSliderWasActive = flag7; GUI.enabled = true; 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.RequestSyncImmediate(forceSave: false, SyncField.Bulge); } } 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); } } [IteratorStateMachine(typeof(d__79))] private static IEnumerator LogBulgeTestSpawnResult(ShlongController sc, int presetIndex, string expectedId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__79(0) { sc = sc, presetIndex = presetIndex, expectedId = expectedId }; } 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 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; } [IteratorStateMachine(typeof(d__88))] private IEnumerable> GetShortcutEntries() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__88(-2) { <>4__this = this }; } 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); KeyCode val2; if ((int)val == 306) { val2 = (KeyCode)306; if (!list.Contains(((object)(KeyCode)(ref val2)).ToString())) { val2 = (KeyCode)306; list.Add(((object)(KeyCode)(ref val2)).ToString()); continue; } } if ((int)val == 308) { val2 = (KeyCode)308; if (!list.Contains(((object)(KeyCode)(ref val2)).ToString())) { val2 = (KeyCode)308; list.Add(((object)(KeyCode)(ref val2)).ToString()); continue; } } if ((int)val == 304) { val2 = (KeyCode)304; if (!list.Contains(((object)(KeyCode)(ref val2)).ToString())) { val2 = (KeyCode)304; list.Add(((object)(KeyCode)(ref val2)).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 ShlongController GetActiveController() { ShlongController shlongController = ShlongController.ResolveLocalAuthoritative(); if ((Object)(object)shlongController != (Object)null) { _cachedController = shlongController; return shlongController; } if ((Object)(object)_cachedController != (Object)null && _cachedController.IsLocal && _cachedController.HasPlayerParent) { 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) { _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"); } } } 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 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)(ref mode)).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 { [HarmonyPostfix] public static void ShlongSaving(ProfileDataManager __instance) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_011e: 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_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) try { ShlongController shlongController = null; if ((Object)(object)Player._mainPlayer == (Object)null) { if ((Object)(object)MainMenuManager._current == (Object)null || (int)MainMenuManager._current._mainMenuCondition != 2) { return; } shlongController = Object.FindObjectOfType(false); } else { if (Player._mainPlayer._bufferingStatus) { return; } shlongController = ShlongController.ResolveLocalAuthoritative(); if ((Object)(object)shlongController == (Object)null) { Plugin.LogDebug("[ProfileSave] skipped: no local authoritative controller"); return; } } if (!((Object)(object)shlongController == (Object)null)) { if (shlongController.PresetIndex < 0) { Plugin.LogDebug("[ProfileSave] skipped: invalid preset"); return; } ProfileSaveData profileSaveData = new ProfileSaveData { DickNumber = shlongController.PresetIndex, DickOffsetX = shlongController.PositionOffset.x, DickOffsetY = shlongController.PositionOffset.y, BallsSizeOffset = shlongController.BallsSizeOffset, FutaToggle = shlongController.FutaToggle, HideToggle = shlongController.HideToggle, SizeOffset = shlongController.ScaleOffset.z, AngleOffset = shlongController.BaseRotation, ErectAngle = shlongController.ErectAngleOffset, ScaleOffset = shlongController.ScaleOffset, ColorR = shlongController.ColorTint.r, ColorG = shlongController.ColorTint.g, ColorB = shlongController.ColorTint.b, ColorMode = shlongController.ColorMode, MatchBody = shlongController.MatchBody, ArousalLerpSpeed = shlongController.ArousalLerpSpeed, BallColorR = shlongController.BallColorTint.r, BallColorG = shlongController.BallColorTint.g, BallColorB = shlongController.BallColorTint.b, BallColorMode = shlongController.BallColorMode, BallMatchBody = shlongController.BallMatchBody }; File.WriteAllText(GetProfileSavePath(__instance), JsonUtility.ToJson((object)profileSaveData, true)); } } catch (Exception ex) { Plugin.LogWarningLimited("profile.save", "Failed to save shlong profile: " + ex.Message); } } private static string GetProfileSavePath(ProfileDataManager pdm) { FieldInfo fieldInfo = AccessTools.Field(((object)pdm).GetType(), "_dataPath") ?? AccessTools.Field(((object)pdm).GetType(), "dataPath"); PropertyInfo propertyInfo = AccessTools.Property(((object)pdm).GetType(), "DataPath"); string path = (fieldInfo?.GetValue(pdm) as string) ?? (propertyInfo?.GetValue(pdm, null) as string) ?? Application.persistentDataPath; FieldInfo fieldInfo2 = AccessTools.Field(((object)pdm).GetType(), "_selectedFileIndex") ?? AccessTools.Field(((object)pdm).GetType(), "selectedFileIndex"); PropertyInfo propertyInfo2 = AccessTools.Property(((object)pdm).GetType(), "SelectedFileIndex"); object obj = fieldInfo2?.GetValue(pdm) ?? propertyInfo2?.GetValue(pdm, null); int num = ((obj is int) ? ((int)obj) : 0); return Path.Combine(path, $"atl_characterProfile_{num}_dick"); } } public static class RaceModelPatch { 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Invalid comparison between Unknown and I4 if ((Object)(object)((Component)self).GetComponent() != (Object)null) { return; } int num = Defaults.DetectRace(((Object)self).name); if (num == -1) { return; } bool flag = ((Object)self).name.Contains("equipDisplay"); bool flag2 = ((Object)self).name.Contains("(Clone)"); if (!flag && !flag2) { if (Plugin.IsDebug) { Plugin.LogDebug("Skipping template model: " + ((Object)self).name); } return; } if (!flag && (Object)(object)Player._mainPlayer != (Object)null && (int)Player._mainPlayer._currentGameCondition == 0) { LoadingAttachBuffered++; LifecycleDiagnostics.OnLoadingAttachBuffered(); if (!_pendingAttachments.Contains(self)) { _pendingAttachments.Add(self); } return; } LifecycleDiagnostics.OnAttach(flag, flag2); if (Plugin.IsDebug) { Plugin.LogDebug("AttachToRaceModel: race=" + num + " name=" + ((Object)self).name + " transition=" + ShlongController.TransitionCount + " frame=" + Time.frameCount + " stage=" + (flag ? "immediate" : "deferred")); } ShlongController shlongController = ((Component)self).gameObject.AddComponent(); shlongController.RaceIndex = num; if (flag) { shlongController.InitializeOwnershipFromHierarchy(); shlongController.Spawn(num); if ((Object)(object)shlongController.SizeBone != (Object)null) { if (Plugin.IsDebug) { Plugin.LogDebug("Spawned on " + ((Object)self).name); } } 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; } 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; } } } internal static class TransitionWatchdog { private static Timer _timer; private static volatile int _mainThreadFrame; private static int _lastCheckedFrame; private static int _stallCount; 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, 10000, 5000); } internal 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)(GameCondition)(ref _lastLocalCondition)).ToString() + " -> " + ((object)(GameCondition)(ref currentGameCondition)).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 val = shlongController.ColorTint; obj[5] = ((object)(Color)(ref val)).ToString(); obj[6] = " ballColor="; val = shlongController.BallColorTint; obj[7] = ((object)(Color)(ref val)).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)(GameCondition)(ref _lastLocalCondition)).ToString() + " -> " + ((object)(GameCondition)(ref currentGameCondition)).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)(GameCondition)(ref _lastLocalCondition)).ToString() + " -> " + ((object)(GameCondition)(ref currentGameCondition)).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.LogErrorLimited("watchdog.main_thread_blocked", "[WATCHDOG] Main thread BLOCKED! frame=" + mainThreadFrame + " stalledFor=" + _stallCount * 5 + "s"); } else { if (_stallCount > 0 && Plugin.IsDebug) { Plugin.LogDebug("[WATCHDOG] Main thread recovered after " + _stallCount * 5 + "s stall at frame=" + _lastCheckedFrame); } _stallCount = 0; } _lastCheckedFrame = mainThreadFrame; if (_isInLoading && _loadingEntryTicks > 0) { double num = (double)(DateTime.UtcNow.Ticks - _loadingEntryTicks) / 10000000.0; if (num > 10.0 && _loadingReportCount < 2) { _loadingReportCount++; Plugin.LogErrorLimited("watchdog.stuck_loading", "[WATCHDOG] STUCK IN LOADING! duration=" + num.ToString("F1") + "s frame=" + mainThreadFrame + " report=" + _loadingReportCount + "/2"); } } } } } 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, 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, 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 }; 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, 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, 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 }; SyncField syncField = ComputeDelta(shlongSyncPacket, _lastSent); syncField |= forceFields; if (syncField != 0) { 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) != 0 || (syncField & SyncField.BallColor) != 0)) { 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) { 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) { 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) { 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 bool ApplyPacket(string senderId, ShlongSyncPacket packet) { //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_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: 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_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Unknown result type (might be due to invalid IL or missing references) //IL_0549: Unknown result type (might be due to invalid IL or missing references) //IL_0870: Unknown result type (might be due to invalid IL or missing references) //IL_0875: Unknown result type (might be due to invalid IL or missing references) //IL_0b74: Unknown result type (might be due to invalid IL or missing references) //IL_0b79: Unknown result type (might be due to invalid IL or missing references) //IL_0d26: Unknown result type (might be due to invalid IL or missing references) //IL_0d2b: 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) != 0 && 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) != 0) { value.PositionOffset = new Vector2(packet.DickOffsetX, packet.DickOffsetY); flag = true; } if ((syncField & SyncField.BallsSize) != 0) { value.BallsSizeOffset = packet.BallsSizeOffset; flag = true; } if ((syncField & SyncField.Arousal) != 0) { value.ArousalTarget = packet.ArousalTarget; } if ((syncField & SyncField.Futa) != 0) { value.FutaToggle = packet.FutaToggle; } if ((syncField & SyncField.Clothing) != 0) { value.ClothingOverride = packet.ClothingOverride; } if ((syncField & SyncField.Rotation) != 0) { value.BaseRotation = new Vector3(packet.BaseRotationX, packet.BaseRotationY, packet.BaseRotationZ); flag = true; } if ((syncField & SyncField.ErectAngle) != 0) { value.ErectAngleOffset = packet.ErectAngleOffset; flag = true; } Vector3 val; if ((syncField & SyncField.Scale) != 0) { 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 }; val = scaleOffset; obj[17] = ((object)(Vector3)(ref val)).ToString(); obj[18] = " newScale="; val = value.ScaleOffset; obj[19] = ((object)(Vector3)(ref val)).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) != 0) { 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.InvalidateColorMaterialCache(dick: true, balls: false); value.ApplyColorTint(); flag3 = true; } if ((syncField & SyncField.BallColor) != 0) { 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.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) != 0) { value.HideToggle = packet.HideToggle; } if (packet.ChangedFields != 0 && (syncField & SyncField.Bulge) != 0) { 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); } 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 }; val = value.ScaleOffset; obj2[7] = ((object)(Vector3)(ref val)).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) != 0 && (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) != 0) { existing.DickOffsetX = incoming.DickOffsetX; existing.DickOffsetY = incoming.DickOffsetY; } if ((syncField & SyncField.Scale) != 0) { existing.ScaleX = incoming.ScaleX; existing.ScaleY = incoming.ScaleY; existing.ScaleZ = incoming.ScaleZ; existing.DickSizeOffset = incoming.DickSizeOffset; } if ((syncField & SyncField.BallsSize) != 0) { existing.BallsSizeOffset = incoming.BallsSizeOffset; } if ((syncField & SyncField.Preset) != 0) { existing.CurrentDick = incoming.CurrentDick; } if ((syncField & SyncField.Arousal) != 0) { existing.ArousalTarget = incoming.ArousalTarget; } if ((syncField & SyncField.Futa) != 0) { existing.FutaToggle = incoming.FutaToggle; } if ((syncField & SyncField.Clothing) != 0) { existing.ClothingOverride = incoming.ClothingOverride; } if ((syncField & SyncField.Rotation) != 0) { existing.BaseRotationX = incoming.BaseRotationX; existing.BaseRotationY = incoming.BaseRotationY; existing.BaseRotationZ = incoming.BaseRotationZ; } if ((syncField & SyncField.ErectAngle) != 0) { existing.ErectAngleOffset = incoming.ErectAngleOffset; } if ((syncField & SyncField.Color) != 0) { existing.ColorR = incoming.ColorR; existing.ColorG = incoming.ColorG; existing.ColorB = incoming.ColorB; existing.ColorMode = incoming.ColorMode; existing.MatchBody = incoming.MatchBody; existing.MatchBodyWire = incoming.MatchBodyWire; existing.ColorRWire = incoming.ColorRWire; existing.ColorGWire = incoming.ColorGWire; existing.ColorBWire = incoming.ColorBWire; } if ((syncField & SyncField.BallColor) != 0) { existing.BallColorR = incoming.BallColorR; existing.BallColorG = incoming.BallColorG; existing.BallColorB = incoming.BallColorB; existing.BallColorMode = incoming.BallColorMode; existing.BallMatchBody = incoming.BallMatchBody; existing.BallMatchBodyWire = incoming.BallMatchBodyWire; existing.BallColorRWire = incoming.BallColorRWire; existing.BallColorGWire = incoming.BallColorGWire; existing.BallColorBWire = incoming.BallColorBWire; } if ((syncField & SyncField.Hide) != 0) { existing.HideToggle = incoming.HideToggle; } if ((syncField & SyncField.Bulge) != 0) { existing.BulgeAmount = incoming.BulgeAmount; existing.BulgePosition = incoming.BulgePosition; existing.BulgeWidth = incoming.BulgeWidth; existing.BulgeSharpness = incoming.BulgeSharpness; } 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, 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, 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 }; } } } 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 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_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0294: 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_029d: Invalid comparison between Unknown and I4 //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: 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_0309: Invalid comparison between Unknown and I4 //IL_0327: 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 mouse."); _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)."); 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 bool ProcessKeyboardInput(ShlongController sc) { //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_0357: 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) //IL_038d: 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_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: 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_03bd: 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_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_03db: Unknown result type (might be due to invalid IL or missing references) //IL_03de: 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_040a: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_046d: 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_0478: Unknown result type (might be due to invalid IL or missing references) //IL_047d: 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 (IsShortcutDown(_toggleClothing)) { sc.ClothingOverride = !sc.ClothingOverride; sc.RequestSyncImmediate(); } 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.BaseRotation.x = Mathf.Repeat(sc.BaseRotation.x + Input.mouseScrollDelta.y * 1.5f, 360f); 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 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) { KeyCode current = modifier; list.Add(((object)(KeyCode)(ref current)).ToString()); } KeyCode mainKey = ((KeyboardShortcut)(ref shortcut)).MainKey; list.Add(((object)(KeyCode)(ref mainKey)).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 Color ColorTint; public int ColorMode; public bool MatchBody; public Color BallColorTint; public int BallColorMode; public bool BallMatchBody; 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 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 float ArousalLerpSpeed = 2f; public float BallColorR = 1f; public float BallColorG = 1f; public float BallColorB = 1f; public int BallColorMode; public bool BallMatchBody = true; } [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 PerPresetSettingsEntry[] Entries; } public class UserPresetManager { private readonly string _baseDir; private readonly string _presetsDir; private readonly string _lastUsedPath; private readonly string _perPresetPath; 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"); try { if (!Directory.Exists(_baseDir)) { Directory.CreateDirectory(_baseDir); } if (!Directory.Exists(_presetsDir)) { Directory.CreateDirectory(_presetsDir); } } catch (Exception ex) { Plugin.LogWarningLimited("preset.create_dirs", "Failed to create preset directories: " + ex.Message); } } public void SaveLastUsed(ProfileSaveData data) { try { 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 { 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) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { name = name.Replace(oldChar, '_'); } return Path.Combine(_presetsDir, name + ".json"); } public void SavePerPresetSettings(Dictionary memory) { try { PerPresetSettingsEntry[] array = new PerPresetSettingsEntry[memory.Count]; int num = 0; foreach (KeyValuePair item in memory) { string text = null; if (Plugin.Presets != null) { text = Plugin.Presets.GetPreset(item.Key)?.Id; } array[num++] = new PerPresetSettingsEntry { PresetIndex = item.Key, PresetId = (text ?? item.Key.ToString()), Settings = item.Value }; } PerPresetSettingsStore perPresetSettingsStore = new PerPresetSettingsStore { Entries = array }; 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; } PerPresetSettingsEntry[] entries = perPresetSettingsStore.Entries; foreach (PerPresetSettingsEntry perPresetSettingsEntry in entries) { if (perPresetSettingsEntry.PresetIndex >= 0) { dictionary[perPresetSettingsEntry.PresetIndex] = perPresetSettingsEntry.Settings; } } } catch (Exception ex) { Plugin.LogWarningLimited("preset.load_per_preset", "Failed to load per-preset settings: " + ex.Message); } return dictionary; } public static ProfileSaveData CaptureFromController(ShlongController sc) { //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_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) return new ProfileSaveData { DickNumber = sc.PresetIndex, DickOffsetX = sc.PositionOffset.x, DickOffsetY = sc.PositionOffset.y, BallsSizeOffset = sc.BallsSizeOffset, FutaToggle = sc.FutaToggle, 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, ArousalLerpSpeed = sc.ArousalLerpSpeed, BallColorR = sc.BallColorTint.r, BallColorG = sc.BallColorTint.g, BallColorB = sc.BallColorTint.b, BallColorMode = sc.BallColorMode, BallMatchBody = sc.BallMatchBody }; } } } namespace AtlyssShlongs.Core { public class AssetManager { private AssetBundle _mainBundle; private AssetBundle _testBundle; private string _mainBundlePath; private string _testBundlePath; private readonly ManualLogSource _log; public const string TestBundleFileName = "ShlongsPackage_test.unity3d"; private static MethodInfo _setReadableMethod; private static bool _setReadableChecked; 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); } 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 ((Object)(object)val.sharedMesh != (Object)null && !val.sharedMesh.isReadable) { TryMakeReadable(val.sharedMesh); } 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 void TryMakeReadable(Mesh mesh) { if (!_setReadableChecked) { _setReadableChecked = true; _setReadableMethod = typeof(Mesh).GetMethod("SetIsReadable", BindingFlags.Instance | BindingFlags.NonPublic); if (_setReadableMethod == null) { Plugin.LogWarningLimited("asset.mesh_set_readable", "Mesh.SetIsReadable not found — vertex clipping may be skipped"); } } if (_setReadableMethod == null) { return; } try { _setReadableMethod.Invoke(mesh, new object[1] { true }); } catch (Exception ex) { Plugin.LogWarningLimited("asset.mesh_readable." + ((Object)mesh).name, "Failed to make mesh readable: " + ((Object)mesh).name + " — " + ex.Message); } } 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 if (sharedMesh.blendShapeCount > 0) { _arousedIndex = 0; _arousedIsLegacyFallback = true; } for (int j = 0; j < BulgeBlendShapeNames.Length; j++) { int blendShapeIndex2 = sharedMesh.GetBlendShapeIndex(BulgeBlendShapeNames[j]); _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) { float num = Time.deltaTime / Mathf.Max(lerpSpeed, 0.1f); float blendShapeWeight = smr.GetBlendShapeWeight(_arousedIndex); smr.SetBlendShapeWeight(_arousedIndex, Mathf.Lerp(blendShapeWeight, target, num)); } } } 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 num = Mathf.Clamp(bulgeAmount, 0f, 100f); float num2 = _bulgeIndices.Length - 1; float num3 = Mathf.Clamp(bulgePosition, 0f, num2); float num4 = Mathf.Max(0.001f, bulgeWidth); float num5 = Mathf.Max(0.05f, bulgeSharpness); float num6 = Time.deltaTime / Mathf.Max(lerpSpeed, 0.1f); for (int i = 0; i < _bulgeIndices.Length; i++) { int num7 = _bulgeIndices[i]; if (num7 >= 0) { float num8 = Mathf.Abs((float)i - num3); float num9 = 0f; if (num8 <= num4) { float num10 = num8 / num4; num9 = Mathf.Pow(Mathf.Clamp01(1f - num10), num5); } float num11 = num * num9; float blendShapeWeight = smr.GetBlendShapeWeight(num7); smr.SetBlendShapeWeight(num7, Mathf.Lerp(blendShapeWeight, num11, num6)); } } } 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 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 Color LastBallColorTint; internal bool LastBallMatchBody = true; 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 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 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() { Application.quitting += OnApplicationQuit; } private static void OnApplicationQuit() { _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 || _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_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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: 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_02d0: 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, SourceSteamId = source.GetKnownSteamId(), PositionOffset = spawnResult.InitialOffset, BaseRotation = spawnResult.InitialRotation, SpawnedPresetIndex = num, SpawnedRaceIndex = raceIndex, MaterialResyncCount = 0 }; PresetData preset = Plugin.Presets.GetPreset(num); 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 ((Object)(object)spawnResult.DickMesh != (Object)null && ((Renderer)spawnResult.DickMesh).sharedMaterials != null) { displayRig.TemplateDickMaterials = (Material[])((Renderer)spawnResult.DickMesh).sharedMaterials.Clone(); } 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); CacheOriginalShlongMaterials(displayRig); SyncSettingsFromSource(source, displayRig); displayRig.LastColorTint = source.ColorTint; displayRig.LastMatchBody = source.MatchBody; displayRig.LastBallColorTint = source.BallColorTint; displayRig.LastBallMatchBody = source.BallMatchBody; 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); } } } internal static void ForceRefreshColorsFor(ShlongController source, bool dick, bool balls) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_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_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_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_0135: 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_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) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025d: 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; } Color val; if ((Object)(object)value.DickMesh != (Object)null && DickMeshHasBallsSheathSlots(value)) { value.LastColorTint = source.ColorTint; value.LastMatchBody = source.MatchBody; value.LastBallColorTint = source.BallColorTint; value.LastBallMatchBody = source.BallMatchBody; 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 }; val = source.ColorTint; obj[11] = ((object)(Color)(ref val)).ToString(); obj[12] = " ballColor="; val = source.BallColorTint; obj[13] = ((object)(Color)(ref val)).ToString(); obj[14] = " frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } return; } if (dick) { value.LastColorTint = source.ColorTint; value.LastMatchBody = source.MatchBody; ApplyDickColor(value); } if (balls) { value.LastBallColorTint = source.BallColorTint; value.LastBallMatchBody = source.BallMatchBody; 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 }; val = source.ColorTint; obj2[7] = ((object)(Color)(ref val)).ToString(); obj2[8] = " match="; obj2[9] = source.MatchBody.ToString(); obj2[10] = " ballColor="; val = source.BallColorTint; obj2[11] = ((object)(Color)(ref val)).ToString(); obj2[12] = " ballMatch="; obj2[13] = source.BallMatchBody.ToString(); obj2[14] = " frame="; obj2[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj2)); } } 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 void UpdateSingleRig(ShlongController source, DisplayRig rig) { //IL_0027: 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_004e: 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_01dd: 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_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0187: 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_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_0346: 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_0327: 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_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rig.HipBone == (Object)null) { return; } rig.DisplayRoot.transform.SetPositionAndRotation(rig.HipBone.position, rig.HipBone.rotation); rig.DisplayRoot.transform.localScale = rig.HipBone.lossyScale; 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; rig.BlendShapes.ApplyAroused(rig.DickMesh, arousalTarget, arousalLerpSpeed); rig.BlendShapes.ApplyBulge(rig.DickMesh, source.BulgeAmount, source.BulgePosition, source.BulgeWidth, source.BulgeSharpness, arousalLerpSpeed); } 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) { rig.LastColorTint = source.ColorTint; rig.LastMatchBody = source.MatchBody; ApplyDickColor(rig); } if (source.BallColorTint != rig.LastBallColorTint || source.BallMatchBody != rig.LastBallMatchBody) { rig.LastBallColorTint = source.BallColorTint; rig.LastBallMatchBody = source.BallMatchBody; ApplyBallColor(rig); } } PresetData presetData = Plugin.Presets?.GetPreset(rig.SpawnedPresetIndex); if (presetData != null && presetData.AssetSource == PresetAssetSource.Test) { bool flag = rig.MaterialResyncCount < 60 && Time.frameCount % 10 == 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 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_015b: 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 flag3 = (flag2 ? rig.LastBallMatchBody : rig.LastMatchBody); Material val2 = ((rig.TemplateDickMaterials != null && i < rig.TemplateDickMaterials.Length) ? rig.TemplateDickMaterials[i] : null); Material val3 = (flag3 ? val : (val2 ?? val)); array2[i] = ShlongController.BuildColoredMaterial(val3, tint, flag3); if (Plugin.IsDebug) { Plugin.LogDebug("[SplitColorSlot] slot=" + i + " isBallSlot=" + flag2 + " match=" + flag3 + " 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.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.OriginalBodyMaterial); } } } private static void ApplyColorToRenderer(SkinnedMeshRenderer smr, Material[] originalMaterials, Material[] templateMaterials, Color tint, bool matchBody, Material fallbackBodyMat) { //IL_00cf: 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 (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 ? val : (val2 ?? val)); array[i] = ShlongController.BuildColoredMaterial(baseMat, tint, matchBody); } ((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 ? val3 : (val4 ?? val3)); Material val6 = ShlongController.BuildColoredMaterial(val5, tint, matchBody); 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 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)(ref val)).ToString(); obj[4] = " displayedScale="; val = rig.LastStableScaleOffset; obj[5] = ((object)(Vector3)(ref val)).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 = (Object)(object)cachedPRM == (Object)null || (Object)(object)cachedPRM._baseBodyMesh == (Object)null || ((Renderer)cachedPRM._baseBodyMesh).enabled; if (flag3 != rig.PendingBodyVisible) { rig.PendingBodyVisible = flag3; rig.PendingBodyVisibleSince = Time.unscaledTime; } bool playerBodyVisible = rig.LastAppliedBodyVisible; if (flag3 == rig.LastAppliedBodyVisible || Time.unscaledTime - rig.PendingBodyVisibleSince >= 0.2f) { rig.LastAppliedBodyVisible = flag3; playerBodyVisible = flag3; } bool flag4 = VisibilityResolver.ShouldShowDick(source.IsLocal, charMenuON, activeInHierarchy, displayBoobs, futaToggle, clothingOverride, flag, noLeggingsEquipped, playerBodyVisible, source.HideToggle); if (!clothingOverride && !flag && !flag2 && !rig.HasKnownNoLeggings) { flag4 = false; } if (flag4 != rig.PendingVisible) { rig.PendingVisible = flag4; rig.PendingVisibleSince = Time.unscaledTime; } if ((flag4 == rig.LastAppliedVisible || Time.unscaledTime - rig.PendingVisibleSince >= 0.2f || charMenuON) && flag4 != rig.LastAppliedVisible) { rig.LastAppliedVisible = flag4; if (Plugin.IsDebug) { Plugin.LogDebug("[CosmeticDisplay] VisibilityChange\n source=" + ((Object)((Component)source).gameObject).name + "\n visible=" + flag4 + "\n preset=" + source.PresetIndex + "\n rigPreset=" + rig.SpawnedPresetIndex + "\n isLocal=" + source.IsLocal + "\n goActive=" + activeInHierarchy + "\n bodyVisible=" + playerBodyVisible + "\n rawBodyVisible=" + flag3 + "\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 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_06c1: 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_06c9: Unknown result type (might be due to invalid IL or missing references) //IL_06ce: Unknown result type (might be due to invalid IL or missing references) //IL_06d0: Unknown result type (might be due to invalid IL or missing references) //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_06e7: Unknown result type (might be due to invalid IL or missing references) //IL_078f: Unknown result type (might be due to invalid IL or missing references) //IL_07a7: Unknown result type (might be due to invalid IL or missing references) //IL_07bf: Unknown result type (might be due to invalid IL or missing references) //IL_0767: 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_0781: Unknown result type (might be due to invalid IL or missing references) //IL_0786: Unknown result type (might be due to invalid IL or missing references) //IL_078b: Unknown result type (might be due to invalid IL or missing references) //IL_0715: Unknown result type (might be due to invalid IL or missing references) //IL_070c: Unknown result type (might be due to invalid IL or missing references) //IL_07f2: Unknown result type (might be due to invalid IL or missing references) //IL_07f7: Unknown result type (might be due to invalid IL or missing references) //IL_07fb: Unknown result type (might be due to invalid IL or missing references) //IL_0800: Unknown result type (might be due to invalid IL or missing references) //IL_0807: Unknown result type (might be due to invalid IL or missing references) //IL_080d: Unknown result type (might be due to invalid IL or missing references) //IL_0812: Unknown result type (might be due to invalid IL or missing references) //IL_0817: Unknown result type (might be due to invalid IL or missing references) //IL_071a: 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_086c: 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_0879: Unknown result type (might be due to invalid IL or missing references) //IL_0880: Unknown result type (might be due to invalid IL or missing references) //IL_0886: Unknown result type (might be due to invalid IL or missing references) //IL_088b: Unknown result type (might be due to invalid IL or missing references) //IL_0890: Unknown result type (might be due to invalid IL or missing references) //IL_0904: 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_0910: Unknown result type (might be due to invalid IL or missing references) //IL_0915: Unknown result type (might be due to invalid IL or missing references) //IL_082e: Unknown result type (might be due to invalid IL or missing references) //IL_0835: Unknown result type (might be due to invalid IL or missing references) //IL_083a: 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_0847: Unknown result type (might be due to invalid IL or missing references) //IL_084c: Unknown result type (might be due to invalid IL or missing references) //IL_0851: Unknown result type (might be due to invalid IL or missing references) //IL_072e: Unknown result type (might be due to invalid IL or missing references) //IL_0730: Unknown result type (might be due to invalid IL or missing references) //IL_0748: Unknown result type (might be due to invalid IL or missing references) //IL_074d: Unknown result type (might be due to invalid IL or missing references) //IL_0752: 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; } 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 j = 0; j < proceduralJiggleChain.Bones.Count; j++) { ProceduralJiggleBone proceduralJiggleBone2 = proceduralJiggleChain.Bones[j]; if (proceduralJiggleBone2 != null && !((Object)(object)proceduralJiggleBone2.Bone == (Object)null)) { num10++; if (proceduralJiggleBone == null) { proceduralJiggleBone = proceduralJiggleBone2; } Vector3 val15 = MapWorldMotionToJiggleTarget(source, rig, worldVel, worldAngularDeg, velToDeg, angToDeg); Vector3 val16 = val15 * (num4 * num16 * proceduralJiggleBone2.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 * proceduralJiggleBone2.Weight * num17 * num21); } if (num9 != 0f) { val16 += new Vector3(num9, 0f, 0f) * proceduralJiggleBone2.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; } proceduralJiggleBone2.Velocity += (val16 - proceduralJiggleBone2.Offset) * num18 * num2; if (num20 > 0f) { proceduralJiggleBone2.Velocity += -proceduralJiggleBone2.Offset * num20 * num2; } proceduralJiggleBone2.Velocity *= Mathf.Pow(num19, num2 * 60f); proceduralJiggleBone2.Offset += proceduralJiggleBone2.Velocity * num2; proceduralJiggleBone2.Offset.x = Mathf.Clamp(proceduralJiggleBone2.Offset.x, 0f - num7, num7); proceduralJiggleBone2.Offset.y = Mathf.Clamp(proceduralJiggleBone2.Offset.y, 0f - num7, num7); proceduralJiggleBone2.Offset.z = Mathf.Clamp(proceduralJiggleBone2.Offset.z, 0f - num7, num7); proceduralJiggleBone2.Bone.localRotation = proceduralJiggleBone2.BaseLocalRotation * Quaternion.Euler(proceduralJiggleBone2.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) { 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); } rig.MaterialResyncCount++; 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) { 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); } } } rig.LastRaceBodyShader = shader; rig.LastRaceBodyTexture = mainTexture; rig.LastRaceBodyAdjustmentSignature = characterColorAdjustmentSignature; rig.MaterialResyncCount++; 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 ((Object)(object)bodyMaterial2 != (Object)(object)((Renderer)rig.DickMesh).sharedMaterial) { ((Renderer)rig.DickMesh).sharedMaterial = bodyMaterial2; flag2 = true; } if (rig.Balls != null) { for (int k = 0; k < rig.Balls.Length; k++) { if ((Object)(object)rig.Balls[k] != (Object)null && (Object)(object)bodyMaterial2 != (Object)(object)((Renderer)rig.Balls[k]).sharedMaterial) { ((Renderer)rig.Balls[k]).sharedMaterial = bodyMaterial2; flag2 = true; } } } if (flag2) { rig.MaterialResyncCount++; rig.OriginalBodyMaterial = bodyMaterial2; CacheOriginalShlongMaterials(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) { return ((Renderer)component).sharedMaterials[race.MaterialSlot]; } return null; } } internal static class MaterialSkinUtility { 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 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 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; } return ((Renderer)bodySMR).sharedMaterials[race.MaterialSlot]; } internal static Material BuildRaceShadedMaterial(Material original, Material raceBodyMaterial) { //IL_0025: 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_002b: Expected O, but got Unknown if ((Object)(object)raceBodyMaterial == (Object)null) { return original; } Material val = (((Object)(object)original != (Object)null) ? new Material(original) : new Material(raceBodyMaterial)); if ((Object)(object)raceBodyMaterial.shader != (Object)null) { val.shader = raceBodyMaterial.shader; } CopyMainTextureLikeProperties(raceBodyMaterial, val); CopyMainColorLikeProperties(raceBodyMaterial, val); if (ShouldCopyCharacterColorAdjustments()) { CopyCharacterColorAdjustmentProperties(raceBodyMaterial, val); } else { NeutralizeCharacterColorAdjustmentProperties(val); } if ((Object)(object)original != (Object)null) { val.renderQueue = original.renderQueue; val.enableInstancing = original.enableInstancing; ((Object)val).name = ((Object)original).name.Replace(" (Instance)", "") + "_RaceShaded"; } return val; } internal static bool ShouldCopyCharacterColorAdjustments() { return PluginConfig.ApplyCharacterHbcToMatchedShlongs != null && PluginConfig.ApplyCharacterHbcToMatchedShlongs.Value; } internal static void CopyCharacterColorAdjustmentProperties(Material src, Material dst) { if (!ShouldCopyCharacterColorAdjustments() || (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 (!ShouldCopyCharacterColorAdjustments()) { return "hbc:disabled"; } if ((Object)(object)src == (Object)null) { return "hbc:null"; } StringBuilder stringBuilder = new StringBuilder(128); stringBuilder.Append("hbc:on;"); 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_0106: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected I4, but got Unknown //IL_0076: 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_00b6: 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) if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null || string.IsNullOrEmpty(propName) || !src.HasProperty(propName) || !dst.HasProperty(propName)) { return; } try { ShaderPropertyType propertyType = GetPropertyType(src, propName); ShaderPropertyType val = propertyType; 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 { try { dst.SetFloat(propName, src.GetFloat(propName)); } catch { } try { dst.SetColor(propName, src.GetColor(propName)); } catch { } try { dst.SetVector(propName, src.GetVector(propName)); } catch { } } } private static void NeutralizeCharacterAdjustmentPropertyIfPresent(Material mat, string propName) { //IL_00ad: 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_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_0039: 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_003e: 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_0059: Expected I4, but got Unknown //IL_005d: 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) if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(propName) || !mat.HasProperty(propName)) { return; } try { ShaderPropertyType propertyType = GetPropertyType(mat, propName); ShaderPropertyType val = propertyType; ShaderPropertyType val2 = val; switch ((int)val2) { case 0: mat.SetColor(propName, Color.white); break; case 1: mat.SetVector(propName, GetNeutralAdjustmentVector(propName)); break; case 4: break; default: mat.SetFloat(propName, GetNeutralAdjustmentFloat(propName)); break; } } catch { try { mat.SetFloat(propName, GetNeutralAdjustmentFloat(propName)); } catch { } try { mat.SetVector(propName, GetNeutralAdjustmentVector(propName)); } catch { } try { mat.SetColor(propName, Color.white); } catch { } } } 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 ShaderPropertyType GetPropertyType(Material mat, string propName) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) Shader shader = mat.shader; if ((Object)(object)shader == (Object)null) { return (ShaderPropertyType)2; } int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if (shader.GetPropertyName(i) == propName) { return shader.GetPropertyType(i); } } return (ShaderPropertyType)2; } private static void AppendMaterialPropertySignature(Material src, string propName, StringBuilder sb) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0044: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected I4, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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) if ((Object)(object)src == (Object)null || string.IsNullOrEmpty(propName) || !src.HasProperty(propName)) { return; } try { ShaderPropertyType propertyType = GetPropertyType(src, propName); sb.Append(propName).Append('='); ShaderPropertyType val = propertyType; 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 void CopyMainTextureLikeProperties(Material src, Material dst) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)src == (Object)null || (Object)(object)dst == (Object)null) { return; } CopyTextureProperty(src, dst, "_MainTex"); CopyTextureProperty(src, dst, "_BaseMap"); CopyTextureProperty(src, dst, "_BaseColorMap"); 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 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 Vector2 InitialOffset; public Vector3 InitialRotation; 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 int ApplySoloStyleDynamicBones(GameObject instance, PresetData preset, ref SpawnResult result, string context) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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) if ((Object)(object)instance == (Object)null || preset == null || preset.DynamicBones == null) { return 0; } int num = 0; int num2 = 0; bool flag = false; 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; } } } 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_0200: 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_02d0: 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_02fc: 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_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0351: 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_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) 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; 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; } } } 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); bool flag = preset.AssetSource == PresetAssetSource.Test; SkinnedMeshRenderer component2 = ((Component)val6).GetComponent(); if (!flag && (Object)(object)component2 != (Object)null && ((Renderer)component2).sharedMaterials != null && race.MaterialSlot >= 0 && race.MaterialSlot < ((Renderer)component2).sharedMaterials.Length) { ((Renderer)component).sharedMaterial = ((Renderer)component2).sharedMaterials[race.MaterialSlot]; } SkinnedMeshRenderer[] componentsInChildren = val.GetComponentsInChildren(true); List list = new List(); SkinnedMeshRenderer[] array = componentsInChildren; foreach (SkinnedMeshRenderer val8 in array) { if (!((Object)(object)val8 == (Object)(object)component)) { val8.updateWhenOffscreen = true; if (!flag && (Object)(object)component2 != (Object)null && ((Renderer)component2).sharedMaterials != null && race.MaterialSlot >= 0 && race.MaterialSlot < ((Renderer)component2).sharedMaterials.Length) { ((Renderer)val8).sharedMaterial = ((Renderer)component2).sharedMaterials[race.MaterialSlot]; } list.Add(val8); } } result.BallMeshes = ((list.Count > 0) ? list.ToArray() : null); if (flag) { Material raceBodyMaterial = GetRaceBodyMaterial(component2, race); if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin] preset=" + preset.Id + " race=" + race.BodyMesh + " sourceSlot=" + race.MaterialSlot + " sourceMat=" + (((Object)(object)raceBodyMaterial != (Object)null) ? ((Object)raceBodyMaterial).name : "") + " sourceShader=" + (((Object)(object)raceBodyMaterial != (Object)null && (Object)(object)raceBodyMaterial.shader != (Object)null) ? ((Object)raceBodyMaterial.shader).name : "")); } ApplyRaceShadingToRendererMaterials(component, raceBodyMaterial, "Dick", preset.Id); if (result.BallMeshes != null) { for (int k = 0; k < result.BallMeshes.Length; k++) { ApplyRaceShadingToRendererMaterials(result.BallMeshes[k], raceBodyMaterial, "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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0257: 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_0271: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_055d: Unknown result type (might be due to invalid IL or missing references) //IL_0802: Unknown result type (might be due to invalid IL or missing references) //IL_0807: 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; } 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; bool flag = preset.AssetSource == PresetAssetSource.Test; SkinnedMeshRenderer component2 = ((Component)val4).GetComponent(); if (!flag && (Object)(object)component2 != (Object)null && ((Renderer)component2).sharedMaterials != null && race.MaterialSlot >= 0 && race.MaterialSlot < ((Renderer)component2).sharedMaterials.Length) { ((Renderer)component).sharedMaterial = ((Renderer)component2).sharedMaterials[race.MaterialSlot]; } 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 (!flag && (Object)(object)component2 != (Object)null && ((Renderer)component2).sharedMaterials != null && race.MaterialSlot >= 0 && race.MaterialSlot < ((Renderer)component2).sharedMaterials.Length) { ((Renderer)val6).sharedMaterial = ((Renderer)component2).sharedMaterials[race.MaterialSlot]; } list.Add(val6); } } result.BallMeshes = ((list.Count > 0) ? list.ToArray() : null); if (flag) { Material raceBodyMaterial = GetRaceBodyMaterial(component2, race); if (Plugin.IsDebug) { Plugin.LogDebug("[MaterialSkin][Cosmetic] preset=" + preset.Id + " race=" + race.BodyMesh + " sourceSlot=" + race.MaterialSlot + " sourceMat=" + (((Object)(object)raceBodyMaterial != (Object)null) ? ((Object)raceBodyMaterial).name : "") + " sourceShader=" + (((Object)(object)raceBodyMaterial != (Object)null && (Object)(object)raceBodyMaterial.shader != (Object)null) ? ((Object)raceBodyMaterial.shader).name : "")); } ApplyRaceShadingToRendererMaterials(component, raceBodyMaterial, "Dick", preset.Id); if (result.BallMeshes != null) { for (int j = 0; j < result.BallMeshes.Length; j++) { ApplyRaceShadingToRendererMaterials(result.BallMeshes[j], raceBodyMaterial, "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 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 float ArousalLerpSpeed = 2f; public Color BallColorTint = Color.white; public int BallColorMode; public bool BallMatchBody = true; public float BulgeAmount; public float BulgePosition; public float BulgeWidth = 1f; public float BulgeSharpness = 1f; 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; 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 string _cachedSteamId; private bool _respawnAfterTransition; private int _deferredSpawnPreset = -1; private int _queuedInteractivePreset = -1; private int _queuedInteractivePresetFrame = -1; private bool _syncAfterQueuedInteractivePreset; private ProfileSaveData _pendingUserProfile; private float _lastAutoSaveTime; private Material _cachedDickMaterial; private Color _cachedDickColor; private bool _cachedDickMatchBody; private Material _cachedBallMaterial; private Color _cachedBallColor; private bool _cachedBallMatchBody; 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; 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 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; _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 void RememberPresetSettings(int presetIndex, PresetSettings settings) { _presetMemory[presetIndex] = settings; } private void UpdateCurrentPresetMemory(string reason) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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) if (PresetIndex >= 0) { _presetMemory[PresetIndex] = CaptureSettings(); if (IsLocal && Plugin.UserPresets != null) { Plugin.UserPresets.SavePerPresetSettings(_presetMemory); } 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 val = ColorTint; obj[7] = ((object)(Color)(ref val)).ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; val = BallColorTint; obj[11] = ((object)(Color)(ref val)).ToString(); obj[12] = " ballMatchBody="; obj[13] = BallMatchBody.ToString(); obj[14] = " frame="; obj[15] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } } 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; _syncAfterQueuedInteractivePreset = true; 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)") && !((Object)((Component)this).gameObject).name.Contains("equipDisplay"); } 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; _cachedOriginalBodyMaterial = null; _cachedHipBone = null; _originalDickMaterials = null; _originalMaterialsByRenderer.Clear(); _templateDickMaterials = null; _templateMaterialsByRenderer.Clear(); _respawnAfterTransition = false; _deferredSpawnPreset = -1; _queuedInteractivePreset = -1; _queuedInteractivePresetFrame = -1; _syncAfterQueuedInteractivePreset = false; _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; } 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; _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 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_08df: 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 profileSaveData = null; if (_presetMemory.Count == 0) { if (Plugin.UserPresets != null) { Dictionary dictionary = Plugin.UserPresets.LoadPerPresetSettings(); foreach (KeyValuePair item in dictionary) { _presetMemory[item.Key] = item.Value; } if (Plugin.IsDebug && dictionary.Count > 0) { Plugin.LogDebug("[PerPresetLoad] Loaded " + dictionary.Count + " per-preset entries on " + ((Object)((Component)this).gameObject).name); } } if (Plugin.UserPresets != null) { profileSaveData = Plugin.UserPresets.LoadLastUsed(); } if (profileSaveData == null) { int currentProfileIndex = RaceModelPatch.GetCurrentProfileIndex(); if (currentProfileIndex >= 0 && currentProfileIndex < Plugin.LoadedProfiles.Length) { profileSaveData = Plugin.LoadedProfiles[currentProfileIndex]; } } if (profileSaveData != null) { presetIndex = ResolvePresetForLocalAssets(profileSaveData.DickNumber); } } if (Plugin.IsDebug) { Plugin.LogDebug("[DeferredSpawn] " + ((Object)((Component)this).gameObject).name + " local=" + IsLocal + " preset=" + presetIndex + " profile=" + (profileSaveData != null) + " frame=" + Time.frameCount); } Spawn(presetIndex); if (profileSaveData != null) { ApplyLoadedProfile(profileSaveData); } 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.Rotation | SyncField.ErectAngle | SyncField.Color | SyncField.BallColor | SyncField.Hide | SyncField.Bulge); } } _syncAfterQueuedInteractivePreset = false; 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; 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; _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 && Time.frameCount % 300 == 0) { TryResyncMaterial(); } if ((Object)(object)InstanceRoot != (Object)null) { InstanceRoot.transform.position = ((Component)this).transform.position; } 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, ArousalLerpSpeed); } 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 charMenuON = Plugin.CharMenuON; bool playerBodyVisible = (Object)(object)_cachedPlayerRaceModel == (Object)null || (Object)(object)_cachedPlayerRaceModel._baseBodyMesh == (Object)null || ((Renderer)_cachedPlayerRaceModel._baseBodyMesh).enabled; bool flag = VisibilityResolver.ShouldShowDick(IsLocal, charMenuON, ((Component)this).gameObject.activeInHierarchy, displayBoobs, FutaToggle, ClothingOverride, hideLeggingsVisual, noLeggingsEquipped, playerBodyVisible, HideToggle); if (flag != _visPendingShow) { _visPendingShow = flag; _visPendingSince = Time.unscaledTime; } if ((flag == _visAppliedShow || Time.unscaledTime - _visPendingSince >= 0.2f || charMenuON) && flag != _visAppliedShow) { _visAppliedShow = flag; } ((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 flag2 = VisibilityResolver.ShouldHideForCamera(CameraCollision._current._unhidePlayerModel); if (flag2 != _camHidePending) { _camHidePending = flag2; _camHidePendingSince = Time.unscaledTime; } if (Time.unscaledTime - _camHidePendingSince >= 0.05f || flag2 == _camHideStable) { _camHideStable = flag2; } 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_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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) PresetSettings result = default(PresetSettings); result.ScaleOffset = ScaleOffset; result.BallsSizeOffset = BallsSizeOffset; result.PositionOffset = PositionOffset; result.BaseRotation = BaseRotation; result.ErectAngleOffset = ErectAngleOffset; result.ArousalTarget = ArousalTarget; result.ColorTint = ColorTint; result.ColorMode = ColorMode; result.MatchBody = MatchBody; result.BallColorTint = BallColorTint; result.BallColorMode = BallColorMode; result.BallMatchBody = BallMatchBody; result.FutaToggle = FutaToggle; result.ClothingOverride = ClothingOverride; result.HideToggle = HideToggle; return result; } public 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_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) ScaleOffset = s.ScaleOffset; BallsSizeOffset = s.BallsSizeOffset; PositionOffset = s.PositionOffset; BaseRotation = s.BaseRotation; ErectAngleOffset = s.ErectAngleOffset; ArousalTarget = s.ArousalTarget; ColorTint = s.ColorTint; ColorMode = s.ColorMode; MatchBody = s.MatchBody; BallColorTint = s.BallColorTint; BallColorMode = s.BallColorMode; BallMatchBody = s.BallMatchBody; 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 val = s.ColorTint; obj[5] = ((object)(Color)(ref val)).ToString(); obj[6] = " matchBody="; obj[7] = s.MatchBody.ToString(); obj[8] = " ballColor="; val = s.BallColorTint; obj[9] = ((object)(Color)(ref val)).ToString(); obj[10] = " ballMatchBody="; obj[11] = s.BallMatchBody.ToString(); obj[12] = " frame="; obj[13] = Time.frameCount.ToString(); Plugin.LogDebug(string.Concat(obj)); } } private void ApplyLoadedProfile(ProfileSaveData data) { //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_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_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_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_00b4: 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_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) FutaToggle = data.FutaToggle; 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; ArousalLerpSpeed = data.ArousalLerpSpeed; BallColorTint = new Color(data.BallColorR, data.BallColorG, data.BallColorB); BallColorMode = data.BallColorMode; BallMatchBody = data.BallMatchBody; 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 val = ColorTint; obj[5] = ((object)(Color)(ref val)).ToString(); obj[6] = " colorMode="; obj[7] = ColorMode.ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; val = BallColorTint; obj[11] = ((object)(Color)(ref val)).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)); } RefreshTransform(); ApplyColorTint(); ApplyBallColorTint(); if (IsLocal) { RequestSyncImmediate(forceSave: false, SyncField.Position | SyncField.Scale | SyncField.BallsSize | SyncField.Rotation | SyncField.ErectAngle | SyncField.Color | SyncField.BallColor); } } public void Spawn(int presetIndex, bool resetNetworkDelta = true) { //IL_0414: 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_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Unknown result type (might be due to invalid IL or missing references) //IL_04de: 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 (!((Object)((Component)this).gameObject).name.Contains("equipDisplay") && !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); } 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; _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; BlendShapes.Reset(); BulgeAmount = 0f; BulgePosition = 0f; BulgeWidth = 1f; BulgeSharpness = 1f; PositionOffset = spawnResult.InitialOffset; BaseRotation = spawnResult.InitialRotation; PresetIndex = presetIndex; 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(); CacheOriginalShlongMaterials(); if (_presetMemory.TryGetValue(presetIndex, out var value)) { ApplySettings(value); } ApplyColorTint(); ApplyBallColorTint(); RefreshTransform(); if (resetNetworkDelta && IsLocal && Plugin.Network != null) { Plugin.Network.ResetDelta(); } TryRegisterInDict(); } } private bool ShouldDeferSpawnDuringLoading() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 if (((Object)((Component)this).gameObject).name.Contains("equipDisplay")) { 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 if (((Object)((Component)this).gameObject).name.Contains("equipDisplay")) { 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 ApplySplitColorToDickMesh() { //IL_0101: 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_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0195: 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_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: 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) 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[] 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 flag3 = (flag2 ? BallMatchBody : MatchBody); Material val2 = ((_templateDickMaterials != null && i < _templateDickMaterials.Length) ? _templateDickMaterials[i] : null); Material baseMat = (flag3 ? val : (val2 ?? val)); array2[i] = BuildColoredMaterial(baseMat, tint, flag3); } ((Renderer)DickMesh).sharedMaterials = array2; _cachedDickMaterial = ((array2.Length != 0) ? array2[0] : null); _cachedDickColor = ColorTint; _cachedDickMatchBody = MatchBody; _cachedBallColor = BallColorTint; _cachedBallMatchBody = BallMatchBody; } } 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, ref _cachedDickMaterial, ref _cachedDickColor, ref _cachedDickMatchBody); } 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, ref _cachedBallMaterial, ref _cachedBallColor, ref _cachedBallMatchBody); 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, ref Material cachedMat, ref Color cachedColor, ref bool cachedMatch) { //IL_015f: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_00cf: Unknown result type (might be due to invalid IL or missing references) if (originalMaterials == null || originalMaterials.Length <= 1) { Material val = ((originalMaterials != null && originalMaterials.Length == 1 && (Object)(object)originalMaterials[0] != (Object)null) ? originalMaterials[0] : (GetOriginalBodyMaterial() ?? ((Renderer)smr).sharedMaterial)); Material val2 = ((templateMaterials != null && templateMaterials.Length >= 1) ? templateMaterials[0] : null); Material baseMat = (matchBody ? val : (val2 ?? val)); if ((Object)(object)cachedMat != (Object)null && cachedColor == tint && cachedMatch == matchBody) { if ((Object)(object)((Renderer)smr).sharedMaterial != (Object)(object)cachedMat) { ((Renderer)smr).sharedMaterial = cachedMat; } } else { Material val4 = (((Renderer)smr).sharedMaterial = BuildColoredMaterial(baseMat, tint, matchBody)); cachedMat = val4; cachedColor = tint; cachedMatch = matchBody; } } else { Material[] array = (Material[])(object)new Material[originalMaterials.Length]; for (int i = 0; i < originalMaterials.Length; i++) { Material val5 = originalMaterials[i] ?? ((Renderer)smr).sharedMaterials[i]; Material val6 = ((templateMaterials != null && i < templateMaterials.Length) ? templateMaterials[i] : null); Material baseMat2 = (matchBody ? val5 : (val6 ?? val5)); array[i] = BuildColoredMaterial(baseMat2, tint, matchBody); } ((Renderer)smr).sharedMaterials = array; cachedMat = ((array.Length != 0) ? array[0] : null); cachedColor = tint; cachedMatch = matchBody; } } internal static Material BuildColoredMaterial(Material baseMat, Color tint, bool matchBody) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_009b: 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_005b: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: 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_0140: 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_01a4: 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) if ((Object)(object)baseMat == (Object)null) { return null; } Material val = new Material(baseMat); ((Object)val).name = ((Object)baseMat).name.Replace(" (Instance)", "").Replace("_ShlongColorRuntime", "") + "_ShlongColorRuntime"; if (matchBody) { if (!ApplyAdditiveToProperty(val, "_Color", tint) && !ApplyAdditiveToProperty(val, "_BaseColor", tint)) { ApplyAdditiveFallback(val, tint); } } else { NeutralizeTextures(val); bool flag = ApplySolidToProperty(val, "_Color", tint, forceAlphaOne: true); bool flag2 = ApplySolidToProperty(val, "_BaseColor", tint, forceAlphaOne: true); bool flag3 = flag || flag2; int num = Shader.PropertyToID("_ColorTint"); if (flag3) { if (val.HasProperty(num)) { val.SetColor(num, Color.white); } } else if (val.HasProperty(num)) { val.SetColor(num, tint); } else { ApplySolidFallback(val, tint); } if (val.HasProperty("_TintColor")) { val.SetColor("_TintColor", new Color(tint.r, tint.g, tint.b, 1f)); } if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", Color.black); } ForceOpaqueSolidMaterial(val); if (Plugin.IsDebug) { string[] obj = new string[12] { "[ColorSolidBuild] material=", ((Object)baseMat).name, " matchBody=false tint=", null, null, null, null, null, null, null, null, null }; Color val2 = tint; obj[3] = ((object)(Color)(ref val2)).ToString(); obj[4] = " shader="; obj[5] = ((Object)val.shader).name; obj[6] = " renderQueue="; obj[7] = val.renderQueue.ToString(); obj[8] = " hasColor="; obj[9] = val.HasProperty("_Color").ToString(); obj[10] = " hasBaseColor="; obj[11] = val.HasProperty("_BaseColor").ToString(); Plugin.LogDebug(string.Concat(obj)); } } return val; } 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; } Transform val = ((Component)this).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) { return ((Renderer)component).sharedMaterials[race.MaterialSlot]; } return null; } 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) { Plugin.Network.SendSync(this, forceFields); } if (IsLocal) { if (forceSave) { ForceSaveSettings(); } else { AutoSaveSettings(); } } } internal void ForceSaveSettings() { //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_00e8: 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 (IsLocal && Plugin.UserPresets != null) { _lastAutoSaveTime = Time.unscaledTime; Plugin.UserPresets.SaveLastUsed(UserPresetManager.CaptureFromController(this)); 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 val = ColorTint; obj[5] = ((object)(Color)(ref val)).ToString(); obj[6] = " colorMode="; obj[7] = ColorMode.ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; val = BallColorTint; obj[11] = ((object)(Color)(ref val)).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 void SaveCurrentPresetMemoryToDisk(string reason) { //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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if (IsLocal && PresetIndex >= 0 && Plugin.UserPresets != null) { _presetMemory[PresetIndex] = CaptureSettings(); Plugin.UserPresets.SavePerPresetSettings(_presetMemory); 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 val = ColorTint; obj[7] = ((object)(Color)(ref val)).ToString(); obj[8] = " matchBody="; obj[9] = MatchBody.ToString(); obj[10] = " ballColor="; val = BallColorTint; obj[11] = ((object)(Color)(ref val)).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; Plugin.UserPresets.SaveLastUsed(UserPresetManager.CaptureFromController(this)); 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) { 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) { 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); } } } _lastRaceBodyShader = shader; _lastRaceBodyTexture = mainTexture; _lastRaceBodyAdjustmentSignature = characterColorAdjustmentSignature; _lastRaceBodySourceKey = text; _materialResyncCount++; _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 ((Object)(object)currentRaceBodyMaterial2 != (Object)null && (Object)(object)((Renderer)DickMesh).sharedMaterial != (Object)(object)currentRaceBodyMaterial2) { ((Renderer)DickMesh).sharedMaterial = currentRaceBodyMaterial2; flag2 = true; } if (BallMeshes != null) { for (int k = 0; k < BallMeshes.Length; k++) { if ((Object)(object)BallMeshes[k] != (Object)null && (Object)(object)currentRaceBodyMaterial2 != (Object)null && (Object)(object)((Renderer)BallMeshes[k]).sharedMaterial != (Object)(object)currentRaceBodyMaterial2) { ((Renderer)BallMeshes[k]).sharedMaterial = currentRaceBodyMaterial2; flag2 = true; } } } if (flag2 || force) { _materialResyncCount++; _cachedOriginalBodyMaterial = currentRaceBodyMaterial2; _lastRaceBodyShader = null; _lastRaceBodyTexture = null; _lastRaceBodyAdjustmentSignature = null; _lastRaceBodySourceKey = null; CacheOriginalShlongMaterials(); InvalidateColorMaterialCache(dick: true, balls: true); ApplyColorTint(); ApplyBallColorTint(); } } } internal void ForceColorAdjustmentMaterialRefresh(string reason) { _materialResyncCount = 0; _lastRaceBodyShader = null; _lastRaceBodyTexture = null; _lastRaceBodyAdjustmentSignature = null; _lastRaceBodySourceKey = null; _cachedOriginalBodyMaterial = null; InvalidateColorMaterialCache(dick: true, balls: true); TryResyncMaterial(force: true); ApplyColorTint(); ApplyBallColorTint(); if (Plugin.IsDebug) { Plugin.LogDebug("[ColorHBC][LocalRefresh] controller=" + ((Object)((Component)this).gameObject).name + " reason=" + reason + " frame=" + Time.frameCount); } } 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) { if (!gameObjectActive) { return false; } if (!playerBodyVisible) { return false; } if (hideToggle) { return false; } if (displayBoobs && !futaToggle) { return false; } if (isCharMenu) { return true; } if (!clothingOverride && !hideLeggingsVisual && !noLeggingsEquipped) { return false; } return true; } public static bool ShouldHideForCamera(bool cameraUnhidePlayerModel) { return cameraUnhidePlayerModel; } } }