Decompiled source of ASKA Fox v0.6.3
BepInEx/plugins/AskaFox/AskaFox.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Cinemachine; using Fusion; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using Microsoft.CodeAnalysis; using SSSGame; using SSSGame.Combat; using SSSGame.Controllers; using SSSGame.Localization; using SSSGame.Network; using SSSGame.UI; using SSSGame.Water; using SandSailorStudio; using SandSailorStudio.Attributes; using SandSailorStudio.Inventory; using SandSailorStudio.Parameters; using SandSailorStudio.Storage; using SandSailorStudio.UI; using SandSailorStudio.Utils; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("AskaFox")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AskaFox")] [assembly: AssemblyTitle("AskaFox")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace AskaWolfPrototype { internal sealed class AnimalCarryVisuals { private sealed class Display { internal GameObject Source; internal GameObject Root; internal Transform Parent; internal Vector3 Center; internal Vector3 SourceScale; internal bool Tool; internal float RetryAfter; internal readonly List<(Renderer source, Renderer copy, bool hidden)> Parts = new List<(Renderer, Renderer, bool)>(); internal readonly List<Mesh> Baked = new List<Mesh>(); } private readonly Dictionary<int, Display> _shown = new Dictionary<int, Display>(); private readonly Dictionary<int, GameObject> _wanted = new Dictionary<int, GameObject>(); private readonly HashSet<int> _tools = new HashSet<int>(); private readonly List<int> _remove = new List<int>(); private readonly List<ItemPrefabStackSlot> _slots = new List<ItemPrefabStackSlot>(); private float _nextScan; private static bool Same(ItemContainer a, ItemContainer b) { if (a != null && b != null) { return ((Il2CppObjectBase)a).Pointer == ((Il2CppObjectBase)b).Pointer; } return false; } private static bool Below(Transform child, Transform root) { if ((Object)(object)child != (Object)null && (Object)(object)root != (Object)null) { if (!((Object)(object)child == (Object)(object)root)) { return child.IsChildOf(root); } return true; } return false; } private static bool Restricted(ItemContainer container, CharacterInventory inventory, ItemContainerComponent target = null) { if (container != null) { if (!Same(container, (inventory != null) ? inventory.RestrictedCarryContainer : null)) { ItemContainerType containerType = container.containerType; if (containerType != null) { CharacterItemContainerType obj = ((Il2CppObjectBase)containerType).TryCast<CharacterItemContainerType>(); if (((obj != null) ? new bool?(obj.restrictedCarry) : ((bool?)null)) == true) { goto IL_005f; } } return (Object)(object)((target != null) ? ((Il2CppObjectBase)target).TryCast<CharacterCarrySlot>() : null) != (Object)null; } goto IL_005f; } return false; IL_005f: return true; } internal bool Contains(GameObject item) { if ((Object)(object)item != (Object)null) { return _wanted.ContainsKey(((Object)item).GetInstanceID()); } return false; } internal bool Owns(Renderer renderer) { foreach (Display value in _shown.Values) { if ((Object)(object)value.Source != (Object)null && (Object)(object)renderer != (Object)null && Below(((Component)renderer).transform, value.Source.transform)) { return true; } } return false; } internal unsafe void Refresh(Character player, GameObject geometry, EquipmentManager equipment, WolfVisual visual, Action<GameObject> exclude, Action<GameObject> releaseVisibility) { //IL_0595: Unknown result type (might be due to invalid IL or missing references) //IL_059a: Unknown result type (might be due to invalid IL or missing references) _wanted.Clear(); _tools.Clear(); InventoryComponent inventory = player.Inventory; CharacterInventory inventory2 = ((inventory != null) ? ((Il2CppObjectBase)inventory).TryCast<CharacterInventory>() : null); PlayerCharacter val = ((Il2CppObjectBase)player).TryCast<PlayerCharacter>(); Villager val2 = ((Il2CppObjectBase)player).TryCast<Villager>(); PlayerInteractionAgent val3 = (((Object)(object)val == (Object)null) ? null : FoxCoop.Agent(val)); if ((Object)(object)val2 == (Object)null) { if (!((Object)(object)val3 == (Object)null)) { PlayerCharacter character = val3.GetCharacter(); if (((character != null) ? new int?(((Object)character).GetInstanceID()) : ((int?)null)) == ((Object)player).GetInstanceID()) { goto IL_00a4; } } Release(releaseVisibility); return; } goto IL_00a4; IL_00a4: Transform root = (((Object)(object)val2 != (Object)null) ? val2.GetGrabbingHand() : val3.grabbingHand); Transform root2 = (((Object)(object)val2 != (Object)null) ? val2.GetGrabbingOffHand() : val3.grabbingOffHand); if (Time.unscaledTime >= _nextScan) { _nextScan = Time.unscaledTime + 0.5f; _slots.Clear(); HashSet<int> hashSet = new HashSet<int>(); GameObject[] array = (GameObject[])(object)new GameObject[2] { ((Component)player).gameObject, geometry }; foreach (GameObject val4 in array) { if (!((Object)(object)val4 != (Object)null)) { continue; } foreach (ItemPrefabStackSlot componentsInChild in val4.GetComponentsInChildren<ItemPrefabStackSlot>(true)) { if (hashSet.Add(((Object)componentsInChild).GetInstanceID())) { _slots.Add(componentsInChild); } } } } foreach (ItemPrefabStackSlot slot in _slots) { if ((Object)(object)slot == (Object)null || slot._instances == null || !Restricted(((ItemDisplaySlot)slot)._container, inventory2, ((ItemDisplaySlot)slot).target)) { continue; } Enumerator<DisplayStack> enumerator3 = slot._instances.GetEnumerator(); while (enumerator3.MoveNext()) { DisplayStack current3 = enumerator3.Current; if (((current3 != null) ? current3.item : null) != null && current3.item.count > 0 && Same(current3.item.Container, ((ItemDisplaySlot)slot)._container)) { Want(current3.gameObject); } } } if (((equipment != null) ? equipment.equipPoints : null) != null) { Enumerator<EquipPoint> enumerator4 = equipment.equipPoints.GetEnumerator(); while (enumerator4.MoveNext()) { EquipPoint current4 = enumerator4.Current; EquipmentItem val5 = ((current4 != null) ? current4.GetCurrentItem() : null); if (val5 == null || !val5.IsEquipped() || ((Item)val5).count <= 0) { continue; } bool flag = false; List<EquipPoint> activePoints = val5.GetActivePoints(); if (activePoints != null) { Enumerator<EquipPoint> enumerator5 = activePoints.GetEnumerator(); while (enumerator5.MoveNext()) { EquipPoint current5 = enumerator5.Current; if (current5 != null && ((Il2CppObjectBase)current5).Pointer == ((Il2CppObjectBase)current4).Pointer) { flag = true; break; } } } if (!flag) { continue; } GameObject val6 = val5.GetObject(); bool flag2 = Below(current4.handle, root) || Below(current4.handle, root2) || Below((val6 != null) ? val6.transform.parent : null, root) || Below((val6 != null) ? val6.transform.parent : null, root2); if (!flag2 && ((val3 != null) ? val3.lockableEquipmentIds : null) != null) { Enumerator<EquipHandleId> enumerator6 = val3.lockableEquipmentIds.GetEnumerator(); while (enumerator6.MoveNext()) { EquipHandleId current6 = enumerator6.Current; if (current4.HasId(current6)) { flag2 = true; break; } } } bool flag3 = Restricted(((Item)val5).Container, inventory2); if (flag2 || flag3) { Want(val6, !flag3); } } } _remove.Clear(); foreach (KeyValuePair<int, Display> item in _shown) { if (!_wanted.ContainsKey(item.Key) || NeedsRefresh(item.Value, _tools.Contains(item.Key))) { Dispose(item.Value, releaseVisibility); _remove.Add(item.Key); } } foreach (int item2 in _remove) { _shown.Remove(item2); } foreach (KeyValuePair<int, GameObject> item3 in _wanted) { exclude(item3.Value); if (!_shown.ContainsKey(item3.Key)) { Display display = Create(item3.Value, visual.Root.transform, _tools.Contains(item3.Key)); _shown.Add(item3.Key, display); ManualLogSource logger = Plugin.Logger; string[] obj = new string[8] { "Animal continuous mouth display: ", ((Object)item3.Value).name, "; mesh parts=", display.Parts.Count.ToString(), "; tool=", display.Tool.ToString(), "; source scale=", null }; Vector3 sourceScale = display.SourceScale; obj[7] = ((object)(*(Vector3*)(&sourceScale))/*cast due to .constrained prefix*/).ToString(); logger.LogInfo((object)string.Concat(obj)); } } } private static bool ValidScale(Vector3 scale) { //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) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (float.IsFinite(scale.x) && float.IsFinite(scale.y) && float.IsFinite(scale.z) && Mathf.Abs(scale.x) > 1E-05f && Mathf.Abs(scale.y) > 1E-05f) { return Mathf.Abs(scale.z) > 1E-05f; } return false; } private void Want(GameObject obj, bool tool = false) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)obj == (Object)null) && obj.activeInHierarchy && ValidScale(obj.transform.lossyScale)) { int instanceID = ((Object)obj).GetInstanceID(); _wanted[instanceID] = obj; if (tool) { _tools.Add(instanceID); } } } private static bool NeedsRefresh(Display d, bool tool) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)d.Source == (Object)null || (Object)(object)d.Root == (Object)null || (Object)(object)d.Source.transform.parent != (Object)(object)d.Parent || d.Tool != tool) { return true; } Vector3 val = d.Source.transform.lossyScale - d.SourceScale; if (((Vector3)(ref val)).sqrMagnitude > 1E-05f) { return true; } if (d.Parts.Count == 0) { return Time.unscaledTime >= d.RetryAfter; } foreach (var part in d.Parts) { if ((Object)(object)part.source == (Object)null || (Object)(object)part.copy == (Object)null) { return true; } } return false; } private static Display Create(GameObject source, Transform parent, bool tool) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: 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_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) Display display = new Display { Source = source, Parent = source.transform.parent, Tool = tool, SourceScale = source.transform.lossyScale, RetryAfter = Time.unscaledTime + 0.25f, Root = new GameObject("Animal mouth held visual") }; try { Transform transform = display.Root.transform; transform.position = source.transform.position; transform.rotation = source.transform.rotation; transform.localScale = display.SourceScale; bool flag = true; Bounds val = default(Bounds); foreach (Renderer componentsInChild in source.GetComponentsInChildren<Renderer>(true)) { if (tool && !ValidScale(((Component)componentsInChild).transform.lossyScale)) { continue; } MeshFilter component = ((Component)componentsInChild).GetComponent<MeshFilter>(); Mesh val2 = ((component != null) ? component.sharedMesh : null); SkinnedMeshRenderer val3 = ((Il2CppObjectBase)componentsInChild).TryCast<SkinnedMeshRenderer>(); if ((Object)(object)val2 == (Object)null && (Object)(object)val3 != (Object)null) { val2 = new Mesh(); val3.BakeMesh(val2); display.Baked.Add(val2); } if (!((Object)(object)val2 == (Object)null)) { GameObject val4 = new GameObject(((Object)((Component)componentsInChild).gameObject).name + " mouth visual") { layer = (tool ? ((Component)parent).gameObject.layer : ((Component)componentsInChild).gameObject.layer) }; val4.transform.position = ((Component)componentsInChild).transform.position; val4.transform.rotation = ((Component)componentsInChild).transform.rotation; val4.transform.localScale = ((Component)componentsInChild).transform.lossyScale; val4.transform.SetParent(transform, true); val4.AddComponent<MeshFilter>().sharedMesh = val2; MeshRenderer val5 = val4.AddComponent<MeshRenderer>(); ((Renderer)val5).sharedMaterials = componentsInChild.sharedMaterials; ((Renderer)val5).shadowCastingMode = componentsInChild.shadowCastingMode; ((Renderer)val5).receiveShadows = componentsInChild.receiveShadows; display.Parts.Add((componentsInChild, (Renderer)(object)val5, componentsInChild.forceRenderingOff)); if (flag) { val = ((Renderer)val5).bounds; flag = false; } else { ((Bounds)(ref val)).Encapsulate(((Renderer)val5).bounds); } } } display.Center = (flag ? Vector3.zero : transform.InverseTransformPoint(((Bounds)(ref val)).center)); transform.SetParent(parent, true); return display; } catch { Dispose(display, null); throw; } } internal void Place(Transform mouth) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) foreach (Display value in _shown.Values) { if ((Object)(object)value.Root == (Object)null || (Object)(object)value.Source == (Object)null || (Object)(object)mouth == (Object)null) { continue; } value.Root.transform.rotation = mouth.rotation * Quaternion.Euler(0f, (float)(value.Tool ? 90 : 180), 0f); value.Root.transform.position = mouth.position - value.Root.transform.TransformVector(value.Center); foreach (var part in value.Parts) { if ((Object)(object)part.source != (Object)null && (Object)(object)part.copy != (Object)null) { part.copy.enabled = value.Tool || (part.source.enabled && ((Component)part.source).gameObject.activeInHierarchy); part.copy.forceRenderingOff = false; part.source.forceRenderingOff = true; } } } } private static void Dispose(Display d, Action<GameObject> releaseVisibility) { if ((Object)(object)d.Source != (Object)null) { foreach (var part in d.Parts) { if ((Object)(object)part.source != (Object)null) { part.source.forceRenderingOff = part.hidden; } } releaseVisibility?.Invoke(d.Source); } if ((Object)(object)d.Root != (Object)null) { Object.Destroy((Object)(object)d.Root); } foreach (Mesh item in d.Baked) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } } internal void Release(Action<GameObject> releaseVisibility) { foreach (Display value in _shown.Values) { Dispose(value, releaseVisibility); } _shown.Clear(); _wanted.Clear(); _tools.Clear(); _slots.Clear(); _nextScan = 0f; } } internal sealed class AnimalHeldItem { private GameObject _item; private Transform _parent; private Vector3 _localPosition; private Vector3 _center; private Quaternion _localRotation; private readonly List<(Renderer renderer, bool hidden)> _renderers = new List<(Renderer, bool)>(); internal bool Owns(Renderer renderer) { if ((Object)(object)_item != (Object)null && (Object)(object)renderer != (Object)null) { if (!((Object)(object)((Component)renderer).gameObject == (Object)(object)_item)) { return ((Component)renderer).transform.IsChildOf(_item.transform); } return true; } return false; } internal bool Observe(GameObject item) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_item == (Object)(object)item) { return false; } Release(); if ((Object)(object)item == (Object)null) { return false; } _item = item; Transform transform = item.transform; _parent = transform.parent; _localPosition = transform.localPosition; _localRotation = transform.localRotation; bool flag = true; Bounds val = default(Bounds); foreach (Renderer componentsInChild in item.GetComponentsInChildren<Renderer>(true)) { _renderers.Add((componentsInChild, componentsInChild.forceRenderingOff)); if (flag) { val = componentsInChild.bounds; flag = false; } else { ((Bounds)(ref val)).Encapsulate(componentsInChild.bounds); } } _center = (flag ? Vector3.zero : transform.InverseTransformPoint(((Bounds)(ref val)).center)); Plugin.Logger.LogInfo((object)("Animal temporary item attached: " + ((Object)item).name)); return true; } internal void Place(Transform socket, float yaw = 90f) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_item == (Object)null || (Object)(object)socket == (Object)null) { return; } if ((Object)(object)_item.transform.parent != (Object)(object)_parent) { Release(); return; } Transform transform = _item.transform; transform.rotation = socket.rotation * Quaternion.Euler(0f, yaw, 0f); transform.position = socket.position - transform.TransformVector(_center); foreach (var renderer in _renderers) { if ((Object)(object)renderer.renderer != (Object)null) { renderer.renderer.forceRenderingOff = false; } } } internal void Release(bool hide = false) { //IL_003c: 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) bool flag = (Object)(object)_item != (Object)null && (Object)(object)_item.transform.parent == (Object)(object)_parent; if (flag) { _item.transform.localPosition = _localPosition; _item.transform.localRotation = _localRotation; } foreach (var renderer in _renderers) { if (flag && (Object)(object)renderer.renderer != (Object)null) { renderer.renderer.forceRenderingOff = hide || renderer.hidden; } } _renderers.Clear(); _item = null; _parent = null; } } [HarmonyPatch] internal static class AnimalHandSpawnHook { private static IEnumerable<MethodBase> TargetMethods() { return from m in AccessTools.GetDeclaredMethods(typeof(ItemInfo)) where m.Name == "SpawnObject" select m; } private static void Postfix(GameObject __result, Transform parent) { try { if ((Object)(object)__result != (Object)null && (Object)(object)parent != (Object)null) { Plugin.Behaviour?.SpawnedHandProp(__result, parent); } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Animal hand prop skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(CraftInteractionDisplay), "BeginCraftingSequence")] internal static class AnimalCraftDisplayHook { private static void Postfix(CraftInteractionDisplay __instance, InteractionSession interactionSession) { try { Plugin.Behaviour?.CraftProps(__instance, interactionSession); } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Animal craft props skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(EquipmentStackSlot), "_SetupInstance")] internal static class AnimalStackDisplayHook { private static void Postfix(DisplayStack displayStack) { try { EquipmentStack val = ((displayStack != null) ? ((Il2CppObjectBase)displayStack).TryCast<EquipmentStack>() : null); if (val != null) { Item item = ((DisplayStack)val).item; if (((item != null) ? ((Il2CppObjectBase)item).TryCast<EquipmentItem>() : null) == null) { Plugin.Behaviour?.StackProp(val._eqManager, ((DisplayStack)val).gameObject); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Animal stack prop skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(ItemPrefabStackSlot), "_SetupInstance")] internal static class AnimalResourceDisplayHook { private static void Postfix(ItemPrefabStackSlot __instance, DisplayStack displayStack) { try { if (displayStack != null) { Item item = displayStack.item; if (((item != null) ? ((Il2CppObjectBase)item).TryCast<EquipmentItem>() : null) == null) { Plugin.Behaviour?.SlotProp(__instance, displayStack.gameObject); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Animal resource prop skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(GatherInteraction), "GatherItemsCharge")] internal static class FoxQuickGatherHook { private static void Postfix(IInteractionAgent interactionAgent, int __result) { try { if (__result > 0 && (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303))) { object obj; if (interactionAgent == null) { obj = null; } else { PlayerInteractionAgent obj2 = ((Il2CppObjectBase)interactionAgent).TryCast<PlayerInteractionAgent>(); obj = ((obj2 != null) ? obj2.GetCharacter() : null); } PlayerCharacter val = (PlayerCharacter)obj; if ((Object)(object)val != (Object)null) { Plugin.Behaviour?.QuickPickup(((Component)val).gameObject); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox quick gather skipped: " + ex.Message)); } } } [HarmonyPatch] internal static class FoxTakeItemsHook { private static IEnumerable<MethodBase> TargetMethods() { return from m in AccessTools.GetDeclaredMethods(typeof(CharacterInventory)) where m.Name == "TakeItems" select m; } private static void Postfix(CharacterInventory __instance, int __result) { try { if (__result > 0) { Character character = __instance.character; PlayerCharacter val = ((character != null) ? ((Il2CppObjectBase)character).TryCast<PlayerCharacter>() : null); if ((Object)(object)val != (Object)null) { Plugin.Behaviour?.QuickPickup(((Component)val).gameObject); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox take-items animation skipped: " + ex.Message)); } } } internal enum AnimalPropKind { Pickup, Craft } internal sealed class AnimalPropLifetime { internal const float PickupSeconds = 1f; private float _expires; internal AnimalPropKind Kind { get; private set; } internal AnimalPropLifetime(AnimalPropKind kind, float now) { Kind = kind; _expires = now + ((kind == AnimalPropKind.Pickup) ? 1f : 0.25f); } internal void Observe(AnimalPropKind kind, float now) { if (kind == AnimalPropKind.Craft) { Kind = kind; _expires = now + 0.25f; } } internal bool Expired(float now) { return now >= _expires; } } internal sealed class AnimalPropSet { private sealed class Entry { internal GameObject Item; internal Transform Parent; internal AnimalPropLifetime Lifetime; internal AnimalHeldItem Binding = new AnimalHeldItem(); } private readonly Dictionary<int, Entry> _items = new Dictionary<int, Entry>(); private readonly List<int> _expired = new List<int>(); private readonly Dictionary<int, GameObject> _retired = new Dictionary<int, GameObject>(); internal void Add(GameObject item, AnimalPropKind kind) { if ((Object)(object)item == (Object)null) { return; } int instanceID = ((Object)item).GetInstanceID(); if (!_retired.TryGetValue(instanceID, out var value) || !((Object)(object)value == (Object)(object)item) || kind != AnimalPropKind.Pickup) { if (_items.TryGetValue(instanceID, out var value2)) { value2.Lifetime.Observe(kind, Time.time); return; } Entry entry = new Entry { Item = item, Parent = item.transform.parent, Lifetime = new AnimalPropLifetime(kind, Time.time) }; entry.Binding.Observe(item); _items[instanceID] = entry; } } internal bool Owns(Renderer renderer) { foreach (Entry value in _items.Values) { if (value.Binding.Owns(renderer)) { return true; } } return false; } internal void Exclude(GameObject item) { if (!((Object)(object)item == (Object)null)) { int instanceID = ((Object)item).GetInstanceID(); if (_items.TryGetValue(instanceID, out var value)) { value.Binding.Release(); _items.Remove(instanceID); } _retired[instanceID] = item; } } internal void Place(WolfVisual visual, bool working) { _expired.Clear(); foreach (KeyValuePair<int, Entry> item in _items) { Entry value = item.Value; if ((Object)(object)value.Item == (Object)null || !value.Item.activeInHierarchy || (Object)(object)value.Item.transform.parent != (Object)(object)value.Parent || value.Lifetime.Expired(Time.time)) { if ((Object)(object)value.Item != (Object)null) { _retired[item.Key] = value.Item; } value.Binding.Release(Plugin.HideEquipment.Value); _expired.Add(item.Key); } else { bool flag = value.Lifetime.Kind == AnimalPropKind.Craft && working; value.Binding.Place(visual.ItemSocket(flag), flag ? 90 : 180); } } foreach (int item2 in _expired) { _items.Remove(item2); } _expired.Clear(); foreach (KeyValuePair<int, GameObject> item3 in _retired) { if ((Object)(object)item3.Value == (Object)null) { _expired.Add(item3.Key); } } foreach (int item4 in _expired) { _retired.Remove(item4); } } internal void Release() { foreach (Entry value in _items.Values) { value.Binding.Release(); } _items.Clear(); _retired.Clear(); } } internal static class FoxActionMapping { private static readonly HashSet<string> WorkActions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Craft", "Gather", "GatherLow", "GatherMiddle", "GatherHigh", "Harvest", "Skinning", "Anvil", "Carpentry", "Build", "Shovel", "Till", "Grinding", "Cooking", "Forge", "Bellows", "Painting" }; internal static string Action(string name) { if (string.IsNullOrWhiteSpace(name)) { return null; } string text = name.Trim().TrimStart('_').Replace(" ", "") .Replace("_", ""); if (text.StartsWith("Pickup", StringComparison.OrdinalIgnoreCase)) { return "fox_pickup"; } if (text.Equals("Chop", StringComparison.OrdinalIgnoreCase) || text.Equals("ChopGround", StringComparison.OrdinalIgnoreCase)) { return "wolf_attack1"; } if (!WorkActions.Contains(text)) { return null; } return "fox_dig"; } internal static bool ImpactHarvest(string moveset) { return !(moveset?.Contains("Skinning", StringComparison.OrdinalIgnoreCase) ?? false); } } internal static class FoxCamera { [HarmonyPatch(typeof(InputManager), "UpdateCamera")] private static class UpdateCamera { private static void Postfix(InputManager __instance) { try { Refresh(__instance); } catch (Exception ex) { Reset(); Plugin.Logger.LogWarning((object)("Fox camera offset skipped: " + ex.Message)); } } } private static readonly Dictionary<int, (Cinemachine3rdPersonFollow follow, Vector3 original)> Saved = new Dictionary<int, (Cinemachine3rdPersonFollow, Vector3)>(); private static InputManager _manager; private static void Apply(CameraObject camera) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Cinemachine3rdPersonFollow val = ((camera != null) ? camera.baseComp : null); if (!((Object)(object)val == (Object)null)) { int instanceID = ((Object)val).GetInstanceID(); if (!Saved.TryGetValue(instanceID, out (Cinemachine3rdPersonFollow, Vector3) value) || (Object)(object)value.Item1 != (Object)(object)val) { value = (Saved[instanceID] = (val, val.ShoulderOffset)); } Vector3 item = value.Item2; item.y += Plugin.CameraHeightOffset.Value; val.ShoulderOffset = item; } } internal static void Reset() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) foreach (var value in Saved.Values) { if ((Object)(object)value.follow != (Object)null) { value.follow.ShoulderOffset = value.original; } } Saved.Clear(); _manager = null; } private static void Refresh(InputManager manager) { if ((Object)(object)_manager != (Object)(object)manager) { Reset(); } _manager = manager; if (Plugin.Behaviour?.LocalCameraVisual == null || Plugin.CameraHeightOffset.Value == 0f) { Reset(); return; } Apply(manager.normalCamera); Apply(manager.aimCamera); Apply(manager.climbingCamera); Apply(manager.lockCamera); Apply(manager.buildCamera); Apply(manager.insideBuildingCamera); Apply(manager.caveCamera); } } internal sealed class FoxConsumeAnimation { private string _clip; private float _remaining; internal bool Active => _remaining > 0f; internal static string Classify(string action, string moveset) { if (string.Equals(action, "Drink", StringComparison.OrdinalIgnoreCase) || (moveset != null && moveset.StartsWith("Moveset_Drink", StringComparison.OrdinalIgnoreCase))) { return "fox_drink"; } if (string.Equals(action, "Eat", StringComparison.OrdinalIgnoreCase) || (moveset != null && moveset.StartsWith("Moveset_Eat", StringComparison.OrdinalIgnoreCase))) { return "fox_eat"; } return null; } internal void Begin(string clip, float duration) { if (!(clip != "fox_eat") || !(clip != "fox_drink")) { _clip = clip; _remaining = ((float.IsFinite(duration) && duration > 0f) ? Math.Clamp(duration, 1.2f, 5f) : 2.5f); } } internal string Tick(float delta, bool interrupted) { if (interrupted) { Reset(); } _remaining = Math.Max(0f, _remaining - Math.Max(0f, delta)); if (!(_remaining > 0f)) { return null; } return _clip; } internal void Reset() { _clip = null; _remaining = 0f; } } internal static class FoxConsumeHooks { [HarmonyPatch(typeof(Consumable), "_TryPlayConsumeAnimation")] private static class ConsumeStarted { private static void Postfix(Consumable __instance, GameObject owner, bool __result) { if (__result) { Notify(__instance, owner); } } } [HarmonyPatch(typeof(Consumable), "_ApplyEffect")] private static class ConsumeApplied { private static void Postfix(Consumable __instance, StatusEffectManager sem) { if ((Object)(object)sem != (Object)null) { Notify(__instance, ((Component)sem).gameObject); } } } [HarmonyPatch(typeof(ConsumableDisplayer), "ShowConsumableItem")] private static class ConsumableShown { private static void Postfix(ConsumableDisplayer __instance) { try { Plugin.Behaviour?.ConsumptionDisplay(__instance); } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Animal food display skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(ConsumableDisplayer), "_RefreshShowingConsumable")] private static class ConsumableRefreshed { private static void Postfix(ConsumableDisplayer __instance) { try { Plugin.Behaviour?.ConsumptionDisplay(__instance); } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Animal food display refresh skipped: " + ex.Message)); } } } private static void Notify(Consumable item, GameObject owner) { try { if (item == null || (Object)(object)owner == (Object)null) { return; } ConsumableInfo consumableInfo = item.ConsumableInfo; InteractionMoveset val = ((consumableInfo != null) ? consumableInfo.moveSet : null); if (!((Object)(object)val == (Object)null)) { string text = FoxConsumeAnimation.Classify(val.attackActionName, ((Object)val).name); if (text != null) { Plugin.Behaviour?.Consume(owner, text, val.displayDuration); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox consume visual skipped: " + ex.Message)); } } } internal static class FoxCoop { [HarmonyPatch(typeof(NetworkRunner), "Fusion_Simulation_ICallbacks_OnReliableData")] private static class ReliableData { private static bool Prefix(NetworkRunner __instance, PlayerRef __0, Il2CppStructArray<byte> __1) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (__1 == null || ((Il2CppArrayBase<byte>)(object)__1).Length < FoxCoopProtocol.Magic.Length) { return true; } for (int i = 0; i < FoxCoopProtocol.Magic.Length; i++) { if (((Il2CppArrayBase<byte>)(object)__1)[i] != FoxCoopProtocol.Magic[i]) { return true; } } try { if (((Il2CppArrayBase<byte>)(object)__1).Length == 48) { Receive(__instance, __0, ((IEnumerable<byte>)__1).ToArray()); } } catch (Exception ex) { TransportError(ex); } return false; } } internal static PlayerManager Manager; private static NetworkRunner _runner; private static readonly FoxCoopStateBuffer Buffer = new FoxCoopStateBuffer(); private static readonly Dictionary<int, FoxMovement> Movement = new Dictionary<int, FoxMovement>(); private static readonly HashSet<int> Seen = new HashSet<int>(); private static readonly HashSet<int> Warned = new HashSet<int>(); private static readonly Dictionary<int, float> Waiting = new Dictionary<int, float>(); private static readonly List<int> Removed = new List<int>(); private static float _nextSend; private static float _nextScan; private static uint _sequence; private static bool _loggedTransportError; private static Dictionary<int, (FoxNetState state, float received)> States => Buffer.Entries; internal static PlayerCharacter Local { get { PlayerEntity instance = PlayerEntity.Instance; if (instance == null) { return null; } PlayerInteractionAgent agent = instance.Agent; if (agent == null) { return null; } return agent.GetCharacter(); } } internal static PlayerInteractionAgent Agent(PlayerCharacter player) { if ((Object)(object)player == (Object)null) { return null; } PlayerManager manager = Manager; if (((manager != null) ? manager._players : null) != null) { foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players) { if ((Object)(object)((item != null) ? item.playerCharacter : null) == (Object)(object)player) { IInteractionAgent playerInteractionAgent = item.playerInteractionAgent; PlayerInteractionAgent val = ((playerInteractionAgent != null) ? ((Il2CppObjectBase)playerInteractionAgent).TryCast<PlayerInteractionAgent>() : null); if ((Object)(object)val != (Object)null) { return val; } } } } PlayerEntity instance = PlayerEntity.Instance; PlayerInteractionAgent val2 = ((instance != null) ? instance.Agent : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetCharacter() == (Object)(object)player) { return val2; } return ((Component)player).GetComponent<PlayerInteractionAgent>() ?? ((Component)player).GetComponentInChildren<PlayerInteractionAgent>(true); } internal static IEnumerable<PlayerCharacter> Players() { PlayerManager manager = Manager; if (((manager != null) ? manager._players : null) == null) { yield break; } foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players) { if ((Object)(object)((item != null) ? item.playerCharacter : null) != (Object)null && (Object)(object)item.playerObject != (Object)null && item.playerObject.IsValid) { yield return item.playerCharacter; } } } internal static bool MaySimulate(PlayerCharacter player) { NetworkObject val = ((player != null) ? ((Character)player).NetworkObject : null); if ((Object)(object)player != (Object)null) { if (!((Character)player).HasAuthority) { if ((Object)(object)val != (Object)null && val.IsValid) { if (!val.HasStateAuthority) { return val.HasInputAuthority; } return true; } return false; } return true; } return false; } internal static bool TryState(PlayerCharacter player, out FoxNetState state, out float age) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) state = default(FoxNetState); age = 0f; NetworkObject val = ((player != null) ? ((Character)player).NetworkObject : null); if ((Object)(object)val == (Object)null || !val.IsValid) { return false; } foreach (var value in States.Values) { if (value.state.ObjectId == val.Id.Raw) { state = value.state; age = Time.unscaledTime - value.received; return true; } } return false; } internal static void Tick() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Expected O, but got Unknown PlayerManager manager = Manager; object obj; if (manager == null) { obj = null; } else { NetworkSession session = manager._session; obj = ((session != null) ? session.runner : null); } NetworkRunner val = (NetworkRunner)obj; if ((Object)(object)val == (Object)null || !val.IsRunning) { if ((Object)(object)_runner != (Object)null) { Plugin.Behaviour?.ClearPlayers(); Reset(); } return; } bool flag = default(bool); PlayerRef val3; if ((Object)(object)val != (Object)(object)_runner) { Plugin.Behaviour?.ClearPlayers(); Reset(); _runner = val; ManualLogSource logger = Plugin.Logger; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(51, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Fox co-op session: mode="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<GameMode>(val.GameMode); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", local player="); val3 = val.LocalPlayer; ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(((PlayerRef)(ref val3)).RawEncoded); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", protocol="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<byte>((byte)1); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("."); } logger.LogInfo(val2); } if (Time.unscaledTime < _nextScan) { return; } _nextScan = Time.unscaledTime + 0.25f; Seen.Clear(); foreach (PlayerCharacter item in Players()) { int instanceID = ((Object)item).GetInstanceID(); Seen.Add(instanceID); if (!Movement.TryGetValue(instanceID, out var value)) { value = (Movement[instanceID] = new FoxMovement()); } value.Tick(item); if (WolfSelection.IsFox(item) && MaySimulate(item)) { WolfStats.EnsureSimulationProfile(item); } } Removed.Clear(); foreach (KeyValuePair<int, FoxMovement> item2 in Movement) { if (!Seen.Contains(item2.Key)) { item2.Value.Dispose(); Removed.Add(item2.Key); } } foreach (int item3 in Removed) { Movement.Remove(item3); } Removed.Clear(); foreach (KeyValuePair<int, (FoxNetState, float)> state in States) { if ((Object)(object)Find(state.Key, state.Value.Item1.ObjectId) == (Object)null) { Removed.Add(state.Key); } } foreach (int item4 in Removed) { States.Remove(item4); } PlayerManager manager2 = Manager; if (((manager2 != null) ? manager2._players : null) == null || _runner.IsSinglePlayer) { return; } foreach (Player item5 in (Il2CppArrayBase<Player>)(object)Manager._players) { if ((Object)(object)((item5 != null) ? item5.playerObject : null) == (Object)null || !item5.playerObject.IsValid || item5.reference == _runner.LocalPlayer) { continue; } val3 = item5.reference; int rawEncoded = ((PlayerRef)(ref val3)).RawEncoded; float value2; if (States.ContainsKey(rawEncoded)) { Waiting.Remove(rawEncoded); } else if (!Waiting.TryGetValue(rawEncoded, out value2)) { Waiting[rawEncoded] = Time.unscaledTime; } else if (Time.unscaledTime - value2 > 20f && Warned.Add(rawEncoded)) { ManualLogSource logger2 = Plugin.Logger; BepInExWarningLogInterpolatedStringHandler val4 = new BepInExWarningLogInterpolatedStringHandler(111, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Fox co-op: no compatible state from player "); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(rawEncoded); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(". Both players need ASKA Fox "); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>("0.6.3"); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("; inspect both logs if it is installed."); } logger2.LogWarning(val4); } } } internal static void Send(WolfController local) { //IL_005b: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Invalid comparison between Unknown and I4 if ((Object)(object)_runner == (Object)null || !_runner.IsRunning || _runner.IsSinglePlayer || Time.unscaledTime < _nextSend) { return; } PlayerCharacter local2 = Local; NetworkObject val = ((local2 != null) ? ((Character)local2).NetworkObject : null); if ((Object)(object)val == (Object)null || !val.IsValid) { return; } PlayerRef localPlayer = _runner.LocalPlayer; if ((Object)(object)Find(((PlayerRef)(ref localPlayer)).RawEncoded, val.Id.Raw) != (Object)(object)local2) { return; } localPlayer = _runner.LocalPlayer; FoxNetState state = local.Snapshot(local2, ((PlayerRef)(ref localPlayer)).RawEncoded, val.Id.Raw, ++_sequence); _nextSend = Time.unscaledTime + (state.Visible ? 0.1f : 1f); try { byte[] array = FoxCoopProtocol.Encode(state); if (_runner.IsServer || (int)_runner.GameMode == 2) { localPlayer = _runner.LocalPlayer; Broadcast(array, ((PlayerRef)(ref localPlayer)).RawEncoded); } else { _runner.SendReliableDataToServer(Il2CppStructArray<byte>.op_Implicit(array)); } } catch (Exception ex) { TransportError(ex); } } private static PlayerCharacter Find(int owner, uint objectId) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) PlayerManager manager = Manager; if (((manager != null) ? manager._players : null) == null) { return null; } foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players) { if (item != null) { PlayerRef reference = item.reference; if (((PlayerRef)(ref reference)).RawEncoded == owner && (Object)(object)item.playerObject != (Object)null && item.playerObject.IsValid && item.playerObject.Id.Raw == objectId) { return item.playerCharacter; } } } return null; } private static void Broadcast(byte[] bytes, int exceptOwner) { //IL_004f: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) PlayerManager manager = Manager; if (((manager != null) ? manager._players : null) == null) { return; } foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players) { if ((Object)(object)((item != null) ? item.playerObject : null) != (Object)null && item.playerObject.IsValid && item.reference != _runner.LocalPlayer) { PlayerRef reference = item.reference; if (((PlayerRef)(ref reference)).RawEncoded != exceptOwner) { _runner.SendReliableDataToPlayer(item.reference, Il2CppStructArray<byte>.op_Implicit(bytes)); } } } } private static void Receive(NetworkRunner runner, PlayerRef sender, byte[] bytes) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown if ((Object)(object)runner == (Object)null || (Object)(object)runner != (Object)(object)_runner || !runner.IsRunning) { return; } if (!FoxCoopProtocol.TryDecode(bytes, out var state)) { if (Warned.Add(-((PlayerRef)(ref sender)).RawEncoded - 1000)) { Plugin.Logger.LogWarning((object)"Fox co-op rejected incompatible or malformed state. Install matching Fox builds on every peer."); } return; } PlayerRef val; int num; if (!runner.IsServer && (int)runner.GameMode != 2) { if (!((PlayerRef)(ref sender)).IsNone) { val = sender; PlayerManager manager = Manager; PlayerRef? obj; if (manager == null) { obj = null; } else { Player masterPlayer = manager.MasterPlayer; obj = ((masterPlayer != null) ? new PlayerRef?(masterPlayer.reference) : ((PlayerRef?)null)); } PlayerRef? val2 = obj; num = ((val2.HasValue && val == val2.GetValueOrDefault()) ? 1 : 0); } else { num = 1; } } else { num = 0; } bool serverRelay = (byte)num != 0; PlayerCharacter val3 = Find(state.Owner, state.ObjectId); if ((Object)(object)val3 == (Object)null) { return; } int owner = state.Owner; val = runner.LocalPlayer; if (owner == ((PlayerRef)(ref val)).RawEncoded || !FoxCoopProtocol.MatchesOwner(((PlayerRef)(ref sender)).RawEncoded, state.Owner, state.ObjectId, state.Owner, ((Character)val3).NetworkObject.Id.Raw, serverRelay) || !Buffer.Accept(state, Time.unscaledTime, out var first)) { return; } WolfSelection.SetIdentity(val3, state.Fox, new FoxPalette(state.Coat, state.Eye)); if (first) { ManualLogSource logger = Plugin.Logger; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(58, 5, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Fox co-op recognized player "); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(state.Owner); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", object "); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<uint>(state.ObjectId); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(": Fox="); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<bool>(state.Fox); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", coat="); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<byte>(state.Coat); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", eyes="); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<byte>(state.Eye); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("."); } logger.LogInfo(val4); } if (runner.IsServer) { Broadcast(bytes, state.Owner); } } internal static void Reset() { foreach (FoxMovement value in Movement.Values) { value.Dispose(); } Movement.Clear(); States.Clear(); Seen.Clear(); Waiting.Clear(); Warned.Clear(); _runner = null; _nextScan = (_nextSend = 0f); _sequence = 0u; _loggedTransportError = false; } private static void TransportError(Exception ex) { if (!_loggedTransportError) { _loggedTransportError = true; Plugin.Logger.LogError((object)("Fox co-op transport error; local gameplay remains active: " + ex)); } } } internal readonly record struct FoxNetState(int Owner, uint ObjectId, uint Sequence, bool Fox, bool Visible, byte Coat, byte Eye, byte Clip, uint Animation, float Time, float Yaw, float Hit); internal static class FoxCoopProtocol { internal const byte Version = 1; internal const int Size = 48; internal static readonly byte[] Magic = new byte[8] { 65, 83, 75, 65, 70, 79, 88, 0 }; internal static readonly string[] Clips = new string[27] { "wolf_idle", "wolf_walk", "wolf_trot", "wolf_sprint", "wolf_attack1", "wolf_death", "wolf_dodge", "fox_scurry", "fox_jump_takeoff", "fox_jump_air", "fox_jump_fall", "fox_jump_land", "fox_hit", "fox_dig", "fox_pickup", "fox_drink", "fox_eat", "fox_lie_down", "fox_sleep", "fox_wake", "fox_sit_down", "fox_sit", "fox_sit_up", "fox_emote_wave", "fox_emote_cheer", "fox_emote_wave_seated", "fox_emote_cheer_seated" }; internal static byte ClipId(string clip) { int val = Array.IndexOf(Clips, clip); return (byte)Math.Max(0, val); } internal static bool IsOurs(ReadOnlySpan<byte> data) { if (data.Length >= Magic.Length) { return data.Slice(0, Magic.Length).SequenceEqual(Magic); } return false; } internal static bool Newer(uint incoming, uint current) { return (int)(incoming - current) > 0; } internal static bool MatchesOwner(int sender, int claimedOwner, uint claimedObject, int actualOwner, uint actualObject, bool serverRelay) { if (claimedObject != 0 && claimedObject == actualObject && claimedOwner == actualOwner) { if (!serverRelay) { return sender == actualOwner; } return true; } return false; } internal static byte[] Encode(FoxNetState state) { byte[] array = new byte[48]; Magic.CopyTo(array, 0); array[8] = 1; array[9] = (byte)((state.Fox ? 1u : 0u) | (uint)(state.Visible ? 2 : 0)); array[10] = state.Coat; array[11] = state.Eye; array[12] = state.Clip; BinaryPrimitives.WriteInt32LittleEndian(array.AsSpan(16), state.Owner); BinaryPrimitives.WriteUInt32LittleEndian(array.AsSpan(20), state.ObjectId); BinaryPrimitives.WriteUInt32LittleEndian(array.AsSpan(24), state.Sequence); BinaryPrimitives.WriteUInt32LittleEndian(array.AsSpan(28), state.Animation); WriteFloat(array, 32, state.Time); WriteFloat(array, 36, state.Yaw); WriteFloat(array, 40, state.Hit); return array; } private static void WriteFloat(byte[] bytes, int offset, float value) { BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(offset), BitConverter.SingleToInt32Bits(value)); } private static float ReadFloat(ReadOnlySpan<byte> bytes, int offset) { return BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(offset))); } internal static bool TryDecode(ReadOnlySpan<byte> data, out FoxNetState state) { state = default(FoxNetState); if (data.Length != 48 || !IsOurs(data) || data[8] != 1 || data[9] > 3 || data[10] >= FoxPalette.Coats.Length || data[11] >= FoxPalette.Eyes.Length || data[12] >= Clips.Length) { return false; } if (data[13] != 0 || data[14] != 0 || data[15] != 0 || BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(44)) != 0) { return false; } int num = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16)); uint num2 = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(20)); float num3 = ReadFloat(data, 32); float num4 = ReadFloat(data, 36); float num5 = ReadFloat(data, 40); if (num <= 0 || num2 == 0 || !float.IsFinite(num3) || num3 < 0f || num3 > 120f || !float.IsFinite(num4) || num4 < 0f || num4 > 360f || !float.IsFinite(num5) || num5 < 0f || num5 > 0.7f) { return false; } state = new FoxNetState(num, num2, BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(24)), (data[9] & 1) != 0, (data[9] & 2) != 0, data[10], data[11], data[12], BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(28)), num3, num4, num5); return true; } } internal sealed class FoxCoopStateBuffer { internal readonly Dictionary<int, (FoxNetState state, float received)> Entries = new Dictionary<int, (FoxNetState, float)>(); internal bool Accept(FoxNetState state, float now, out bool first) { first = !Entries.TryGetValue(state.Owner, out (FoxNetState, float) value) || value.Item1.ObjectId != state.ObjectId; if (!first && !FoxCoopProtocol.Newer(state.Sequence, value.Item1.Sequence)) { return false; } Entries[state.Owner] = (state, now); return true; } internal void Clear() { Entries.Clear(); } } internal static class FoxCustomization { [HarmonyPatch(typeof(CharacterSelectionTabPage), "ResetSelectedPreset")] private static class ResetFoxColors { private static bool Prefix(CharacterSelectionTabPage __instance) { CharacterDisplaySetup selectedCharacterSetup = __instance._selectedCharacterSetup; if ((Object)(object)((selectedCharacterSetup != null) ? selectedCharacterSetup.characterDefinition : null) != (Object)(object)WolfSelection.FoxDefinition) { return true; } Selected = default(FoxPalette); return false; } } internal const string CoatKey = "com.aska.fox.coat.v1"; internal const string EyeKey = "com.aska.fox.eyes.v1"; private static ConfigEntry<int> _coat; private static ConfigEntry<int> _eye; private static readonly Dictionary<int, (PlayerCharacter owner, FoxPalette colors)> Players = new Dictionary<int, (PlayerCharacter, FoxPalette)>(); internal static FoxPalette? Loaded; internal static FoxPalette Selected { get { return new FoxPalette(_coat?.Value ?? 0, _eye?.Value ?? 0); } set { _coat.Value = value.Coat; _eye.Value = value.Eye; Loaded = null; } } internal static void Configure(ConfigFile config) { _coat = config.Bind<int>("Customization", "NewFoxCoat", 0, "New Fox default: 0 Red, 1 Gold, 2 Silver, 3 Arctic, 4 Brown, 5 Black. Saved Fox colors are independent."); _eye = config.Bind<int>("Customization", "NewFoxEyes", 0, "New Fox default: 0 Green, 1 Amber, 2 Blue, 3 Brown, 4 Gray, 5 Violet."); } internal static FoxPalette Read(DataObject record) { return new FoxPalette(ReadIndex(record, "com.aska.fox.coat.v1"), ReadIndex(record, "com.aska.fox.eyes.v1")); } private static int ReadIndex(DataObject record, string key) { DataElement val = default(DataElement); if (record == null || !record.TryGetElement(key, ref val)) { return 0; } int? obj; if (val == null) { obj = null; } else { DataElementInt obj2 = ((Il2CppObjectBase)val).TryCast<DataElementInt>(); obj = ((obj2 != null) ? new int?(obj2.value) : ((int?)null)); } int? num = obj; return num.GetValueOrDefault(); } internal static void Write(DataObject record, FoxPalette colors) { record.AddElement("com.aska.fox.coat.v1", DataElement.op_Implicit(colors.Coat)); record.AddElement("com.aska.fox.eyes.v1", DataElement.op_Implicit(colors.Eye)); } internal static void Register(PlayerCharacter player) { Players[((Object)player).GetInstanceID()] = (player, Loaded ?? Selected); } internal static void Register(PlayerCharacter player, FoxPalette palette) { Players[((Object)player).GetInstanceID()] = (player, palette); } internal static void Forget(PlayerCharacter player) { Players.Remove(((Object)player).GetInstanceID()); } internal static FoxPalette For(PlayerCharacter player) { if (!((Object)(object)player != (Object)null) || !Players.TryGetValue(((Object)player).GetInstanceID(), out (PlayerCharacter, FoxPalette) value) || !((Object)(object)value.Item1 == (Object)(object)player)) { return Selected; } return value.Item2; } } internal sealed class FoxCustomizationPanel : IDisposable { private GameObject _root; private IncreaseDecreasePanel _coat; private IncreaseDecreasePanel _eye; private readonly List<UnityAction> _callbacks = new List<UnityAction>(); internal FoxCustomizationPanel(CharacterSelectionTabPage page) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0085: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) try { IncreaseDecreasePanel val = page.hairStylePanel ?? page.selectedPresetPanel; DropdownElement faceAndHairDropdown = page.faceAndHairDropdown; Transform val2 = ((faceAndHairDropdown != null) ? ((Component)faceAndHairDropdown).transform.parent : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { throw new InvalidOperationException("Fox customization template/container unavailable."); } _root = new GameObject("FoxColorCustomization"); RectTransform obj = _root.AddComponent<RectTransform>(); ((Transform)obj).SetParent(val2, false); obj.anchorMin = new Vector2(0f, 1f); obj.anchorMax = new Vector2(1f, 1f); obj.pivot = new Vector2(0.5f, 1f); obj.sizeDelta = new Vector2(-24f, 176f); obj.anchoredPosition = new Vector2(0f, -12f); LayoutElement obj2 = _root.AddComponent<LayoutElement>(); obj2.preferredHeight = 176f; obj2.minHeight = 176f; obj2.flexibleWidth = 1f; _coat = Row(val, "FoxCoatColor", -20f, coat: true); _eye = Row(val, "FoxEyeColor", -98f, coat: false); Refresh(); } catch { Dispose(); throw; } } private IncreaseDecreasePanel Row(IncreaseDecreasePanel template, string name, float y, bool coat) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) IncreaseDecreasePanel val = Object.Instantiate<IncreaseDecreasePanel>(template, _root.transform, false); ((Object)val).name = name; ((Behaviour)val).enabled = false; val.group = null; val.AutomaticValueText = false; val.m_OnValueChanged = new IncreseDecreaseEvent(); val.m_OnIncrease = new UnityEvent(); val.m_OnDecrease = new UnityEvent(); foreach (LocalizedText componentsInChild in ((Component)val).GetComponentsInChildren<LocalizedText>(true)) { ((Behaviour)componentsInChild).enabled = false; Object.Destroy((Object)(object)componentsInChild); } RectTransform component = ((Component)val).GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); component.sizeDelta = new Vector2(-20f, 60f); component.anchoredPosition = new Vector2(0f, y); LayoutElement component2 = ((Component)val).GetComponent<LayoutElement>(); if ((Object)(object)component2 != (Object)null) { component2.ignoreLayout = true; } ((Component)val).gameObject.SetActive(true); Bind(val.IncreaseButton, delegate { Change(coat, 1); }); Bind(val.DecreaseButton, delegate { Change(coat, -1); }); if ((Object)(object)val.ValueText == (Object)null) { throw new InvalidOperationException("Fox color row has no value label."); } ((TMP_Text)val.ValueText).enableAutoSizing = true; ((TMP_Text)val.ValueText).fontSizeMin = 14f; ((TMP_Text)val.ValueText).fontSizeMax = 22f; if ((Object)(object)val.Icon != (Object)null) { ((Component)val.Icon).gameObject.SetActive(false); } if ((Object)(object)val.InputField != (Object)null) { ((Component)val.InputField).gameObject.SetActive(false); } return val; } private void Bind(Button button, Action action) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if ((Object)(object)button == (Object)null) { throw new InvalidOperationException("Fox color row has no arrow button."); } ((Component)button).gameObject.SetActive(true); ((Selectable)button).interactable = true; button.onClick = new ButtonClickedEvent(); UnityAction val = UnityAction.op_Implicit(action); _callbacks.Add(val); ((UnityEvent)button.onClick).AddListener(val); } private void Change(bool coat, int step) { WolfSelection.Guard("color selection", delegate { FoxCustomization.Selected = (coat ? FoxCustomization.Selected.ChangeCoat(step) : FoxCustomization.Selected.ChangeEye(step)); Refresh(); }); } internal void Refresh() { FoxPalette selected = FoxCustomization.Selected; ((TMP_Text)_coat.ValueText).text = "COAT: " + FoxPalette.Coats[selected.Coat]; ((TMP_Text)_eye.ValueText).text = "EYES: " + FoxPalette.Eyes[selected.Eye]; } internal void Show(bool visible) { if ((Object)(object)_root != (Object)null) { _root.SetActive(visible); } } public void Dispose() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } _root = null; _callbacks.Clear(); } } internal sealed class FoxDamageReaction { internal const float Duration = 0.7f; internal float Elapsed { get; private set; } = 0.7f; internal bool Active => Elapsed < 0.7f; internal bool Trigger(float damage, bool unavailable) { if (unavailable || !float.IsFinite(damage) || damage <= 0f || (Active && Elapsed < 0.15f)) { return false; } Elapsed = 0f; return true; } internal void Tick(float delta) { Elapsed = Math.Min(0.7f, Elapsed + Math.Max(0f, delta)); } internal void Reset() { Elapsed = 0.7f; } } internal static class FoxFirstPersonCompatibility { private sealed class LastView { internal int FoxAnchor; } private sealed class Swap { internal Transform Original; internal Transform Fox; } private static FieldInfo _head; private static FieldInfo _active; private static FieldInfo _stablePosition; private static FieldInfo _velocity; private static bool _warned; private static readonly ConditionalWeakTable<object, LastView> Views = new ConditionalWeakTable<object, LastView>(); internal static void Install() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_01c5: Expected O, but got Unknown if (!Plugin.FirstPersonCompatibility.Value) { return; } Type type = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { type = assemblies[i].GetType("AskaFirstPerson.FirstPersonBehaviour", throwOnError: false); if (type != null) { break; } } if (type == null) { Plugin.Logger.LogInfo((object)"First-person mod absent; Fox camera compatibility is inactive."); return; } Harmony val = new Harmony("com.aska.wolfprototype.firstperson"); try { _head = AccessTools.Field(type, "_headBone"); _active = AccessTools.Field(type, "IsFirstPerson"); _stablePosition = AccessTools.Field(type, "_stableBasePos"); _velocity = AccessTools.Field(type, "_smoothVelocity"); MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "LateUpdate", (Type[])null, (Type[])null); if (_head?.FieldType != typeof(Transform) || _head.IsStatic || _active?.FieldType != typeof(bool) || !_active.IsStatic || _stablePosition?.FieldType != typeof(Vector3) || _velocity?.FieldType != typeof(Vector3) || methodInfo == null || methodInfo.ReturnType != typeof(void) || methodInfo.GetParameters().Length != 0) { throw new InvalidOperationException("The installed first-person mod's camera API has changed."); } val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(FoxFirstPersonCompatibility), "BeforeCamera", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FoxFirstPersonCompatibility), "AfterCamera", (Type[])null), (HarmonyMethod)null); Plugin.Logger.LogInfo((object)("First-person Fox head compatibility enabled for " + type.Assembly.GetName().Name + ". The mod retains its toggle and camera controls.")); } catch (Exception ex) { val.UnpatchSelf(); Plugin.Logger.LogWarning((object)("First-person compatibility disabled; native mod retained: " + ex.Message)); } } private static void BeforeCamera(object __instance, out Swap __state) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) __state = null; try { bool num = (bool)_active.GetValue(null); object? value = _head.GetValue(__instance); Transform val = (Transform)((value is Transform) ? value : null); Transform val2 = ((!num || !Plugin.FirstPersonCompatibility.Value) ? null : Plugin.Behaviour?.LocalCameraVisual?.CameraHead); LastView value2 = Views.GetValue(__instance, (object _) => new LastView()); int num2 = (((Object)(object)val2 != (Object)null) ? ((Object)val2).GetInstanceID() : 0); if (value2.FoxAnchor != num2) { Transform val3 = (((Object)(object)val2 != (Object)null) ? val2 : val); if ((Object)(object)val3 != (Object)null) { _stablePosition.SetValue(__instance, val3.position); } _velocity.SetValue(__instance, Vector3.zero); value2.FoxAnchor = num2; } if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val == (Object)null)) { __state = new Swap { Original = val, Fox = val2 }; _head.SetValue(__instance, val2); } } catch (Exception ex) { if (!_warned) { _warned = true; Plugin.Logger.LogWarning((object)("First-person Fox anchor unavailable: " + ex.Message)); } } } private static Exception AfterCamera(object __instance, Swap __state, Exception __exception) { if (__state != null) { try { object? value = _head.GetValue(__instance); if ((Object)((value is Transform) ? value : null) == (Object)(object)__state.Fox) { _head.SetValue(__instance, __state.Original); } } catch (Exception ex) { if (!_warned) { _warned = true; Plugin.Logger.LogWarning((object)("First-person head restoration failed: " + ex.Message)); } } } return __exception; } } internal sealed class FoxFootsteps : IDisposable { [HarmonyPatch(typeof(AudioSurface), "PlayRandomClip")] private static class PawSample { private static bool Prefix(AudioSurface __instance, AudioSource __1, float __2) { if ((Object)(object)__1 != (Object)null && Owners.TryGetValue(((Object)__1).GetInstanceID(), out var value)) { return !value.TryPlay(__instance, __1, __2); } return true; } } private static readonly Dictionary<int, FoxFootsteps> Owners = new Dictionary<int, FoxFootsteps>(); private readonly Dictionary<int, FootPlantingPlayer> _sources = new Dictionary<int, FootPlantingPlayer>(); private AudioSurface _paws; private FisherYatesRandom _random; private float _nextScan; private bool _failed; private bool _logged; internal void Tick(Character player, bool suspended) { //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown if (suspended || (Object)(object)player == (Object)null) { Dispose(); } else { if (_failed || Time.unscaledTime < _nextScan) { return; } _nextScan = Time.unscaledTime + 1f; try { if ((Object)(object)_paws == (Object)null) { ItemInfo obj = Resources.Load<ItemInfo>("item_population_wolf"); GameObject obj2 = ((obj != null) ? obj.spawnObject : null); FootPlantingPlayer val = ((obj2 != null) ? obj2.GetComponentInChildren<FootPlantingPlayer>(true) : null); _paws = ((val != null) ? val.defaultSurface : null); if ((Object)(object)_paws == (Object)null || ((Object)_paws).name != "defaultSurfaceDog" || _paws.audioClips == null || _paws.audioClips.Count == 0) { throw new InvalidOperationException("Native wolf paw clips unavailable."); } _random = new FisherYatesRandom(); } Unregister(); foreach (FootPlantingPlayer componentsInChild in ((Component)player).GetComponentsInChildren<FootPlantingPlayer>(true)) { AudioSource footstepAudioSource = componentsInChild.footstepAudioSource; if ((Object)(object)footstepAudioSource != (Object)null) { _sources[((Object)footstepAudioSource).GetInstanceID()] = componentsInChild; Owners[((Object)footstepAudioSource).GetInstanceID()] = this; } } if (!_logged && _sources.Count > 0) { _logged = true; ManualLogSource logger = Plugin.Logger; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(94, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Fox footsteps: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_paws.audioClips.Count); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" native wolf paw clips on "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_sources.Count); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" player footstep source(s); original timing retained."); } logger.LogInfo(val2); } } catch (Exception ex) { Fail(ex); } } } private bool TryPlay(AudioSurface surface, AudioSource source, float volume) { try { if (_failed || (Object)(object)_paws == (Object)null || (Object)(object)source == (Object)null || volume <= 0f || !_sources.TryGetValue(((Object)source).GetInstanceID(), out var value) || (Object)(object)value == (Object)null || (Object)(object)value.footstepAudioSource != (Object)(object)source || !((Component)value).gameObject.activeInHierarchy || value.IsUnderwater) { return false; } List<AudioClip> audioClips = _paws.audioClips; if (audioClips == null || audioClips.Count == 0) { return false; } AudioClip val = audioClips[_random.Next(audioClips.Count)]; if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)surface.audioMixerGroup != (Object)null) { source.outputAudioMixerGroup = surface.audioMixerGroup; } source.PlayOneShot(val, volume); return true; } catch (Exception ex) { Fail(ex); return false; } } private void Fail(Exception ex) { _failed = true; Dispose(); Plugin.Logger.LogError((object)("Fox paw replacement disabled; native footsteps retained: " + ex)); } private void Unregister() { foreach (int key in _sources.Keys) { if (Owners.TryGetValue(key, out var value) && value == this) { Owners.Remove(key); } } _sources.Clear(); } public void Dispose() { Unregister(); _sources.Clear(); _paws = null; _random = null; _nextScan = 0f; _logged = false; } } internal static class FoxInteractionTracking { private static readonly Dictionary<IntPtr, (PlayerCharacter player, InteractionSession session)> Sessions = new Dictionary<IntPtr, (PlayerCharacter, InteractionSession)>(); internal static IEnumerable<InteractionSession> For(PlayerCharacter player) { foreach (var value in Sessions.Values) { if ((Object)(object)value.player != (Object)null && (Object)(object)value.player == (Object)(object)player) { yield return value.session; } } } internal static void Track(PlayerInteractionAgent agent, InteractionSession session) { PlayerCharacter val = ((agent != null) ? agent.GetCharacter() : null); if ((Object)(object)val != (Object)null && session != null) { Sessions[((Il2CppObjectBase)session).Pointer] = (val, session); } } internal static void Forget(PlayerCharacter player) { List<IntPtr> list = new List<IntPtr>(); foreach (KeyValuePair<IntPtr, (PlayerCharacter, InteractionSession)> session in Sessions) { if ((Object)(object)session.Value.Item1 == (Object)null || (Object)(object)session.Value.Item1 == (Object)(object)player) { list.Add(session.Key); } } foreach (IntPtr item in list) { Sessions.Remove(item); } } internal static void Release(InteractionSession session) { if (session != null) { Sessions.Remove(((Il2CppObjectBase)session).Pointer); } } } [HarmonyPatch(typeof(PlayerInteractionAgent), "GetInteractionSession")] internal static class FoxSessionRentedHook { private static void Postfix(PlayerInteractionAgent __instance, InteractionSession __result) { try { FoxInteractionTracking.Track(__instance, __result); } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox session tracking skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(PlayerInteractionAgent), "ClearInteractionSession")] internal static class FoxSessionReturnedHook { private static void Prefix(InteractionSession session) { FoxInteractionTracking.Release(session); } } internal sealed class FoxMovement : IDisposable { private CharacterMovement _movement; private MovementStats _original; private MovementStats _copy; private FloatParameterNode _sprintDrain; private bool _failed; internal void Tick(PlayerCharacter player) { //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown if (_failed) { return; } try { CharacterMovement val = ((player != null) ? player.GetCharacterMovement() : null); if (!WolfSelection.IsFox(player) || !FoxCoop.MaySimulate(player) || (Object)(object)val == (Object)null || !((Component)player).gameObject.activeInHierarchy || player.IsGhost || val.IsRaven) { Dispose(); } else { if ((Object)(object)_movement == (Object)(object)val && (Object)(object)_copy != (Object)null && (Object)(object)val.parameters == (Object)(object)_copy) { return; } Dispose(); if (!((Object)(object)val.parameters == (Object)null)) { MovementStats parameters = val.parameters; MovementStats val2 = Object.Instantiate<MovementStats>(parameters); _movement = val; _original = parameters; _copy = val2; ((Object)val2).name = "AskaFox_MovementProfile"; val2.speed = 6f; val2.sprintMultiplier = 1.6666666f; FloatParameterReference sprintStaminaUsage = parameters.sprintStaminaUsage; if ((Object)(object)((sprintStaminaUsage != null) ? sprintStaminaUsage.parameter : null) == (Object)null) { throw new InvalidOperationException("Native sprint drain parameter missing."); } _sprintDrain = Object.Instantiate<FloatParameterNode>(sprintStaminaUsage.parameter); ((Object)_sprintDrain).name = "AskaFox_SprintDrain"; _sprintDrain.SetValue(16f); val2.sprintStaminaUsage = new FloatParameterReference { parameter = _sprintDrain }; val.parameters = val2; ManualLogSource logger = Plugin.Logger; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(76, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Fox movement: base="); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(val2.speed); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", sprint="); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(val2.speed * val2.sprintMultiplier); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", sprint drain="); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(val2.sprintStaminaUsage.Value); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("/s (native="); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(sprintStaminaUsage.Value); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("/s, before discounts)."); } logger.LogInfo(val3); } } } catch (Exception ex) { _failed = true; try { Dispose(); } catch { } Plugin.Logger.LogError((object)("Fox movement override disabled after failure: " + ex)); } } public void Dispose() { if ((Object)(object)_movement != (Object)null && (Object)(object)_copy != (Object)null && (Object)(object)_movement.parameters == (Object)(object)_copy) { _movement.parameters = _original; } if ((Object)(object)_copy != (Object)null) { Object.Destroy((Object)(object)_copy); } if ((Object)(object)_sprintDrain != (Object)null) { Object.Destroy((Object)(object)_sprintDrain); } _sprintDrain = null; _movement = null; _original = null; _copy = null; } } internal sealed class FoxNameTag : IDisposable { private PlayerNameTag _tag; private Transform _parent; private Vector3 _position; internal static bool Owns(PlayerCharacter player, Renderer renderer) { PlayerNameTag val = ((player != null) ? player.nameTag : null); if ((Object)(object)val == (Object)null || (Object)(object)renderer == (Object)null) { return false; } Transform transform = ((Component)renderer).transform; if (!((Object)(object)transform == (Object)(object)((Component)val).transform) && !transform.IsChildOf(((Component)val).transform)) { if ((Object)(object)val.nameText != (Object)null) { if (!((Object)(object)transform == (Object)(object)val.nameText.transform)) { return transform.IsChildOf(val.nameText.transform); } return true; } return false; } return true; } internal void Tick(PlayerCharacter player, Transform mouth) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) PlayerNameTag val = ((player != null) ? player.nameTag : null); if ((Object)(object)val != (Object)(object)_tag) { Dispose(); if ((Object)(object)val != (Object)null) { _tag = val; _parent = ((Component)val).transform.parent; _position = ((Component)val).transform.localPosition; } } if (!((Object)(object)_tag == (Object)null) && !((Object)(object)mouth == (Object)null)) { Vector3 position = mouth.position; position.y += 0.35f; ((Component)_tag).transform.position = position; } } public void Dispose() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_tag != (Object)null && (Object)(object)((Component)_tag).transform.parent == (Object)(object)_parent) { ((Component)_tag).transform.localPosition = _position; } _tag = null; _parent = null; } } internal static class FoxNativeDodge { private static readonly HashSet<int> States = new HashSet<int> { Animator.StringToHash("Base Layer.OneHandedLocomotion.Roll_OneHandedLocomotion"), Animator.StringToHash("Base Layer.OneHandedLocomotion.Dodge"), Animator.StringToHash("Base Layer.TwoHandedLocomotion.Roll_TwoHandedLocomotion"), Animator.StringToHash("Base Layer.TwoHandedLocomotion.Roll 0"), Animator.StringToHash("Base Layer.Bow.Roll_Bow") }; internal static bool Read(Animator animator, out float phase, out int stateHash) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) phase = 0f; stateHash = 0; if ((Object)(object)animator == (Object)null || animator.layerCount == 0) { return false; } AnimatorStateInfo val = animator.GetCurrentAnimatorStateInfo(0); if (animator.IsInTransition(0)) { AnimatorStateInfo nextAnimatorStateInfo = animator.GetNextAnimatorStateInfo(0); if (States.Contains(((AnimatorStateInfo)(ref nextAnimatorStateInfo)).fullPathHash)) { val = nextAnimatorStateInfo; } } if (!States.Contains(((AnimatorStateInfo)(ref val)).fullPathHash)) { return false; } phase = Mathf.Clamp01(((AnimatorStateInfo)(ref val)).normalizedTime); stateHash = ((AnimatorStateInfo)(ref val)).fullPathHash; return true; } } internal static class FoxNativeEmotes { private static readonly Dictionary<int, string> States = new Dictionary<int, string> { [Animator.StringToHash("Actions.Emotes.sit_Emotes")] = "fox_sit_down", [Animator.StringToHash("Actions.Emotes.Sit Idle")] = "fox_sit", [Animator.StringToHash("Actions.Emotes.Sit Up")] = "fox_sit_up", [Animator.StringToHash("Actions.Emotes.Wave")] = "fox_emote_wave", [Animator.StringToHash("Actions.Emotes.Cheer")] = "fox_emote_cheer", [Animator.StringToHash("UpperBody.Wave Feast")] = "fox_emote_wave_seated", [Animator.StringToHash("UpperBody.Cheer Feast")] = "fox_emote_cheer_seated", [Animator.StringToHash("UpperBody.Skal Feast")] = "fox_emote_cheer_seated", [Animator.StringToHash("UpperBody.Skal")] = "fox_emote_cheer_seated", [Animator.StringToHash("Base Layer.SitAtTable.SitAtTable")] = "fox_sit" }; internal static string Read(Animator animator, out float phase) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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) phase = 0f; if ((Object)(object)animator == (Object)null) { return null; } string result = null; int num = -1; for (int i = 0; i < animator.layerCount; i++) { if (i > 0 && animator.GetLayerWeight(i) <= 0.001f) { continue; } AnimatorStateInfo val = animator.GetCurrentAnimatorStateInfo(i); if (animator.IsInTransition(i)) { AnimatorStateInfo nextAnimatorStateInfo = animator.GetNextAnimatorStateInfo(i); if (States.ContainsKey(((AnimatorStateInfo)(ref nextAnimatorStateInfo)).fullPathHash)) { val = nextAnimatorStateInfo; } } if (States.TryGetValue(((AnimatorStateInfo)(ref val)).fullPathHash, out var value)) { int num2 = ((!value.StartsWith("fox_emote_")) ? 1 : 2); if (num2 > num) { result = value; num = num2; phase = ((value == "fox_sit") ? Mathf.Repeat(Mathf.Max(0f, ((AnimatorStateInfo)(ref val)).normalizedTime), 1f) : Mathf.Clamp01(((AnimatorStateInfo)(ref val)).normalizedTime)); } } } return result; } } internal readonly record struct FoxPalette { internal int Coat { get; } internal int Eye { get; } internal static readonly string[] Coats = new string[6] { "Red", "Gold", "Silver", "Arctic", "Brown", "Black" }; internal static readonly string[] Eyes = new string[6] { "Green", "Amber", "Blue", "Brown", "Gray", "Violet" }; internal FoxPalette(int coat, int eye) { Coat = ((coat >= 0 && coat < Coats.Length) ? coat : 0); Eye = ((eye >= 0 && eye < Eyes.Length) ? eye : 0); } internal FoxPalette ChangeCoat(int delta) { return new FoxPalette((Coat + delta % Coats.Length + Coats.Length) % Coats.Length, Eye); } internal FoxPalette ChangeEye(int delta) { return new FoxPalette(Coat, (Eye + delta % Eyes.Length + Eyes.Length) % Eyes.Length); } [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { return false; } } internal sealed class FoxPickupAnimation { internal const float Duration = 1.05f; private float _remaining; internal static bool ShouldInterrupt(bool confirmedTransfer, float speed, bool working, bool blocked) { if (!blocked) { if (!confirmedTransfer) { return speed > 1.2f || working; } return false; } return true; } internal bool Begin() { if (_remaining > 0f) { return false; } _remaining = 1.05f; return true; } internal bool Tick(float delta, bool interrupted) { if (interrupted) { Reset(); } _remaining = Math.Max(0f, _remaining - Math.Max(0f, delta)); return _remaining > 0f; } internal void Reset() { _remaining = 0f; } } [HarmonyPatch(typeof(PickupInteractionSession), "_WaitForAction")] internal static class FoxPickupHooks { private static void Postfix(PickupInteractionSession __instance, IEnumerator __result) { try { if (__result != null) { IInteractionAgent agent = ((InteractionSession)__instance).Agent; object obj; if (agent == null) { obj = null; } else { PlayerInteractionAgent obj2 = ((Il2CppObjectBase)agent).TryCast<PlayerInteractionAgent>(); obj = ((obj2 != null) ? obj2.GetCharacter() : null); } PlayerCharacter val = (PlayerCharacter)obj; if ((Object)(object)val != (Object)null) { Plugin.Behaviour?.Pickup(((Component)val).gameObject); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox pickup visual skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(CharacterGeometry), "TriggerAction")] internal static class FoxNativeActionHook { private static void Postfix(CharacterGeometry __instance, string actionName) { try { string text = FoxActionMapping.Action(actionName); if (text != null) { Plugin.Behaviour?.NativeAction(((Component)__instance).gameObject, text); } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox action visual skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(PickupCreatureInteractionSession), "_OnTargetMatched")] internal static class FoxCreaturePickupHook { private static void Postfix(PickupCreatureInteractionSession __instance, bool matched) { try { if (matched) { IInteractionAgent agent = ((InteractionSession)__instance).Agent; object obj; if (agent == null) { obj = null; } else { PlayerInteractionAgent obj2 = ((Il2CppObjectBase)agent).TryCast<PlayerInteractionAgent>(); obj = ((obj2 != null) ? obj2.GetCharacter() : null); } PlayerCharacter val = (PlayerCharacter)obj; if ((Object)(object)val != (Object)null) { Plugin.Behaviour?.Pickup(((Component)val).gameObject); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox creature pickup visual skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(PlayerGatherInteractionSession), "BeginAction")] internal static class FoxGatherStartedHook { private static void Postfix(PlayerGatherInteractionSession __instance) { try { PlayerInteractionAgent playerAgent = __instance.PlayerAgent; PlayerCharacter val = ((playerAgent != null) ? playerAgent.GetCharacter() : null); if ((Object)(object)val != (Object)null) { Plugin.Behaviour?.WorkPulse(((Component)val).gameObject); } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox gather visual skipped: " + ex.Message)); } } } [HarmonyPatch(typeof(PlayerHarvestInteractionSession), "_OnBeginDamageSwing")] internal static class FoxHarvestSwingHook { private static void Postfix(PlayerHarvestInteractionSession __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 try { if ((int)((InteractionSession)__instance).SessionState != 2) { return; } PlayerInteractionAgent playerAgent = __instance.PlayerAgent; PlayerCharacter val = ((playerAgent != null) ? playerAgent.GetCharacter() : null); if ((Object)(object)val != (Object)null) { HarvestInteraction harvestInteraction = __instance.HarvestInteraction; object moveset; if (harvestInteraction == null) { moveset = null; } else { InteractionMoveset attackMoveset = harvestInteraction.GetAttackMoveset(); moveset = ((attackMoveset != null) ? ((Object)attackMoveset).name : null); } if (FoxActionMapping.ImpactHarvest((string)moveset)) { Plugin.Behaviour?.NativeAction(((Component)val).gameObject, "wolf_attack1"); } else { Plugin.Behaviour?.WorkPulse(((Component)val).gameObject); } } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("Fox harvest visual skipped: " + ex.Message)); } } } internal static class FoxPortrait { private static Texture2D _texture; private static Sprite _sprite; internal static Sprite Get() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_sprite != (Object)null) { return _sprite; } using Stream stream = typeof(FoxPortrait).Assembly.GetManifestResourceStream("AskaWolfPrototype.FoxPortrait.png") ?? throw new InvalidOperationException("Embedded Fox portrait is missing."); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); try { if (!ImageConversion.LoadImage(val, new Il2CppStructArray<byte>(memoryStream.ToArray()), true)) { throw new InvalidOperationException("Unity could not decode the Fox portrait PNG."); } ((Object)val).name = "AskaWolfPrototype_FoxPortrait"; ((Objec