Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Y4NGZInteractions v1.0.1
Y4NGZInteractions.dll
Decompiled 2 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; 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.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using Y4NGZInteractions.InteractionAnimationApi; using Y4NGZInteractions.InteractionAnimationApi.Authoring; using Y4NGZInteractions.InteractionAnimationApi.Presenters; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("Y4NGZInteractions.Tests")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Y4NGZInteractions")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Consumer-agnostic local animation presentation API for Lethal Company")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("Y4NGZInteractions")] [assembly: AssemblyTitle("Y4NGZInteractions")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Y4NGZInteractions { internal sealed class InteractionRuntimeHost : MonoBehaviour { private Harmony harmony; private ManualLogSource log; private bool applicationQuitting; private bool tornDown; internal void Initialize(Harmony harmony, ManualLogSource log) { this.harmony = harmony; this.log = log; Application.quitting += OnApplicationQuitting; } private void LateUpdate() { InteractionAnimationApiRestoreDiagnostics.BeginCoordinatorLateUpdateTick(); try { InteractionAnimationApiPlugin.Tick(Time.deltaTime); } finally { InteractionAnimationApiRestoreDiagnostics.EndCoordinatorLateUpdateTick(); } } private void OnApplicationQuit() { applicationQuitting = true; } private void OnApplicationQuitting() { applicationQuitting = true; TearDown(); } private void OnDestroy() { Application.quitting -= OnApplicationQuitting; if (!applicationQuitting) { ManualLogSource obj = log; if (obj != null) { obj.LogError((object)("Y4NGZInteractions runtime host destroyed outside application shutdown " + string.Format("(frame={0}, host='{1}'). ", Time.frameCount, ((Object)(object)((Component)this).gameObject != (Object)null) ? ((Object)((Component)this).gameObject).name : "<null>") + "The interaction animation API and all Harmony patches are going down with it.")); } } TearDown(); } private void TearDown() { if (tornDown) { return; } tornDown = true; try { InteractionAnimationApiPlugin.Shutdown(); InteractionAnimationApiRestoreDiagnostics.Shutdown(); } catch (Exception ex) { ManualLogSource obj = log; if (obj != null) { obj.LogWarning((object)("Y4NGZInteractions shutdown warning: " + ex.Message)); } } Harmony obj2 = harmony; if (obj2 != null) { obj2.UnpatchSelf(); } } } [BepInPlugin("com.y4ngz.interactions", "Y4NGZInteractions", "1.0.1")] internal sealed class Plugin : BaseUnityPlugin { internal const string Guid = "com.y4ngz.interactions"; internal const string Name = "Y4NGZInteractions"; internal const string Version = "1.0.1"; internal const string HostObjectName = "Y4NGZInteractions_Host"; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static InteractionRuntimeHost Host { get; private set; } private void Awake() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Harmony harmony = new Harmony("com.y4ngz.interactions"); GameObject val = new GameObject("Y4NGZInteractions_Host") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)val); Host = val.AddComponent<InteractionRuntimeHost>(); Host.Initialize(harmony, ((BaseUnityPlugin)this).Logger); InitializeModule("Interaction Animation API", delegate { InteractionAnimationApiPlugin.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); }); InitializeModule("Interaction Animation API Restoration", delegate { InteractionAnimationApiRestoreDiagnostics.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); }); InitializeModule("Interaction Animation API Spawn Hooks", delegate { harmony.PatchAll(); }); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Y4NGZInteractions v1.0.1 loaded."); } private void InitializeModule(string label, Action initialize) { try { initialize(); ((BaseUnityPlugin)this).Logger.LogInfo((object)(label + " initialized.")); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{label} initialization failed: {arg}"); } } } internal static class BuildVersion { internal const string Value = "1.0.1"; } } namespace Y4NGZInteractions.InteractionAnimationApi { internal static class InteractionAnimationApiPlugin { private static ManualLogSource logger; private static InteractionAnimationCoordinator coordinator; private static bool initialized; internal static void Initialize(ConfigFile config, ManualLogSource log) { if (!initialized) { logger = log; coordinator = new InteractionAnimationCoordinator(logger); LCInteractionAnimationAPI.Initialize(coordinator); initialized = true; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"[LCInteractionAnimationAPI] api.initialized: standalone local presentation API ready."); } } } internal static void Tick(float deltaTime) { if (initialized) { coordinator?.Tick(deltaTime); } } internal static void Shutdown() { if (initialized) { coordinator?.Shutdown(); LiveBodyAnimatorPresenter.ShutdownBundleCache(); LCInteractionAnimationAPI.Shutdown(); coordinator = null; initialized = false; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"[LCInteractionAnimationAPI] api.shutdown: restoration complete."); } logger = null; } } } internal enum AnimatorStateRestoreMode { Fresh, Crossfade, Replay } internal sealed class AnimatorStateSnapshot { private readonly struct LayerSnapshot { public readonly int FullPathHash; public readonly float NormalizedTime; public readonly float Weight; public readonly bool InTransition; public LayerSnapshot(int fullPathHash, float normalizedTime, float weight, bool inTransition) { FullPathHash = fullPathHash; NormalizedTime = normalizedTime; Weight = weight; InTransition = inTransition; } } private readonly struct ParameterSnapshot { private readonly int nameHash; private readonly AnimatorControllerParameterType type; private readonly bool boolValue; private readonly int intValue; private readonly float floatValue; private ParameterSnapshot(int nameHash, AnimatorControllerParameterType type, bool boolValue, int intValue, float floatValue) { //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) this.nameHash = nameHash; this.type = type; this.boolValue = boolValue; this.intValue = intValue; this.floatValue = floatValue; } public static ParameterSnapshot Capture(Animator animator, AnimatorControllerParameter parameter) { //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_0007: 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_001f: Expected I4, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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) AnimatorControllerParameterType val = parameter.type; return (val - 1) switch { 3 => new ParameterSnapshot(parameter.nameHash, parameter.type, animator.GetBool(parameter.nameHash), 0, 0f), 2 => new ParameterSnapshot(parameter.nameHash, parameter.type, boolValue: false, animator.GetInteger(parameter.nameHash), 0f), 0 => new ParameterSnapshot(parameter.nameHash, parameter.type, boolValue: false, 0, animator.GetFloat(parameter.nameHash)), _ => new ParameterSnapshot(parameter.nameHash, parameter.type, boolValue: false, 0, 0f), }; } public void Restore(Animator animator) { //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_0007: 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_001f: Expected I4, but got Unknown AnimatorControllerParameterType val = type; switch (val - 1) { case 3: animator.SetBool(nameHash, boolValue); break; case 2: animator.SetInteger(nameHash, intValue); break; case 0: animator.SetFloat(nameHash, floatValue); break; case 1: break; } } } private const float CrossfadeDurationSeconds = 0.12f; private readonly LayerSnapshot[] layers; private readonly ParameterSnapshot[] parameters; public RuntimeAnimatorController RuntimeAnimatorController { get; } public float Speed { get; } public bool? CapturedCrouching { get; set; } private AnimatorStateSnapshot(RuntimeAnimatorController runtimeAnimatorController, float speed, LayerSnapshot[] layers, ParameterSnapshot[] parameters) { RuntimeAnimatorController = runtimeAnimatorController; Speed = speed; this.layers = layers ?? Array.Empty<LayerSnapshot>(); this.parameters = parameters ?? Array.Empty<ParameterSnapshot>(); } public static AnimatorStateSnapshot Capture(Animator animator) { //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) if ((Object)(object)animator == (Object)null) { return null; } try { RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController; float speed = animator.speed; if (!animator.isInitialized) { return new AnimatorStateSnapshot(runtimeAnimatorController, speed, Array.Empty<LayerSnapshot>(), Array.Empty<ParameterSnapshot>()); } int num = Math.Max(0, animator.layerCount); LayerSnapshot[] array = new LayerSnapshot[num]; for (int i = 0; i < num; i++) { AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(i); array[i] = new LayerSnapshot(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime, animator.GetLayerWeight(i), animator.IsInTransition(i)); } AnimatorControllerParameter[] array2 = animator.parameters ?? Array.Empty<AnimatorControllerParameter>(); ParameterSnapshot[] array3 = new ParameterSnapshot[array2.Length]; for (int j = 0; j < array2.Length; j++) { AnimatorControllerParameter parameter = array2[j]; array3[j] = ParameterSnapshot.Capture(animator, parameter); } return new AnimatorStateSnapshot(runtimeAnimatorController, speed, array, array3); } catch { return null; } } public int ReapplyParameters(Animator animator) { if ((Object)(object)animator == (Object)null) { return 0; } int num = 0; for (int i = 0; i < parameters.Length; i++) { try { parameters[i].Restore(animator); num++; } catch { } } return num; } public bool TryReapplyLayerState(Animator animator, int layerIndex) { if ((Object)(object)animator == (Object)null || layerIndex < 0 || layerIndex >= layers.Length || layerIndex >= animator.layerCount) { return false; } try { LayerSnapshot layerSnapshot = layers[layerIndex]; if (layerSnapshot.InTransition || layerSnapshot.FullPathHash == 0 || !animator.HasState(layerIndex, layerSnapshot.FullPathHash)) { return false; } animator.SetLayerWeight(layerIndex, layerSnapshot.Weight); animator.Play(layerSnapshot.FullPathHash, layerIndex, layerSnapshot.NormalizedTime); return true; } catch { return false; } } public bool Restore(Animator animator) { return Restore(animator, RuntimeAnimatorController); } public bool Restore(Animator animator, RuntimeAnimatorController expectedCurrentController) { return Restore(animator, expectedCurrentController, rebindAnimator: true); } public bool Restore(Animator animator, RuntimeAnimatorController expectedCurrentController, bool rebindAnimator) { return Restore(animator, expectedCurrentController, rebindAnimator, AnimatorStateRestoreMode.Replay); } public bool Restore(Animator animator, RuntimeAnimatorController expectedCurrentController, bool rebindAnimator, AnimatorStateRestoreMode restoreMode) { return Restore(animator, expectedCurrentController, rebindAnimator, restoreMode, null, restoreBaseLayerState: true); } public bool Restore(Animator animator, RuntimeAnimatorController expectedCurrentController, bool rebindAnimator, AnimatorStateRestoreMode restoreMode, Action syncParametersBeforeStateReplay, bool restoreBaseLayerState) { if ((Object)(object)animator == (Object)null) { return false; } try { if ((Object)(object)expectedCurrentController != (Object)null && (Object)(object)animator.runtimeAnimatorController != (Object)(object)expectedCurrentController) { return false; } animator.runtimeAnimatorController = RuntimeAnimatorController; if (rebindAnimator) { animator.Rebind(); } animator.speed = Speed; for (int i = 0; i < parameters.Length; i++) { parameters[i].Restore(animator); } if (syncParametersBeforeStateReplay != null) { try { syncParametersBeforeStateReplay(); } catch { } } int num = Math.Min(animator.layerCount, layers.Length); for (int j = 0; j < num; j++) { LayerSnapshot layerSnapshot = layers[j]; animator.SetLayerWeight(j, layerSnapshot.Weight); if ((j != 0 || restoreBaseLayerState) && layerSnapshot.FullPathHash != 0) { switch (restoreMode) { case AnimatorStateRestoreMode.Crossfade: animator.CrossFadeInFixedTime(layerSnapshot.FullPathHash, 0.12f, j, Mathf.Repeat(layerSnapshot.NormalizedTime, 1f)); break; case AnimatorStateRestoreMode.Replay: animator.Play(layerSnapshot.FullPathHash, j, layerSnapshot.NormalizedTime); break; } } } animator.Update(0f); return true; } catch { return false; } } } internal static class InteractionAnimationAssetPathResolver { internal const string RootMissingReason = "pack_asset_root_missing"; internal const string PathEscapesRootReason = "asset_bundle_path_escapes_root"; internal static bool TryNormalizeAssetRoot(string assetRootPath, out string normalizedRoot, out string reason) { normalizedRoot = string.Empty; reason = string.Empty; if (string.IsNullOrWhiteSpace(assetRootPath)) { reason = "pack_asset_root_missing"; return false; } try { normalizedRoot = TrimEndingDirectorySeparators(Path.GetFullPath(assetRootPath.Trim())); } catch (Exception ex) { reason = "pack_asset_root_invalid:" + ex.GetType().Name; normalizedRoot = string.Empty; return false; } if (!Directory.Exists(normalizedRoot)) { reason = "pack_asset_root_missing:" + normalizedRoot; normalizedRoot = string.Empty; return false; } return true; } internal static bool TryResolveBundlePath(string bundleFileName, string normalizedAssetRoot, out string resolvedPath, out string reason) { resolvedPath = string.Empty; reason = string.Empty; if (string.IsNullOrWhiteSpace(bundleFileName)) { reason = "asset_bundle_file_empty"; return false; } if (string.IsNullOrWhiteSpace(normalizedAssetRoot)) { reason = "pack_asset_root_missing"; return false; } try { string text = (Path.IsPathRooted(bundleFileName) ? Path.GetFullPath(bundleFileName) : Path.GetFullPath(Path.Combine(normalizedAssetRoot, bundleFileName))); if (!IsWithinRoot(normalizedAssetRoot, text)) { reason = "asset_bundle_path_escapes_root:" + bundleFileName; return false; } resolvedPath = text; return true; } catch (Exception ex) { reason = "asset_bundle_path_invalid:" + ex.GetType().Name; return false; } } private static bool IsWithinRoot(string normalizedRoot, string candidate) { string text = TrimEndingDirectorySeparators(Path.GetFullPath(normalizedRoot)); string fullPath = Path.GetFullPath(candidate); if (string.Equals(text, fullPath, StringComparison.OrdinalIgnoreCase)) { return true; } return fullPath.StartsWith(text + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase); } private static string TrimEndingDirectorySeparators(string path) { string text = Path.GetPathRoot(path) ?? string.Empty; while (path.Length > text.Length && (path[path.Length - 1] == Path.DirectorySeparatorChar || path[path.Length - 1] == Path.AltDirectorySeparatorChar)) { path = path.Substring(0, path.Length - 1); } return path; } } internal delegate bool InteractionAnimationBodyOwnershipValidator(PlayerControllerB player, InteractionAnimationPresentationKind presentationKind, InteractionAnimationHandle[] conflicts, out string reason); internal sealed class InteractionAnimationCoordinator { private readonly ManualLogSource logger; private readonly Func<InteractionAnimationPresentationKind, IInteractionPresenter> presenterFactory; private readonly Func<PlayerControllerB> localPlayerResolver; private readonly InteractionAnimationBodyOwnershipValidator bodyOwnershipValidator; private readonly Func<InteractionAnimationContext, IInteractionPresenter, InteractionAnimationSession> sessionFactory; private readonly Dictionary<string, RegisteredPackSnapshot> packs = new Dictionary<string, RegisteredPackSnapshot>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<InteractionAnimationHandle, InteractionAnimationSession> activeSessions = new Dictionary<InteractionAnimationHandle, InteractionAnimationSession>(); private readonly InteractionAnimationResourceLeaseRegistry leases = new InteractionAnimationResourceLeaseRegistry(); internal InteractionAnimationCoordinator(ManualLogSource logger, Func<InteractionAnimationPresentationKind, IInteractionPresenter> presenterFactory = null, Func<PlayerControllerB> localPlayerResolver = null, InteractionAnimationBodyOwnershipValidator bodyOwnershipValidator = null, Func<InteractionAnimationContext, IInteractionPresenter, InteractionAnimationSession> sessionFactory = null) { this.logger = logger; this.presenterFactory = presenterFactory ?? new Func<InteractionAnimationPresentationKind, IInteractionPresenter>(CreateDefaultPresenter); this.localPlayerResolver = localPlayerResolver ?? new Func<PlayerControllerB>(ResolveDefaultLocalPlayer); this.bodyOwnershipValidator = bodyOwnershipValidator ?? new InteractionAnimationBodyOwnershipValidator(TryValidateBodyAnimatorOwnership); this.sessionFactory = sessionFactory ?? ((Func<InteractionAnimationContext, IInteractionPresenter, InteractionAnimationSession>)((InteractionAnimationContext context, IInteractionPresenter presenter) => new InteractionAnimationSession(context, presenter))); } internal bool TryRegisterInteractionPack(InteractionAnimationPackDefinition pack, out string reason) { RegisteredPackSnapshot snapshot; InteractionAnimationValidationReport interactionAnimationValidationReport = InteractionAnimationPackValidator.Validate(pack, out snapshot); reason = InteractionAnimationManifestValidator.GetFirstErrorCode(interactionAnimationValidationReport); if (!interactionAnimationValidationReport.IsValid) { return false; } if (packs.ContainsKey(snapshot.PackId)) { reason = "pack_already_registered"; return false; } packs.Add(snapshot.PackId, snapshot); ManualLogSource obj = logger; if (obj != null) { obj.LogDebug((object)("[LCInteractionAnimationAPI] pack.registered: pack='" + snapshot.PackId + "' version='" + snapshot.Version + "' " + $"interactions={snapshot.InteractionCount}.")); } return true; } internal bool TryStartInteraction(InteractionAnimationRequest request, out InteractionAnimationHandle handle, out string reason) { handle = InteractionAnimationHandle.Empty; if (!TryResolveRequest(request, out var pack, out var interaction, out reason)) { return false; } PlayerControllerB val = ResolveLocalPlayer(); bool flag = request.Player == val; if (interaction.PresentationKind == InteractionAnimationPresentationKind.DedicatedLocalViewmodel && !flag) { reason = "dedicated_viewmodel_requires_local_player"; return false; } InteractionAnimationResourceClaim[] claims = BuildClaims(request.Player, interaction.PresentationKind, flag); if (!leases.TryPlanAcquisition(claims, request.ConflictPolicy, out var conflicts, out reason)) { return false; } if (!bodyOwnershipValidator(request.Player, interaction.PresentationKind, conflicts, out reason)) { return false; } handle = InteractionAnimationHandle.NewHandle(); InteractionAnimationRequest request2 = new InteractionAnimationRequest { Player = request.Player, PackId = pack.PackId, InteractionId = interaction.InteractionId, ConflictPolicy = request.ConflictPolicy }; InteractionAnimationContext arg = new InteractionAnimationContext(handle, request2, interaction.CreateDefinition(), interaction.Manifest, pack.AssetRootPath, logger); IInteractionPresenter arg2 = CreatePresenter(interaction.PresentationKind); InteractionAnimationSession interactionAnimationSession = sessionFactory(arg, arg2); if (!interactionAnimationSession.TryPreflight(out reason)) { handle = InteractionAnimationHandle.Empty; return false; } InteractionAnimationSession[] suspended = Array.Empty<InteractionAnimationSession>(); if (conflicts.Length != 0 && !TrySuspendConflicts(conflicts, out suspended, out reason)) { handle = InteractionAnimationHandle.Empty; return false; } if (!leases.TryAcquire(handle, claims, out reason)) { ResumeConflicts(suspended); handle = InteractionAnimationHandle.Empty; return false; } if (!interactionAnimationSession.TryStart(out reason)) { leases.Release(handle); ResumeConflicts(suspended); handle = InteractionAnimationHandle.Empty; return false; } FinalizeConflicts(suspended); activeSessions.Add(handle, interactionAnimationSession); ManualLogSource obj = logger; if (obj != null) { obj.LogDebug((object)("[LCInteractionAnimationAPI] interaction.started: " + $"handle={handle} pack='{pack.PackId}' interaction='{interaction.InteractionId}' " + $"presentation='{interaction.PresentationKind}'.")); } return true; } internal bool TryPreloadInteractionAssets(string packId, string interactionId, out string reason) { reason = string.Empty; if (string.IsNullOrWhiteSpace(packId) || string.IsNullOrWhiteSpace(interactionId)) { reason = "preload_invalid_identity"; return false; } if (!packs.TryGetValue(packId, out var value)) { reason = "pack_not_registered"; return false; } if (!value.TryGetInteraction(interactionId, out var interaction)) { reason = "interaction_not_registered"; return false; } if (interaction.PresentationKind == InteractionAnimationPresentationKind.BodyWorld) { return LiveBodyAnimatorPresenter.TryPreloadBundles(interaction.Manifest, value.AssetRootPath, logger, out reason); } return LocalViewmodelPresenter.TryBeginPreload(interaction.Manifest, value.AssetRootPath, logger, out reason); } internal bool TryStopInteraction(InteractionAnimationHandle handle, InteractionAnimationStopReason reason) { if (!activeSessions.TryGetValue(handle, out var value)) { return false; } if (!value.TryStopAndRestore(reason)) { return false; } leases.Release(handle); activeSessions.Remove(handle); NotifyEnded(value, reason); ManualLogSource obj = logger; if (obj != null) { obj.LogDebug((object)("[LCInteractionAnimationAPI] interaction.stopped: " + $"handle={handle} reason='{reason}'.")); } return true; } internal bool IsInteractionActive(InteractionAnimationHandle handle) { if (activeSessions.TryGetValue(handle, out var value)) { return value.IsActive; } return false; } internal bool TryGetActiveInteraction(PlayerControllerB player, InteractionAnimationPresentationKind presentationKind, out InteractionAnimationHandle handle) { handle = InteractionAnimationHandle.Empty; if (player == null) { return false; } foreach (KeyValuePair<InteractionAnimationHandle, InteractionAnimationSession> activeSession in activeSessions) { if (activeSession.Value.IsActive && activeSession.Value.Player == player && activeSession.Value.PresentationKind == presentationKind) { handle = activeSession.Key; return true; } } return false; } internal bool TrySetInteractionAnimatorParameter(InteractionAnimationHandle handle, string parameterName, AnimatorControllerParameterType parameterType, float value) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (activeSessions.TryGetValue(handle, out var value2)) { return value2.TrySetAnimatorParameter(parameterName, parameterType, value); } return false; } internal bool TryBeginInteractionExit(InteractionAnimationHandle handle, out string reason) { reason = string.Empty; if (!activeSessions.TryGetValue(handle, out var value) || !value.IsActive) { reason = "interaction_not_active"; return false; } float num = value.BeginExit(); ManualLogSource obj = logger; if (obj != null) { obj.LogDebug((object)("[LCInteractionAnimationAPI] interaction.exit_begun: " + $"handle={handle} exitSeconds={num:0.###}.")); } return true; } internal void Tick(float deltaTime) { if (activeSessions.Count == 0) { return; } InteractionAnimationHandle[] array = activeSessions.Keys.ToArray(); for (int i = 0; i < array.Length; i++) { if (activeSessions.TryGetValue(array[i], out var value)) { InteractionAnimationStopReason? interactionAnimationStopReason = value.Tick(deltaTime); if (interactionAnimationStopReason.HasValue) { TryStopInteraction(array[i], interactionAnimationStopReason.Value); } } } } internal void Shutdown() { InteractionAnimationHandle[] array = activeSessions.Keys.ToArray(); for (int i = 0; i < array.Length; i++) { TryStopInteraction(array[i], InteractionAnimationStopReason.Shutdown); } leases.Clear(); packs.Clear(); } private bool TryResolveRequest(InteractionAnimationRequest request, out RegisteredPackSnapshot pack, out RegisteredInteractionSnapshot interaction, out string reason) { pack = null; interaction = null; reason = string.Empty; if (request == null) { reason = "request_null"; return false; } if (request.Player == null) { reason = "request_player_missing"; return false; } if (string.IsNullOrWhiteSpace(request.PackId)) { reason = "request_pack_id_empty"; return false; } if (string.IsNullOrWhiteSpace(request.InteractionId)) { reason = "request_interaction_id_empty"; return false; } if (!Enum.IsDefined(typeof(InteractionAnimationConflictPolicy), request.ConflictPolicy)) { reason = "request_conflict_policy_invalid"; return false; } if (!packs.TryGetValue(request.PackId, out pack)) { reason = "pack_not_registered"; return false; } if (!pack.TryGetInteraction(request.InteractionId, out interaction)) { reason = "interaction_not_registered"; return false; } return true; } private bool TryValidateBodyAnimatorOwnership(PlayerControllerB player, InteractionAnimationPresentationKind presentationKind, InteractionAnimationHandle[] conflicts, out string reason) { reason = string.Empty; if (presentationKind != InteractionAnimationPresentationKind.BodyWorld) { return true; } Animator val = (((Object)(object)player != (Object)null) ? player.playerBodyAnimator : null); if ((Object)(object)val == (Object)null) { reason = "missing_body_animator"; return false; } for (int i = 0; i < conflicts.Length; i++) { if (activeSessions.TryGetValue(conflicts[i], out var value) && value.Player == player && value.PresentationKind == InteractionAnimationPresentationKind.BodyWorld && value.HasResourceOwnership) { return true; } } RuntimeAnimatorController val2 = ResolveExpectedVanillaController(player); if ((Object)(object)val2 == (Object)null) { reason = "expected_player_animator_controller_missing"; return false; } if ((Object)(object)val.runtimeAnimatorController != (Object)(object)val2) { reason = "player_animator_owned_externally"; return false; } return true; } private bool TrySuspendConflicts(InteractionAnimationHandle[] handles, out InteractionAnimationSession[] suspended, out string reason) { reason = string.Empty; List<InteractionAnimationSession> list = new List<InteractionAnimationSession>(); for (int i = 0; i < handles.Length; i++) { if (!activeSessions.TryGetValue(handles[i], out var value)) { continue; } if (!value.TrySuspend(out reason)) { for (int j = 0; j < list.Count; j++) { InteractionAnimationSession interactionAnimationSession = list[j]; if (!interactionAnimationSession.TryResume(out var _)) { leases.Release(interactionAnimationSession.Handle); activeSessions.Remove(interactionAnimationSession.Handle); interactionAnimationSession.TryStopAndRestore(InteractionAnimationStopReason.PresenterFailure); NotifyEnded(interactionAnimationSession, InteractionAnimationStopReason.PresenterFailure); } } if (value.IsEnded) { leases.Release(value.Handle); activeSessions.Remove(value.Handle); NotifyEnded(value, InteractionAnimationStopReason.PresenterFailure); } suspended = Array.Empty<InteractionAnimationSession>(); return false; } list.Add(value); } suspended = list.ToArray(); for (int k = 0; k < suspended.Length; k++) { leases.Release(suspended[k].Handle); } return true; } private void ResumeConflicts(InteractionAnimationSession[] sessions) { foreach (InteractionAnimationSession interactionAnimationSession in sessions) { bool isLocal = interactionAnimationSession.Player == ResolveLocalPlayer(); InteractionAnimationResourceClaim[] claims = BuildClaims(interactionAnimationSession.Player, interactionAnimationSession.PresentationKind, isLocal); if (!leases.TryAcquire(interactionAnimationSession.Handle, claims, out var reason) || !interactionAnimationSession.TryResume(out reason)) { leases.Release(interactionAnimationSession.Handle); activeSessions.Remove(interactionAnimationSession.Handle); interactionAnimationSession.TryStopAndRestore(InteractionAnimationStopReason.PresenterFailure); NotifyEnded(interactionAnimationSession, InteractionAnimationStopReason.PresenterFailure); } } } private void FinalizeConflicts(InteractionAnimationSession[] sessions) { foreach (InteractionAnimationSession interactionAnimationSession in sessions) { activeSessions.Remove(interactionAnimationSession.Handle); if (interactionAnimationSession.TryFinalizeSuspended()) { NotifyEnded(interactionAnimationSession, InteractionAnimationStopReason.Interrupted); } } } private void NotifyEnded(InteractionAnimationSession session, InteractionAnimationStopReason reason) { LCInteractionAnimationAPI.NotifyInteractionEnded(session.CreateEndedEvent(reason)); } private static InteractionAnimationResourceClaim[] BuildClaims(PlayerControllerB player, InteractionAnimationPresentationKind presentationKind, bool isLocal) { if (presentationKind != InteractionAnimationPresentationKind.DedicatedLocalViewmodel) { if (!isLocal) { return new InteractionAnimationResourceClaim[1] { new InteractionAnimationResourceClaim(InteractionAnimationResourceKind.BodyAnimator, player) }; } return new InteractionAnimationResourceClaim[2] { new InteractionAnimationResourceClaim(InteractionAnimationResourceKind.BodyAnimator, player), new InteractionAnimationResourceClaim(InteractionAnimationResourceKind.LocalCameraAndArms, player) }; } return new InteractionAnimationResourceClaim[1] { new InteractionAnimationResourceClaim(InteractionAnimationResourceKind.LocalCameraAndArms, player) }; } private PlayerControllerB ResolveLocalPlayer() { return localPlayerResolver(); } private static PlayerControllerB ResolveDefaultLocalPlayer() { try { return GameNetworkManager.Instance?.localPlayerController ?? StartOfRound.Instance?.localPlayerController; } catch { return null; } } private RuntimeAnimatorController ResolveExpectedVanillaController(PlayerControllerB player) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || player == null) { return null; } if (player != ResolveLocalPlayer()) { return instance.otherClientsAnimatorController; } return instance.localClientAnimatorController; } private IInteractionPresenter CreatePresenter(InteractionAnimationPresentationKind presentationKind) { return presenterFactory(presentationKind); } private static IInteractionPresenter CreateDefaultPresenter(InteractionAnimationPresentationKind presentationKind) { return presentationKind switch { InteractionAnimationPresentationKind.DedicatedLocalViewmodel => new LocalViewmodelPresenter(), InteractionAnimationPresentationKind.BodyWorld => new LiveBodyAnimatorPresenter(), _ => null, }; } } internal sealed class RegisteredPackSnapshot { private readonly Dictionary<string, RegisteredInteractionSnapshot> interactions; internal string PackId { get; } internal string Version { get; } internal string AssetRootPath { get; } internal int InteractionCount => interactions.Count; internal RegisteredPackSnapshot(string packId, string version, string assetRootPath, Dictionary<string, RegisteredInteractionSnapshot> interactions) { PackId = packId; Version = version; AssetRootPath = assetRootPath; this.interactions = interactions; } internal bool TryGetInteraction(string interactionId, out RegisteredInteractionSnapshot interaction) { return interactions.TryGetValue(interactionId, out interaction); } } internal sealed class RegisteredInteractionSnapshot { internal string InteractionId { get; } internal InteractionAnimationPresentationKind PresentationKind { get; } internal string ManifestJson { get; } internal InteractionAnimationManifest Manifest { get; } internal RegisteredInteractionSnapshot(string interactionId, InteractionAnimationPresentationKind presentationKind, string manifestJson, InteractionAnimationManifest manifest) { InteractionId = interactionId; PresentationKind = presentationKind; ManifestJson = manifestJson; Manifest = manifest; } internal InteractionAnimationDefinition CreateDefinition() { return new InteractionAnimationDefinition { InteractionId = InteractionId, PresentationKind = PresentationKind, ManifestJson = ManifestJson }; } } internal static class InteractionAnimationPackValidator { internal static InteractionAnimationValidationReport Validate(InteractionAnimationPackDefinition pack, out RegisteredPackSnapshot snapshot) { snapshot = null; List<InteractionAnimationValidationIssue> issues = new List<InteractionAnimationValidationIssue>(); if (pack == null) { AddError(issues, "pack_null", "$", "Pack definition is required."); return new InteractionAnimationValidationReport(issues); } RequireValue(pack.PackId, "$.PackId", "pack_id_empty", issues); RequireValue(pack.Version, "$.Version", "pack_version_empty", issues); string normalizedRoot = string.Empty; if (!InteractionAnimationAssetPathResolver.TryNormalizeAssetRoot(pack.AssetRootPath, out normalizedRoot, out var reason)) { AddError(issues, ReasonCode(reason), "$.AssetRootPath", "AssetRootPath must name an existing directory and is required for path confinement."); } Dictionary<string, RegisteredInteractionSnapshot> interactions = new Dictionary<string, RegisteredInteractionSnapshot>(StringComparer.OrdinalIgnoreCase); if (pack.Interactions == null || pack.Interactions.Length == 0) { AddError(issues, "pack_interactions_empty", "$.Interactions", "At least one interaction is required."); } else { for (int i = 0; i < pack.Interactions.Length; i++) { ValidateInteraction(pack.Interactions[i], i, interactions, issues); } } InteractionAnimationValidationReport interactionAnimationValidationReport = new InteractionAnimationValidationReport(issues); if (interactionAnimationValidationReport.IsValid) { snapshot = new RegisteredPackSnapshot(pack.PackId, pack.Version, normalizedRoot, interactions); } return interactionAnimationValidationReport; } private static void ValidateInteraction(InteractionAnimationDefinition definition, int index, IDictionary<string, RegisteredInteractionSnapshot> interactions, IList<InteractionAnimationValidationIssue> issues) { string text = "$.Interactions[" + index + "]"; if (definition == null) { AddError(issues, "interaction_null", text, "Interaction is required."); return; } RequireValue(definition.InteractionId, text + ".InteractionId", "interaction_id_empty", issues); if (!Enum.IsDefined(typeof(InteractionAnimationPresentationKind), definition.PresentationKind)) { AddError(issues, "presentation_kind_invalid", text + ".PresentationKind", "Only BodyWorld and DedicatedLocalViewmodel are supported."); } InteractionAnimationManifest manifest; InteractionAnimationValidationReport interactionAnimationValidationReport = InteractionAnimationManifestValidator.Validate(definition.ManifestJson, definition.InteractionId, definition.PresentationKind, out manifest); for (int i = 0; i < interactionAnimationValidationReport.Issues.Count; i++) { InteractionAnimationValidationIssue interactionAnimationValidationIssue = interactionAnimationValidationReport.Issues[i]; issues.Add(new InteractionAnimationValidationIssue(interactionAnimationValidationIssue.Code, text + ".ManifestJson" + interactionAnimationValidationIssue.JsonPath.Substring(1), interactionAnimationValidationIssue.Message, interactionAnimationValidationIssue.Severity)); } if (!string.IsNullOrWhiteSpace(definition.InteractionId)) { if (interactions.ContainsKey(definition.InteractionId)) { AddError(issues, "interaction_id_duplicate", text + ".InteractionId", "Interaction ids must be unique within a pack."); } else if (interactionAnimationValidationReport.IsValid && manifest != null) { interactions.Add(definition.InteractionId, new RegisteredInteractionSnapshot(definition.InteractionId, definition.PresentationKind, definition.ManifestJson ?? string.Empty, manifest)); } } } private static void RequireValue(string value, string path, string code, IList<InteractionAnimationValidationIssue> issues) { if (string.IsNullOrWhiteSpace(value) || value != value.Trim()) { AddError(issues, code, path, "A trimmed non-empty value is required."); } } private static string ReasonCode(string reason) { if (string.IsNullOrWhiteSpace(reason)) { return "pack_asset_root_invalid"; } int num = reason.IndexOf(':'); if (num < 0) { return reason; } return reason.Substring(0, num); } private static void AddError(IList<InteractionAnimationValidationIssue> issues, string code, string path, string message) { issues.Add(new InteractionAnimationValidationIssue(code, path, message, InteractionAnimationValidationSeverity.Error)); } } internal enum InteractionAnimationResourceKind { BodyAnimator, LocalCameraAndArms } internal readonly struct InteractionAnimationResourceClaim : IEquatable<InteractionAnimationResourceClaim> { internal InteractionAnimationResourceKind Kind { get; } internal object Owner { get; } internal InteractionAnimationResourceClaim(InteractionAnimationResourceKind kind, object owner) { Kind = kind; Owner = owner; } public bool Equals(InteractionAnimationResourceClaim other) { if (Kind == other.Kind) { return Owner == other.Owner; } return false; } public override bool Equals(object obj) { if (obj is InteractionAnimationResourceClaim other) { return Equals(other); } return false; } public override int GetHashCode() { return ((int)Kind * 397) ^ ((Owner != null) ? RuntimeHelpers.GetHashCode(Owner) : 0); } } internal sealed class InteractionAnimationResourceLeaseRegistry { private readonly Dictionary<InteractionAnimationResourceClaim, InteractionAnimationHandle> owners = new Dictionary<InteractionAnimationResourceClaim, InteractionAnimationHandle>(); private readonly Dictionary<InteractionAnimationHandle, InteractionAnimationResourceClaim[]> claimsByHandle = new Dictionary<InteractionAnimationHandle, InteractionAnimationResourceClaim[]>(); internal bool TryPlanAcquisition(InteractionAnimationResourceClaim[] claims, InteractionAnimationConflictPolicy policy, out InteractionAnimationHandle[] conflicts, out string reason) { reason = string.Empty; HashSet<InteractionAnimationHandle> hashSet = new HashSet<InteractionAnimationHandle>(); claims = claims ?? Array.Empty<InteractionAnimationResourceClaim>(); for (int i = 0; i < claims.Length; i++) { if (claims[i].Owner == null) { conflicts = Array.Empty<InteractionAnimationHandle>(); reason = "interaction_resource_owner_missing"; return false; } if (owners.TryGetValue(claims[i], out var value)) { hashSet.Add(value); } } conflicts = new InteractionAnimationHandle[hashSet.Count]; hashSet.CopyTo(conflicts); if (conflicts.Length != 0 && policy == InteractionAnimationConflictPolicy.RejectIfBusy) { reason = "interaction_resource_busy"; return false; } return true; } internal bool TryAcquire(InteractionAnimationHandle handle, InteractionAnimationResourceClaim[] claims, out string reason) { reason = string.Empty; if (!handle.IsValid || claimsByHandle.ContainsKey(handle)) { reason = "interaction_lease_handle_invalid"; return false; } claims = claims ?? Array.Empty<InteractionAnimationResourceClaim>(); for (int i = 0; i < claims.Length; i++) { if (claims[i].Owner == null || owners.ContainsKey(claims[i])) { reason = "interaction_resource_busy"; return false; } } InteractionAnimationResourceClaim[] array = new InteractionAnimationResourceClaim[claims.Length]; Array.Copy(claims, array, claims.Length); claimsByHandle.Add(handle, array); for (int j = 0; j < array.Length; j++) { owners.Add(array[j], handle); } return true; } internal void Release(InteractionAnimationHandle handle) { if (!claimsByHandle.TryGetValue(handle, out var value)) { return; } claimsByHandle.Remove(handle); for (int i = 0; i < value.Length; i++) { if (owners.TryGetValue(value[i], out var value2) && value2 == handle) { owners.Remove(value[i]); } } } internal bool IsOwned(InteractionAnimationResourceKind kind, object owner, out InteractionAnimationHandle handle) { return owners.TryGetValue(new InteractionAnimationResourceClaim(kind, owner), out handle); } internal void Clear() { owners.Clear(); claimsByHandle.Clear(); } } internal sealed class InteractionAnimationSession { private readonly InteractionAnimationContext context; private readonly IInteractionPresenter presenter; private readonly StartOfRound owningRound; private readonly bool wasPlayerControlled; private readonly Func<DateTime> utcNow; private readonly Func<InteractionAnimationStopReason?> invalidationResolver; private DateTime startedUtc; private DateTime exitStopAtUtc = DateTime.MaxValue; private bool active; private bool suspended; private bool ended; internal InteractionAnimationHandle Handle => context.Handle; internal PlayerControllerB Player => context.Request.Player; internal string PackId => context.Request.PackId; internal string InteractionId => context.Request.InteractionId; internal InteractionAnimationPresentationKind PresentationKind => context.Definition.PresentationKind; internal bool IsActive { get { if (active) { return !ended; } return false; } } internal bool IsSuspended { get { if (suspended) { return !ended; } return false; } } internal bool IsEnded => ended; internal bool HasResourceOwnership { get { if (active) { return presenter.HasResourceOwnership; } return false; } } internal InteractionAnimationSession(InteractionAnimationContext context, IInteractionPresenter presenter, Func<DateTime> utcNow = null, Func<InteractionAnimationStopReason?> invalidationResolver = null) { this.context = context; this.presenter = presenter; this.utcNow = utcNow ?? ((Func<DateTime>)(() => DateTime.UtcNow)); this.invalidationResolver = invalidationResolver ?? new Func<InteractionAnimationStopReason?>(GetInvalidationReason); try { owningRound = StartOfRound.Instance; } catch { owningRound = null; } try { wasPlayerControlled = context != null && context.Request?.Player?.isPlayerControlled == true; } catch { wasPlayerControlled = false; } } internal bool TryPreflight(out string reason) { reason = string.Empty; try { if (presenter == null) { reason = "presenter_missing"; return false; } return presenter.TryPreflight(context, out reason); } catch (Exception ex) { reason = "presenter_preflight_exception:" + ex.GetType().Name; ManualLogSource logger = context.Logger; if (logger != null) { logger.LogWarning((object)("[LCInteractionAnimationAPI] presenter.preflight_failed: " + ex)); } return false; } } internal bool TryStart(out string reason) { reason = string.Empty; try { if (presenter == null) { reason = "presenter_missing"; return false; } if (!presenter.TryStart(context, out reason)) { TryRestore(InteractionAnimationStopReason.PresenterFailure); return false; } startedUtc = utcNow(); exitStopAtUtc = DateTime.MaxValue; active = true; suspended = false; return true; } catch (Exception ex) { reason = "presenter_start_exception:" + ex.GetType().Name; ManualLogSource logger = context.Logger; if (logger != null) { logger.LogWarning((object)("[LCInteractionAnimationAPI] presenter.start_failed: " + ex)); } TryRestore(InteractionAnimationStopReason.PresenterFailure); return false; } } internal bool TrySuspend(out string reason) { reason = string.Empty; if (!active || ended) { return false; } try { presenter.Stop(InteractionAnimationStopReason.Interrupted); active = false; suspended = true; return true; } catch (Exception ex) { active = false; suspended = false; TryRestore(InteractionAnimationStopReason.PresenterFailure); ended = true; reason = "presenter_suspend_exception:" + ex.GetType().Name; ManualLogSource logger = context.Logger; if (logger != null) { logger.LogWarning((object)("[LCInteractionAnimationAPI] presenter.suspend_failed: " + ex)); } return false; } } internal bool TryResume(out string reason) { reason = string.Empty; if (!suspended || ended) { return false; } DateTime dateTime = startedUtc; DateTime dateTime2 = exitStopAtUtc; if (!TryPreflight(out reason) || !TryStart(out reason)) { return false; } startedUtc = dateTime; exitStopAtUtc = dateTime2; return true; } internal bool TryFinalizeSuspended() { if (!suspended || ended) { return false; } suspended = false; ended = true; return true; } internal bool TryStopAndRestore(InteractionAnimationStopReason reason) { if (ended) { return false; } if (active) { TryRestore(reason); } active = false; suspended = false; ended = true; return true; } internal InteractionAnimationStopReason? Tick(float deltaTime) { if (!active || ended) { return null; } InteractionAnimationStopReason? result = invalidationResolver(); if (result.HasValue) { return result; } try { presenter.Tick(deltaTime); } catch (Exception ex) { ManualLogSource logger = context.Logger; if (logger != null) { logger.LogWarning((object)("[LCInteractionAnimationAPI] presenter.tick_failed: " + ex)); } return InteractionAnimationStopReason.PresenterFailure; } if (presenter.RequestedStopReason.HasValue) { return presenter.RequestedStopReason; } DateTime dateTime = utcNow(); if (dateTime >= exitStopAtUtc) { return InteractionAnimationStopReason.NaturalEnd; } float durationSeconds = context.Manifest.durationSeconds; if (durationSeconds > 0f && (dateTime - startedUtc).TotalSeconds >= (double)durationSeconds) { return InteractionAnimationStopReason.NaturalEnd; } return null; } internal float BeginExit() { if (!active || presenter == null) { return 0f; } float num = Math.Max(0f, presenter.BeginExit()); exitStopAtUtc = utcNow().AddSeconds(num); return num; } internal bool TrySetAnimatorParameter(string parameterName, AnimatorControllerParameterType parameterType, float value) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (active && presenter != null) { return presenter.TrySetAnimatorParameter(parameterName, parameterType, value); } return false; } internal InteractionAnimationEndedEventArgs CreateEndedEvent(InteractionAnimationStopReason reason) { return new InteractionAnimationEndedEventArgs(Handle, Player, PackId, InteractionId, PresentationKind, reason); } private InteractionAnimationStopReason? GetInvalidationReason() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB player = Player; try { if ((Object)(object)player == (Object)null || (Object)(object)((Component)player).gameObject == (Object)null) { goto IL_0033; } Scene scene = ((Component)player).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { goto IL_0033; } if (player.isPlayerDead) { return InteractionAnimationStopReason.PlayerDied; } if (wasPlayerControlled && !player.isPlayerControlled) { return InteractionAnimationStopReason.PlayerInvalidated; } if ((Object)(object)owningRound != (Object)null && (Object)(object)StartOfRound.Instance != (Object)(object)owningRound) { return InteractionAnimationStopReason.RoundUnloaded; } goto end_IL_0007; IL_0033: return InteractionAnimationStopReason.PlayerInvalidated; end_IL_0007:; } catch { return InteractionAnimationStopReason.PlayerInvalidated; } return null; } private void TryRestore(InteractionAnimationStopReason reason) { try { presenter?.Stop(reason); } catch (Exception ex) { ManualLogSource logger = context.Logger; if (logger != null) { logger.LogWarning((object)("[LCInteractionAnimationAPI] presenter.restore_failed: " + ex)); } } } } public enum InteractionAnimationPresentationKind { DedicatedLocalViewmodel, BodyWorld } public enum InteractionAnimationConflictPolicy { RejectIfBusy, InterruptExisting } public enum InteractionAnimationStopReason { Requested, NaturalEnd, Interrupted, PlayerInvalidated, PlayerDied, RoundUnloaded, PresenterFailure, Shutdown } public readonly struct InteractionAnimationHandle : IEquatable<InteractionAnimationHandle> { private readonly Guid value; public static InteractionAnimationHandle Empty => new InteractionAnimationHandle(Guid.Empty); public bool IsValid => value != Guid.Empty; private InteractionAnimationHandle(Guid value) { this.value = value; } internal static InteractionAnimationHandle NewHandle() { return new InteractionAnimationHandle(Guid.NewGuid()); } public bool Equals(InteractionAnimationHandle other) { Guid guid = value; return guid.Equals(other.value); } public override bool Equals(object obj) { if (obj is InteractionAnimationHandle other) { return Equals(other); } return false; } public override int GetHashCode() { return value.GetHashCode(); } public override string ToString() { return value.ToString(); } public static bool operator ==(InteractionAnimationHandle left, InteractionAnimationHandle right) { return left.Equals(right); } public static bool operator !=(InteractionAnimationHandle left, InteractionAnimationHandle right) { return !left.Equals(right); } } public sealed class InteractionAnimationPackDefinition { public string PackId { get; set; } = string.Empty; public string Version { get; set; } = string.Empty; public string AssetRootPath { get; set; } = string.Empty; public InteractionAnimationDefinition[] Interactions { get; set; } = Array.Empty<InteractionAnimationDefinition>(); } public sealed class InteractionAnimationDefinition { public string InteractionId { get; set; } = string.Empty; public InteractionAnimationPresentationKind PresentationKind { get; set; } public string ManifestJson { get; set; } = string.Empty; } public sealed class InteractionAnimationRequest { public PlayerControllerB Player { get; set; } public string PackId { get; set; } = string.Empty; public string InteractionId { get; set; } = string.Empty; public InteractionAnimationConflictPolicy ConflictPolicy { get; set; } } public enum InteractionAnimationValidationSeverity { Warning, Error } public sealed class InteractionAnimationValidationIssue { public string Code { get; } public string JsonPath { get; } public string Message { get; } public InteractionAnimationValidationSeverity Severity { get; } internal InteractionAnimationValidationIssue(string code, string jsonPath, string message, InteractionAnimationValidationSeverity severity) { Code = code ?? string.Empty; JsonPath = jsonPath ?? "$"; Message = message ?? string.Empty; Severity = severity; } } public sealed class InteractionAnimationValidationReport { private readonly ReadOnlyCollection<InteractionAnimationValidationIssue> issues; public bool IsValid { get { for (int i = 0; i < issues.Count; i++) { if (issues[i].Severity == InteractionAnimationValidationSeverity.Error) { return false; } } return true; } } public IReadOnlyList<InteractionAnimationValidationIssue> Issues => issues; internal InteractionAnimationValidationReport(IList<InteractionAnimationValidationIssue> issues) { this.issues = new ReadOnlyCollection<InteractionAnimationValidationIssue>(new List<InteractionAnimationValidationIssue>(issues ?? Array.Empty<InteractionAnimationValidationIssue>())); } } public sealed class InteractionAnimationEndedEventArgs : EventArgs { public InteractionAnimationHandle Handle { get; } public PlayerControllerB Player { get; } public string PackId { get; } public string InteractionId { get; } public InteractionAnimationPresentationKind PresentationKind { get; } public InteractionAnimationStopReason StopReason { get; } internal InteractionAnimationEndedEventArgs(InteractionAnimationHandle handle, PlayerControllerB player, string packId, string interactionId, InteractionAnimationPresentationKind presentationKind, InteractionAnimationStopReason stopReason) { Handle = handle; Player = player; PackId = packId ?? string.Empty; InteractionId = interactionId ?? string.Empty; PresentationKind = presentationKind; StopReason = stopReason; } } internal sealed class InteractionAnimationContext { internal InteractionAnimationHandle Handle { get; } internal InteractionAnimationRequest Request { get; } internal InteractionAnimationDefinition Definition { get; } internal InteractionAnimationManifest Manifest { get; } internal string AssetRootPath { get; } internal ManualLogSource Logger { get; } internal InteractionAnimationContext(InteractionAnimationHandle handle, InteractionAnimationRequest request, InteractionAnimationDefinition definition, InteractionAnimationManifest manifest, string assetRootPath, ManualLogSource logger) { Handle = handle; Request = request; Definition = definition; Manifest = manifest; AssetRootPath = assetRootPath ?? string.Empty; Logger = logger; } } public static class LCInteractionAnimationAPI { private static InteractionAnimationCoordinator coordinator; public static bool IsInitialized => coordinator != null; public static event EventHandler<InteractionAnimationEndedEventArgs> InteractionEnded; public static InteractionAnimationValidationReport ValidateInteractionPack(InteractionAnimationPackDefinition pack) { RegisteredPackSnapshot snapshot; return InteractionAnimationPackValidator.Validate(pack, out snapshot); } public static InteractionAnimationValidationReport ValidateInteractionManifest(string manifestJson, string expectedInteractionId, InteractionAnimationPresentationKind presentationKind) { InteractionAnimationManifest manifest; return InteractionAnimationManifestValidator.Validate(manifestJson, expectedInteractionId, presentationKind, out manifest); } public static bool TryRegisterInteractionPack(InteractionAnimationPackDefinition pack, out string reason) { if (coordinator == null) { reason = "interaction_animation_api_not_initialized"; return false; } return coordinator.TryRegisterInteractionPack(pack, out reason); } public static bool TryStartInteraction(InteractionAnimationRequest request, out InteractionAnimationHandle handle, out string reason) { handle = InteractionAnimationHandle.Empty; if (coordinator == null) { reason = "interaction_animation_api_not_initialized"; return false; } return coordinator.TryStartInteraction(request, out handle, out reason); } public static bool TryPreloadInteractionAssets(string packId, string interactionId, out string reason) { if (coordinator == null) { reason = "interaction_animation_api_not_initialized"; return false; } return coordinator.TryPreloadInteractionAssets(packId, interactionId, out reason); } public static bool TryStopInteraction(InteractionAnimationHandle handle, InteractionAnimationStopReason stopReason) { if (coordinator != null) { return coordinator.TryStopInteraction(handle, stopReason); } return false; } public static bool IsInteractionActive(InteractionAnimationHandle handle) { if (coordinator != null) { return coordinator.IsInteractionActive(handle); } return false; } public static bool TryGetActiveInteraction(PlayerControllerB player, InteractionAnimationPresentationKind presentationKind, out InteractionAnimationHandle handle) { handle = InteractionAnimationHandle.Empty; if (coordinator != null) { return coordinator.TryGetActiveInteraction(player, presentationKind, out handle); } return false; } public static bool TrySetInteractionBool(InteractionAnimationHandle handle, string parameterName, bool value) { if (coordinator != null) { return coordinator.TrySetInteractionAnimatorParameter(handle, parameterName, (AnimatorControllerParameterType)4, value ? 1f : 0f); } return false; } public static bool TrySetInteractionInt(InteractionAnimationHandle handle, string parameterName, int value) { if (coordinator != null) { return coordinator.TrySetInteractionAnimatorParameter(handle, parameterName, (AnimatorControllerParameterType)3, value); } return false; } public static bool TrySetInteractionFloat(InteractionAnimationHandle handle, string parameterName, float value) { if (coordinator != null) { return coordinator.TrySetInteractionAnimatorParameter(handle, parameterName, (AnimatorControllerParameterType)1, value); } return false; } public static bool TryFireInteractionTrigger(InteractionAnimationHandle handle, string parameterName) { if (coordinator != null) { return coordinator.TrySetInteractionAnimatorParameter(handle, parameterName, (AnimatorControllerParameterType)9, 0f); } return false; } public static bool TryBeginInteractionExit(InteractionAnimationHandle handle, out string reason) { reason = string.Empty; if (coordinator == null) { reason = "interaction_animation_api_not_initialized"; return false; } return coordinator.TryBeginInteractionExit(handle, out reason); } internal static void Initialize(InteractionAnimationCoordinator value) { coordinator = value; } internal static void NotifyInteractionEnded(InteractionAnimationEndedEventArgs args) { Delegate[] array = LCInteractionAnimationAPI.InteractionEnded?.GetInvocationList(); if (array == null) { return; } for (int i = 0; i < array.Length; i++) { try { ((EventHandler<InteractionAnimationEndedEventArgs>)array[i])(null, args); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[LCInteractionAnimationAPI] interaction_ended_handler_failed: " + ex)); } } } } internal static void Shutdown() { coordinator = null; } } [HarmonyPatch(typeof(PlayerControllerB), "UpdatePlayerAnimationsToOtherClients")] internal static class PlayerAnimationSyncStateGuardPatch { [HarmonyPrefix] private static void EnsureAnimationStateHashCounts(PlayerControllerB __instance, ref List<int> ___currentAnimationStateHash, ref List<int> ___previousAnimationStateHash) { int? obj; if (__instance == null) { obj = null; } else { Animator playerBodyAnimator = __instance.playerBodyAnimator; obj = ((playerBodyAnimator != null) ? new int?(playerBodyAnimator.layerCount) : ((int?)null)); } int? num = obj; int valueOrDefault = num.GetValueOrDefault(); bool num2 = EnsureCount(ref ___currentAnimationStateHash, valueOrDefault); bool flag = EnsureCount(ref ___previousAnimationStateHash, valueOrDefault); if (num2 || flag) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[LCInteractionAnimationAPI] live_body.sync_state_capacity_expanded: " + $"player={__instance.playerClientId}, layers={valueOrDefault}.")); } } } internal static bool EnsureCount(ref List<int> states, int requiredCount) { if (requiredCount > 0) { List<int> obj = states; if (obj == null || obj.Count < requiredCount) { if (states == null) { states = new List<int>(requiredCount); } while (states.Count < requiredCount) { states.Add(0); } return true; } } return false; } } internal static class InteractionAnimationApiRestoreDiagnostics { internal sealed class CameraChainPoseSnapshot { private readonly Transform[] transforms; private readonly Vector3[] localPositions; private readonly string[] names; internal int Count => transforms.Length; internal string MissingTargets { get; } internal string Source { get; private set; } = "player_awake_prefix_authored_default"; private CameraChainPoseSnapshot(Transform[] transforms, Vector3[] localPositions, string[] names, string missingTargets) { this.transforms = transforms; this.localPositions = localPositions; this.names = names; MissingTargets = missingTargets; } internal bool RefinePositions(string newSource) { //IL_0020: 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) bool flag = false; for (int i = 0; i < transforms.Length; i++) { Transform val = transforms[i]; if (!((Object)(object)val == (Object)null)) { localPositions[i] = val.localPosition; flag = true; } } if (flag) { Source = newSource; } return flag; } internal static CameraChainPoseSnapshot Capture(PlayerControllerB player) { List<Transform> list = new List<Transform>(4); List<Vector3> list2 = new List<Vector3>(4); List<string> list3 = new List<string>(4); List<string> list4 = new List<string>(4); CaptureTarget("cameraContainer", SafeGet(() => player.cameraContainerTransform), list, list2, list3, list4); CaptureTarget("gameplayCamera", SafeGet(() => (!((Object)(object)player.gameplayCamera != (Object)null)) ? null : ((Component)player.gameplayCamera).transform), list, list2, list3, list4); CaptureTarget("playerModelArmsMetarig", SafeGet(() => player.playerModelArmsMetarig), list, list2, list3, list4); CaptureTarget("localArmsTransform", SafeGet(() => player.localArmsTransform), list, list2, list3, list4); return new CameraChainPoseSnapshot(list.ToArray(), list2.ToArray(), list3.ToArray(), string.Join(",", list4.ToArray())); } private static Transform SafeGet(Func<Transform> getter) { try { return getter(); } catch { return null; } } private static void CaptureTarget(string name, Transform target, List<Transform> capturedTransforms, List<Vector3> capturedPositions, List<string> capturedNames, List<string> missing) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { missing.Add(name); return; } capturedTransforms.Add(target); capturedPositions.Add(target.localPosition); capturedNames.Add(name); } internal int RestorePositions() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) int num = 0; for (int i = 0; i < transforms.Length; i++) { Transform val = transforms[i]; if (!((Object)(object)val == (Object)null)) { val.localPosition = localPositions[i]; num++; } } return num; } internal string DescribePositions() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(names.Length); for (int i = 0; i < names.Length; i++) { list.Add(names[i] + "Local=" + FormatVector(localPositions[i])); } return string.Join(" ", list.ToArray()); } } private sealed class RestoreFrameSample { internal readonly int[] LayerStateHashes; internal readonly float[] LayerNormalizedTimes; internal bool Valid; internal int Frame; internal Vector3 GameplayCameraWorldPosition; internal Vector3 CameraContainerLocalPosition; internal Vector3 CameraContainerWorldPosition; internal Vector3 ArmsMetarigWorldPosition; internal string ControllerName; internal int ActualLayerCount; internal int CapturedLayerCount; internal RestoreFrameSample(int maxAnimatorLayers) { LayerStateHashes = new int[maxAnimatorLayers]; LayerNormalizedTimes = new float[maxAnimatorLayers]; ControllerName = "<null>"; } } private sealed class RenderSeamFrameSample { internal bool Valid; internal PlayerControllerB Player; internal int Frame; internal float DeltaTime; internal float UnscaledDeltaTime; internal RenderPoseSample GameplayCamera; internal RenderPoseSample RightHand; internal RenderPoseSample LeftHand; internal RenderPoseSample ArmsMetarig; internal RenderPoseSample LocalArms; internal RenderPoseSample LocalVisor; internal RenderPoseSample LocalVisorTargetPoint; internal RenderVisibilitySample LocalVisorVisibility; internal bool VisorCameraPresent; internal bool VisorCameraEnabled; internal bool CameraParametersPresent; internal float CameraFieldOfView; internal float CameraNearClipPlane; internal RenderVisibilitySample HeldItem; internal void CopyFrom(RenderSeamFrameSample other) { if (other == null) { Reset(); return; } Valid = other.Valid; Player = other.Player; Frame = other.Frame; DeltaTime = other.DeltaTime; UnscaledDeltaTime = other.UnscaledDeltaTime; GameplayCamera = other.GameplayCamera; RightHand = other.RightHand; LeftHand = other.LeftHand; ArmsMetarig = other.ArmsMetarig; LocalArms = other.LocalArms; LocalVisor = other.LocalVisor; LocalVisorTargetPoint = other.LocalVisorTargetPoint; LocalVisorVisibility = other.LocalVisorVisibility; VisorCameraPresent = other.VisorCameraPresent; VisorCameraEnabled = other.VisorCameraEnabled; CameraParametersPresent = other.CameraParametersPresent; CameraFieldOfView = other.CameraFieldOfView; CameraNearClipPlane = other.CameraNearClipPlane; HeldItem = other.HeldItem; } internal void Reset() { Valid = false; Player = null; Frame = 0; DeltaTime = 0f; UnscaledDeltaTime = 0f; GameplayCamera = default(RenderPoseSample); RightHand = default(RenderPoseSample); LeftHand = default(RenderPoseSample); ArmsMetarig = default(RenderPoseSample); LocalArms = default(RenderPoseSample); LocalVisor = default(RenderPoseSample); LocalVisorTargetPoint = default(RenderPoseSample); LocalVisorVisibility = default(RenderVisibilitySample); VisorCameraPresent = false; VisorCameraEnabled = false; CameraParametersPresent = false; CameraFieldOfView = 0f; CameraNearClipPlane = 0f; HeldItem = default(RenderVisibilitySample); } } private sealed class RenderSeamWindow { internal readonly string Phase; internal bool Active; internal int SeamFrame; internal int EndFrame; internal int LastLoggedFrame; internal GameObject AnimatedProp; internal RenderSeamWindow(string phase) { Phase = phase; Reset(); } internal void Activate(int seamFrame, int endFrame, GameObject animatedProp) { Active = true; SeamFrame = seamFrame; EndFrame = endFrame; LastLoggedFrame = -1; AnimatedProp = animatedProp; } internal void Reset() { Active = false; SeamFrame = 0; EndFrame = 0; LastLoggedFrame = -1; AnimatedProp = null; } } private struct RenderPoseSample { internal bool Present; internal Vector3 WorldPosition; internal Vector3 WorldEulerAngles; } private struct RenderVisibilitySample { internal bool Present; internal string Name; internal bool ActiveInHierarchy; internal int RendererCount; internal int EnabledRendererCount; internal bool AnyRendererEnabled; internal bool ReadFailed; } internal sealed class ThirdPersonRigPoseSnapshot { private readonly ThirdPersonRigPoseBaseline[] baselines; internal int FullPoseCount { get; } internal int RotationOnlyCount { get; } internal int TotalCount => baselines.Length; internal bool IsComplete { get; } internal string MissingTargets { get; } internal bool PlausibleAtCapture { get; private set; } internal string Source { get; private set; } = "player_awake_prefix_authored_default"; internal void SetCaptureMetadata(bool plausibleAtCapture, string source) { PlausibleAtCapture = plausibleAtCapture; Source = source; } private ThirdPersonRigPoseSnapshot(ThirdPersonRigPoseBaseline[] baselines, int fullPoseCount, int rotationOnlyCount, string[] missingTargets) { this.baselines = baselines ?? Array.Empty<ThirdPersonRigPoseBaseline>(); FullPoseCount = fullPoseCount; RotationOnlyCount = rotationOnlyCount; IsComplete = missingTargets == null || missingTargets.Length == 0; MissingTargets = (IsComplete ? "<none>" : string.Join(",", missingTargets)); } internal static ThirdPersonRigPoseSnapshot Capture(PlayerControllerB player) { Transform val = null; try { val = (((Object)(object)player != (Object)null && (Object)(object)player.playerBodyAnimator != (Object)null) ? ((Component)player.playerBodyAnimator).transform : null); } catch { } if ((Object)(object)val == (Object)null) { return null; } Transform parent = FindChildRecursive(val, "spine.003"); Transform parent2 = FindChildRecursive(val, "Rig 1"); Transform val2 = FindDirectChild(parent2, "LeftLeg"); Transform val3 = FindDirectChild(parent2, "RightLeg"); List<ThirdPersonRigPoseBaseline> list = new List<ThirdPersonRigPoseBaseline>(12); HashSet<Transform> capturedTransforms = new HashSet<Transform>(); List<string> list2 = new List<string>(10); AddFullPose(FindDirectChild(parent, "LeftArm_target"), "spine.003/LeftArm_target", list, capturedTransforms, list2); AddFullPose(FindDirectChild(parent, "RightArm_target"), "spine.003/RightArm_target", list, capturedTransforms, list2); AddControlGroup(val2, "Rig 1/LeftLeg", new string[2] { "LeftLeg_hint", "LeftLeg_target" }, list, capturedTransforms, list2); AddControlGroup(val3, "Rig 1/RightLeg", new string[2] { "RightLeg_hint", "RightLeg_target" }, list, capturedTransforms, list2); AddRotationOnly(FindChildRecursive(val, "shin.L"), "spine/thigh.L/shin.L", list, capturedTransforms, list2); AddRotationOnly(FindChildRecursive(val, "shin.R"), "spine/thigh.R/shin.R", list, capturedTransforms, list2); int num = 0; int num2 = 0; for (int i = 0; i < list.Count; i++) { if (list[i].RotationOnly) { num2++; } else { num++; } } return new ThirdPersonRigPoseSnapshot(list.ToArray(), num, num2, list2.ToArray()); } private static void AddControlGroup(Transform group, string groupPath, string[] requiredChildren, ICollection<ThirdPersonRigPoseBaseline> captured, ISet<Transform> capturedTransforms, ICollection<string> missing) { if ((Object)(object)group == (Object)null) { missing.Add(groupPath); for (int i = 0; i < requiredChildren.Length; i++) { missing.Add(groupPath + "/" + requiredChildren[i]); } return; } Transform[] componentsInChildren = ((Component)group).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { string relativePath = GetRelativePath(group, val); string path = ((group == val) ? groupPath : (groupPath + relativePath.Substring(((Object)group).name.Length))); AddFullPose(val, path, captured, capturedTransforms, null); } foreach (string text in requiredChildren) { if ((Object)(object)FindDirectChild(group, text) == (Object)null) { missing.Add(groupPath + "/" + text); } } } private static void AddFullPose(Transform transform, string path, ICollection<ThirdPersonRigPoseBaseline> captured, ISet<Transform> capturedTransforms, ICollection<string> missing) { if ((Object)(object)transform == (Object)null) { missing?.Add(path); } else if (capturedTransforms.Add(transform)) { captured.Add(new ThirdPersonRigPoseBaseline(transform, path, rotationOnly: false)); } } private static void AddRotationOnly(Transform transform, string path, ICollection<ThirdPersonRigPoseBaseline> captured, ISet<Transform> capturedTransforms, ICollection<string> missing) { if ((Object)(object)transform == (Object)null) { missing.Add(path); } else if (capturedTransforms.Add(transform)) { captured.Add(new ThirdPersonRigPoseBaseline(transform, path, rotationOnly: true)); } } internal ThirdPersonRigPlausibility EvaluateVanillaRestPlausibility() { //IL_004f: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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 num = 0; int num2 = 0; int num3 = 0; float num4 = 0f; float num5 = 0f; float num6 = 0f; bool flag = false; for (int i = 0; i < baselines.Length; i++) { ThirdPersonRigPoseBaseline thirdPersonRigPoseBaseline = baselines[i]; if (!thirdPersonRigPoseBaseline.HasExpectedVanillaRest) { continue; } if (!thirdPersonRigPoseBaseline.Finite) { flag = true; continue; } float num7 = Quaternion.Angle(thirdPersonRigPoseBaseline.ExpectedLocalRotation, thirdPersonRigPoseBaseline.LocalRotation); num5 = Mathf.Max(num5, num7); if (num7 > 8f) { num2++; } if (!thirdPersonRigPoseBaseline.RotationOnly) { float num8 = Vector3.Distance(thirdPersonRigPoseBaseline.ExpectedLocalPosition, thirdPersonRigPoseBaseline.LocalPosition); float num9 = Vector3.Distance(thirdPersonRigPoseBaseline.ExpectedLocalScale, thirdPersonRigPoseBaseline.LocalScale); num4 = Mathf.Max(num4, num8); num6 = Mathf.Max(num6, num9); if (num8 > 0.05f) { num++; } if (num9 > 0.01f) { num3++; } } } bool flag2 = IsComplete && !flag && num == 0 && num2 == 0 && num3 == 0; string reason = ((!IsComplete) ? "required_transforms_missing" : (flag ? "non_finite_local_pose" : (flag2 ? "within_vanilla_rest_thresholds" : "outside_vanilla_rest_thresholds"))); return new ThirdPersonRigPlausibility(flag2, reason, num, num2, num3, num4, num5, num6); } internal void RestoreExcept(ISet<Transform> excludedTransforms, ISet<Transform> restoredTransforms, out int fullPoseRestored, out int rotationOnlyRestored) { fullPoseRestored = 0; rotationOnlyRestored = 0; for (int i = 0; i < baselines.Length; i++) { ThirdPersonRigPoseBaseline thirdPersonRigPoseBaseline = baselines[i]; Transform transform = thirdPersonRigPoseBaseline.Transform; if (!((Object)(object)transform == (Object)null) && (excludedTransforms == null || !excludedTransforms.Contains(transform)) && thirdPersonRigPoseBaseline.Restore()) { restoredTransforms?.Add(transform); if (thirdPersonRigPoseBaseline.RotationOnly) { rotationOnlyRestored++; } else { fullPoseRestored++; } } } } } private sealed class ThirdPersonRigPoseBaseline { internal Transform Transform { get; } internal string Path { get; } internal bool RotationOnly { get; } internal Vector3 LocalPosition { get; } internal Quaternion LocalRotation { get; } internal Vector3 LocalScale { get; } internal bool HasExpectedVanillaRest { get; } internal Vector3 ExpectedLocalPosition { get; } internal Quaternion ExpectedLocalRotation { get; } internal Vector3 ExpectedLocalScale { get; } internal bool Finite { get { //IL_0001: 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_001b: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(LocalPosition) && IsFinite(LocalRotation)) { return IsFinite(LocalScale); } return false; } } internal ThirdPersonRigPoseBaseline(Transform transform, string path, bool rotationOnly) { //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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //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_0052: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) Transform = transform; Path = path; RotationOnly = rotationOnly; LocalPosition = transform.localPosition; LocalRotation = transform.localRotation; LocalScale = transform.localScale; HasExpectedVanillaRest = TryGetExpectedVanillaRest(path, out var localPosition, out var localRotation, out var localScale); ExpectedLocalPosition = localPosition; ExpectedLocalRotation = localRotation; ExpectedLocalScale = localScale; } internal bool Restore() { //IL_0041: 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_0030: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Transform == (Object)null) { return false; } if (!RotationOnly) { Transform.localPosition = LocalPosition; Transform.localScale = LocalScale; } Transform.localRotation = LocalRotation; return true; } private static bool TryGetExpectedVanillaRest(string path, out Vector3 localPosition, out Quaternion localRotation, out Vector3 localScale) { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_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_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: 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_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_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_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) localPosition = Vector3.zero; localRotation = Quaternion.identity; localScale = Vector3.one; switch (path) { case "spine.003/LeftArm_target": localPosition = new Vector3(-1.045884f, -0.057756394f, -0.044099636f); localRotation = new Quaternion(-0.78043324f, 0.6235791f, 0.028422598f, 0.03557171f); return true; case "spine.003/RightArm_target": localPosition = new Vector3(1.0641153f, -0.06609607f, -0.030803302f); localRotation = new Quaternion(-0.7733263f, -0.6323711f, -0.028823216f, 0.0352481f); return true; case "Rig 1/LeftLeg": case "Rig 1/RightLeg": localPosition = new Vector3(-9.584f, 0f, -11.081f); return true; case "Rig 1/LeftLeg/LeftLeg_hint": localPosition = new Vector3(1.001f, 0.746f, 2.4f); return true; case "Rig 1/LeftLeg/LeftLeg_target": localPosition = new Vector3(0.99f, 0.209f, 1.011f); localRotation = new Quaternion(0.89385676f, -1.803443E-06f, -1.1043475E-06f, 0.4483527f); return true; case "Rig 1/RightLeg/RightLeg_hint": localPosition = new Vector3(1.486f, 0.658f, 2.823f); return true; case "Rig 1/RightLeg/RightLeg_target": localPosition = new Vector3(1.436f, 0.27f, 1.058f); localRotation = new Quaternion(0.89385664f, 3.9951823E-07f, -6.130153E-08f, 0.44835275f); return true; case "spine/thigh.L/shin.L": localRotation = new Quaternion(0.036354546f, -0.0022051183f, -0.008516384f, 0.99930024f); return true; case "spine/thigh.R/shin.R": localRotation = new Quaternion(0.036352716f, 0.002243982f, 0.008508066f, 0.9993003f); return true; default: return false; } } private static bool IsFinite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(value.x) && IsFinite(value.y)) { return IsFinite(value.z); } return false; } private static bool IsFinite(Quaternion value) { //IL_0000: 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_001a: 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 (IsFinite(value.x) && IsFinite(value.y) && IsFinite(value.z)) { return IsFinite(value.w); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal readonly struct ThirdPersonRigPlausibility { internal bool Plausible { get; } internal string Reason { get; } internal int PositionOutliers { get; } internal int RotationOutliers { get; } internal int ScaleOutliers { get; } internal float MaxPositionDelta { get; } internal float MaxRotationDeltaDegrees { get; } internal float MaxScaleDelta { get; } internal ThirdPersonRigPlausibility(bool plausible, string reason, int positionOutliers, int rotationOutliers, int scaleOutliers, float maxPositionDelta, float maxRotationDeltaDegrees, float maxScaleDelta) { Plausible = plausible; Reason = reason; PositionOutliers = positionOutliers; RotationOutliers = rotationOutliers; ScaleOutliers = scaleOutliers; MaxPositionDelta = maxPositionDelta; MaxRotationDeltaDegrees = maxRotationDeltaDegrees; MaxScaleDelta = maxScaleDelta; } } private sealed class RemoteRigProbeSchedule { internal PlayerControllerB Player { get; } internal int ProbeId { get; } internal int RestoreFrame { get; } internal float FiveSecondRealtime { get; } internal int LateUpdatesRemaining { get; set; } internal bool LateUpdateSampleLogged { get; set; } internal bool FiveSecondSampleLogged { get; set; } internal RemoteRigProbeSchedule(PlayerControllerB player, int probeId, int restoreFrame, float fiveSecondRealtime) { Player = player; ProbeId = probeId; RestoreFrame = restoreFrame; FiveSecondRealtime = fiveSecondRealtime; LateUpdatesRemaining = 2; } } private sealed class PristineRigSnapshot { internal readonly PlayerControllerB Player; internal readonly TransformBaseline[] Transforms; internal readonly TwoBoneIkBaseline[] TwoBoneConstraints; internal readonly ChainIkBaseline[] ChainConstraints; internal readonly RigWeightBaseline[] Rigs; internal readonly RigLayerBaseline[] RigLayers; private PristineRigSnapshot(PlayerControllerB player, TransformBaseline[] transforms, TwoBoneIkBaseline[] twoBoneConstraints, ChainIkBaseline[] chainConstraints, RigWeightBaseline[] rigs, RigLayerBaseline[] rigLayers) { Player = player; Transforms = transforms; TwoBoneConstraints = twoBoneConstraints; ChainConstraints = chainConstraints; Rigs = rigs; RigLayers = rigLayers; } internal static PristineRigSnapshot Capture(PlayerControllerB player, Transform metarig, Transform rigArms, Type twoBoneIkConstraintType, Type chainIkConstraintType) { Transform[] componentsInChildren = ((Component)rigArms).GetComponentsInChildren<Transform>(true); TransformBaseline[] array = new TransformBaseline[componentsInChildren.Length + 1]; array[0] = new TransformBaseline(metarig, ((Object)metarig).name + " (metarig root)"); for (int i = 0; i < componentsInChildren.Length; i++) { Transform transform = componentsInChildren[i]; array[i + 1] = new TransformBaseline(transform, GetRelativePath(metarig, transform)); } Component[] componentsInChildren2 = ((Component)metarig).GetComponentsInChildren<Component>(true); List<TwoBoneIkBaseline> list = new List<TwoBoneIkBaseline>(); List<ChainIkBaseline> list2 = new List<ChainIkBaseline>(); List<RigWeightBaseline> list3 = new List<RigWeightBaseline>(); List<RigLayerBaseline> list4 = new List<RigLayerBaseline>(); foreach (Component val in componentsInChildren2) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); string? a = type.FullName ?? type.Name; string relativePath = GetRelativePath(metarig, val.transform); if (twoBoneIkConstraintType != null && twoBoneIkConstraintType.IsAssignableFrom(type)) { list.Add(new TwoBoneIkBaseline(val, relativePath)); } if (chainIkConstraintType != null && chainIkConstraintType.IsAssignableFrom(type)) { list2.Add(new ChainIkBaseline(val, relativePath)); } if (string.Equals(a, "UnityEngine.Animations.Rigging.Rig", StringComparison.Ordinal)) { list3.Add(new RigWeightBaseline(val, relativePath)); } if (!string.Equals(a, "UnityEngine.Animations.Rigging.RigBuilder", StringComparison.Ordinal) || !(ReadMember(val, "layers", "m_RigLayers") is IList list5)) { continue; } for (int k = 0; k < list5.Count; k++) { object obj = list5[k]; if (obj != null) { list4.Add(new RigLayerBaseline(obj, relativePath + "/layer[" + k.ToString(CultureInfo.InvariantCulture) + "]")); } } } return new PristineRigSnapshot(player, array, list.ToArray(), list2.ToArray(), list3.ToArray(), list4.ToArray()); } internal int RestoreRigControlPose(Transform rigArms, ISet<Transform> restoredTransforms) { int num = 0; for (int i = 0; i < Transforms.Length; i++) { TransformBaseline transformBaseline = Transforms[i]; Transform transform = transformBaseline.Transform; if (!((Object)(object)transform == (Object)null) && (transform == rigArms || transform.IsChildOf(rigArms))) { transformBaseline.Restore(); restoredTransforms.Add(transform); num++; } } return num; } } private sealed class TransformBaseline { internal readonly Transform Transform; internal readonly string Path; internal readonly Vector3 LocalPosition; internal readonly Quaternion LocalRotation; internal readonly Vector3 LocalScale; internal TransformBaseline(Transform transform, string path) { //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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_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) Transform = transform; Path = path; LocalPosition = transform.localPosition; LocalRotation = transform.localRotation; LocalScale = transform.localScale; } internal void Restore() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) Transform.localPosition = LocalPosition; Transform.localRotation = LocalRotation; Transform.localScale = LocalScale; } } private readonly struct TwoBoneIkValues : IEquatable<TwoBoneIkValues> { internal readonly string TargetName; internal readonly string HintName; internal readonly float Weight; internal readonly float TargetPositionWeight; internal readonly float TargetRotationWeight; internal readonly float HintWeight; internal readonly bool MaintainTargetPositionOffset; internal readonly bool MaintainTargetRotationOffset; internal TwoBoneIkValues(Component component) { object instance = ReadMember(component, null, "m_Data"); TargetName = ReadObjectName(instance, "target", "m_Target"); HintName = ReadObjectName(instance, "hint", "m_Hint"); Weight = ReadFloat(component, "weight", "m_Weight"); TargetPositionWeight = ReadFloat(instance, "targetPositionWeight", "m_TargetPositionWeight"); TargetRotationWeight = ReadFloat(instance, "targetRotationWeight", "m_TargetRotationWeight"); HintWeight = ReadFloat(instance, "hintWeight", "m_HintWeight"); MaintainTargetPositionOffset = ReadBool(instance, "maintainTargetPositionOffset", "m_MaintainTargetPositionOffset"); MaintainTargetRotationOffset = ReadBool(instance, "maintainTargetRotationOffset", "m_MaintainTargetRotationOffset"); } public bool Equals(TwoBoneIkValues other) { if (string.Equals(TargetName, other.TargetName, StringComparison.Ordinal) && string.Equals(HintName, other.HintName, StringComparison.Ordinal) && Weight.Equals(other.Weight) && TargetPositionWeight.Equals(other.TargetPositionWeight) && TargetRotationWeight.Equals(other.TargetRotationWeight) && HintWeight.Equals(other.HintWeight) && MaintainTargetPositionOffset == other.MaintainTargetPositionOffset) { return MaintainTargetRotationOffset == other.MaintainTargetRotationOffset; } return false; } } private sealed class TwoBoneIkBaseline { private readonly Component component; internal readonly string Path; internal readonly TwoBoneIkValues Values; internal TwoBoneIkBaseline(Component component, string path) { this.component = component; Path = path; Values = new TwoBoneIkValues(component); } internal bool TryReadCurrent(out TwoBoneIkValues current) { if ((Object)(object)component == (Object)null) { current = default(TwoBoneIkValues); return false; } current = new TwoBoneIkValues(component); return true; } } private readonly struct ChainIkValues : IEquatable<ChainIkValues> { internal readonly string RootName; internal readonly string TipName; internal readonly string TargetName; internal readonly float Weight; internal readonly float ChainRotationWeight; internal readonly float TipRotationWeight; internal readonly int MaxIterations; internal readonly float Tolerance; internal readonly bool MaintainTargetPositionOffset; internal readonly bool MaintainTargetRotationOffset; internal ChainIkValues(Component component) { object instance = ReadMember(component, null, "m_Data"); RootName = ReadObjectName(instance, "root", "m_Root"); TipName = ReadObjectName(instance, "tip", "m_Tip"); TargetName = ReadObjectName(instance, "target", "m_Target"); Weight = ReadFloat(component, "weight", "m_Weight"); ChainRotationWeight = ReadFloat(instance, "chainRotationWeight", "m_ChainRotationWeight"); TipRotationWeight = ReadFloat(instance, "tipRotationWeight", "m_TipRotationWeight"); MaxIterations = ReadInt(instance, "maxIterations", "m_MaxIterations"); Tolerance = ReadFloat(instance, "tolerance", "m_Tolerance"); MaintainTargetPositionOffset = ReadBool(instance, "maintainTargetPositionOffset", "m_MaintainTargetPositionOffset"); MaintainTargetRotationOffset = ReadBool(instance, "maintainTargetRotationOffset", "m_MaintainTargetRotationOffset"); } public bool Equals(ChainIkValues other) { if (string.Equals(RootName, other.RootName, StringComparison.Ordinal) && string.Equals(TipName, other.TipName, StringComparison.Ordinal) && string.Equals(TargetName, other.TargetName, StringComparison.Ordinal) && Weight.Equals(other.Weight) && ChainRotationWeight.Equals(other.ChainRotationWeight) && TipRotationWeight.Equals(other.TipRotationWeight) && MaxIterations == other.MaxIterations && Tolerance.Equals(other.Tolerance) && MaintainTargetPositionOffset == other.MaintainTargetPositionOffset) { return MaintainTargetRotationOffset == other.MaintainTargetRotationOffset; } return false; } } private