using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; 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.Logging; using BepInEx.Unity.IL2CPP; using Fusion; using HarmonyLib; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using Microsoft.CodeAnalysis; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Nuisance")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Nuisance")] [assembly: AssemblyTitle("Nuisance")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ShiftAtMidnightNuisance { internal sealed class AtlasTuning { public sealed class Placement { public Vector3 Offset; public float Scale = 1f; } private static readonly Dictionary Saved = new Dictionary(StringComparer.OrdinalIgnoreCase); public static Placement For(string effect) { if (!Saved.TryGetValue(effect, out var value)) { value = new Placement(); Saved[effect] = value; } return value; } public static void Set(string effect, Vector3 offset, float scale) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) Placement placement = For(effect); placement.Offset = offset; if (scale > 0f) { placement.Scale = scale; } } } internal sealed class BodyEmote { private Emote _emote; private Animator _suspended; private GameObject _prop; private List _attached; private readonly List _carried = new List(); private readonly List _carriedWere = new List(); private readonly DonorPuppet _puppet = new DonorPuppet(); private Dictionary _skeleton; private Transform _root; private Quaternion _facing; private Transform _floor; private readonly List _posed = new List(); private readonly List _posedRest = new List(); private Transform _hips; private Vector3 _hipsRest; private Quaternion _rootRest; private const int VerifyAfterFrames = 2; private const float MeaningfulDegrees = 1f; private readonly List _verify = new List(); private readonly List _verifyRest = new List(); private int _verifyIn; private static bool _reportedDrift; private const string HipsBone = "mixamorig:Hips"; private static readonly string[] ToeBones = new string[2] { "mixamorig:LeftToeBase", "mixamorig:RightToeBase" }; private const float GroundTolerance = 0.001f; private static bool _reportedSkeletons; public bool Active => _emote != null; public string Current => _emote?.Name; public bool Apply(ThirdPersonManager body, Emote emote, float yaw) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body == (Object)null || emote == null) { return false; } if (!EmoteCatalog.Resolve()) { return false; } if (!EmoteCatalog.All.Contains(emote)) { ModLog.Msg("'" + emote.Name + "' is not on this rig, so there is nothing to play."); return false; } if (Active) { Clear(0f); } _facing = Quaternion.Euler(0f, yaw, 0f); Animator bodyAnim = body.bodyAnim; if ((Object)(object)bodyAnim == (Object)null) { ModLog.Warning("That body has no animator."); return false; } try { Transform val = Rig.AttachPoint(((Component)bodyAnim).transform, EmoteCatalog.DonorHipsPath) ?? ((Component)bodyAnim).transform; if (!_puppet.Build(EmoteCatalog.Donor, emote.Clip)) { return false; } _root = val; _skeleton = DonorPuppet.Skeleton(val); ReportSkeletons(val, ((Object)(object)body.armsAnim != (Object)null) ? ((Component)body.armsAnim).transform : null, _skeleton); if (_skeleton.Count == 0) { ModLog.Warning("No Mixamo bones found under '" + ((Object)val).name + "' to pose."); _puppet.Destroy(); return false; } _floor = ((Component)bodyAnim).transform; SnapshotRest(); _suspended = bodyAnim; ((Behaviour)_suspended).enabled = false; _emote = emote; HideCarried(body); DropProp(emote, val); _attached = NuisanceAtlas.Attach(emote, _skeleton, null, val); ModLog.Debug($"'{emote.Name}' posing {_skeleton.Count} bones under '{((Object)val).name}'."); return true; } catch (Exception ex) { ModLog.Error("Could not start '" + emote.Name + "': " + ex.Message); Clear(); return false; } } public void Tick() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) VerifyRest(); if (!Active) { return; } try { if ((Object)(object)_suspended != (Object)null && ((Behaviour)_suspended).enabled) { ((Behaviour)_suspended).enabled = false; } if (!_puppet.Valid) { Clear(); return; } if ((Object)(object)_root != (Object)null) { _root.rotation = _facing; _puppet.Follow(_root.position); } NuisanceAtlas.Keep(_attached); _puppet.Hold(_emote.Clip); _puppet.PoseOnto(_skeleton); Ground(); } catch (Exception ex) { ModLog.Warning("'" + _emote?.Name + "' stopped: " + ex.Message); Clear(); } } private void SnapshotRest() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) _posed.Clear(); _posedRest.Clear(); foreach (Transform value in _skeleton.Values) { if (!((Object)(object)value == (Object)null)) { _posed.Add(value); _posedRest.Add(value.localRotation); } } _skeleton.TryGetValue("mixamorig:Hips", out _hips); if ((Object)(object)_hips != (Object)null) { _hipsRest = _hips.localPosition; } _rootRest = (((Object)(object)_root != (Object)null) ? _root.localRotation : Quaternion.identity); } private void RestoreRest() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _posed.Count; i++) { if (!((Object)(object)_posed[i] == (Object)null)) { try { _posed[i].localRotation = _posedRest[i]; } catch { } } } if ((Object)(object)_hips != (Object)null) { try { _hips.localPosition = _hipsRest; } catch { } } if ((Object)(object)_root != (Object)null) { try { _root.localRotation = _rootRest; } catch { } } ArmVerify(); _posed.Clear(); _posedRest.Clear(); } private static float AngleBetween(Quaternion a, Quaternion b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) float num = Mathf.Abs(a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w); return Mathf.Acos(Mathf.Clamp(num, -1f, 1f)) * 2f * 57.29578f; } private void ArmVerify() { if (!_reportedDrift && _posed.Count != 0) { _verify.Clear(); _verifyRest.Clear(); _verify.AddRange(_posed); _verifyRest.AddRange(_posedRest); _verifyIn = 2; } } private void VerifyRest() { //IL_006e: 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) if (_verifyIn <= 0 || _reportedDrift || --_verifyIn > 0) { return; } string value = null; float num = 0f; int num2 = 0; for (int i = 0; i < _verify.Count; i++) { Transform val = _verify[i]; if ((Object)(object)val == (Object)null) { continue; } float num3 = AngleBetween(val.localRotation, _verifyRest[i]); if (!(num3 < 1f)) { num2++; if (!(num3 <= num)) { num = num3; value = ((Object)val).name; } } } _verify.Clear(); _verifyRest.Clear(); if (num2 != 0) { _reportedDrift = true; ModLog.Warning($"The rest pose did not hold: {num2} bone(s) moved back after the emote was stopped, worst '{value}' by {num:0.#} degrees. Something is " + "writing the skeleton after Nuisance puts it back."); } } private void Ground() { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_hips == (Object)null || (Object)(object)_floor == (Object)null || _skeleton == null) { return; } float num = float.MaxValue; for (int i = 0; i < ToeBones.Length; i++) { if (_skeleton.TryGetValue(ToeBones[i], out var value) && !((Object)(object)value == (Object)null) && value.position.y < num) { num = value.position.y; } } if (num == float.MaxValue) { return; } float num2 = _floor.position.y - num; if (!(Mathf.Abs(num2) < 0.001f)) { float num3 = (((Object)(object)_hips.parent != (Object)null) ? _hips.parent.lossyScale.y : 1f); if (!Mathf.Approximately(num3, 0f)) { Transform hips = _hips; hips.localPosition += new Vector3(0f, num2 / num3, 0f); } } } public void Clear() { Clear(Settings.PropLifetime); } private void Clear(float propLifetime) { _puppet.Destroy(); RestoreRest(); if ((Object)(object)_suspended != (Object)null) { try { ((Behaviour)_suspended).enabled = true; } catch { } } NuisanceProps.Retire(_prop, propLifetime); ClearAttached(); RestoreCarried(); _prop = null; _skeleton = null; _root = null; _floor = null; _hips = null; _suspended = null; _emote = null; } private void DropProp(Emote emote, Transform at) { if ((Object)(object)_prop != (Object)null) { NuisanceProps.Retire(_prop, 0f); _prop = null; } ClearAttached(); _prop = NuisanceProps.Drop(emote, at); } private static void ReportSkeletons(Transform attach, Transform arms, Dictionary mounts) { if (_reportedSkeletons || !ModLog.Verbose) { return; } _reportedSkeletons = true; Dictionary dictionary = DonorPuppet.Skeleton(attach); ModLog.Debug($"[rig] root '{((Object)attach).name}': {dictionary.Count} bone(s), {mounts.Count} outside the arms."); ModLog.Debug($"[rig] arms '{(((Object)(object)arms != (Object)null) ? ((Object)arms).name : "(none)")}' under root: {(((Object)(object)arms != (Object)null && arms.IsChildOf(attach)) ? "yes" : "no")}"); string[] array = new string[3] { "mixamorig:RightHand", "mixamorig:Head", "mixamorig:Hips" }; foreach (string text in array) { ModLog.Debug($"[rig] {text}: whole='{Path(dictionary.TryGetValue(text, out var value) ? value : null, attach)}', mount='{Path(mounts.TryGetValue(text, out value) ? value : null, attach)}'"); } foreach (SkinnedMeshRenderer item in Interop.Safe(((Component)attach).GetComponentsInChildren(true))) { ModLog.Debug($"[skin] '{((Object)item).name}' enabled={((Renderer)item).enabled} visible={((Component)item).gameObject.activeInHierarchy} bones={((item.bones != null) ? ((Il2CppArrayBase)(object)item.bones).Length : 0)} root='{Path(item.rootBone, attach)}'"); } } private static string Path(Transform bone, Transform stopAt) { if ((Object)(object)bone == (Object)null) { return "(none)"; } string text = ((Object)bone).name; Transform parent = bone.parent; while ((Object)(object)parent != (Object)null && ((Il2CppObjectBase)parent).Pointer != ((Il2CppObjectBase)stopAt).Pointer) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } private void HideCarried(ThirdPersonManager body) { RestoreCarried(); try { foreach (GameObject item in Interop.Safe((Il2CppArrayBase)(object)body.objs)) { _carried.Add(item); _carriedWere.Add(item.activeSelf); if (item.activeSelf) { item.SetActive(false); } } ModLog.Debug($"Put away {_carried.Count} carried object(s)."); } catch (Exception ex) { ModLog.Warning("Could not put the held item away: " + ex.Message); } } private void RestoreCarried() { for (int i = 0; i < _carried.Count; i++) { try { if ((Object)(object)_carried[i] != (Object)null) { _carried[i].SetActive(_carriedWere[i]); } } catch { } } _carried.Clear(); _carriedWere.Clear(); } private void ClearAttached() { if (_attached == null) { return; } foreach (NuisanceAtlas.AttachedEffect item in _attached) { try { if ((Object)(object)item?.Obj != (Object)null) { Object.Destroy((Object)(object)item.Obj); } } catch { } } _attached = null; } } internal sealed class BodyLock { private bool _ours; public bool Held { get; private set; } public void Hold() { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { return; } FPSController fpsScript = localPlayerManager.fpsScript; if ((Object)(object)fpsScript == (Object)null) { return; } try { if (!Held) { _ours = !fpsScript.lockMove; Held = true; } if (_ours && !fpsScript.lockMove) { fpsScript.lockMove = true; } } catch (Exception ex) { ModLog.Warning("Could not hold the body still: " + ex.Message); Release(); } } public void ForceRelease() { Held = false; _ours = false; try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; FPSController val = ((localPlayerManager != null) ? localPlayerManager.fpsScript : null); if ((Object)(object)val != (Object)null && val.lockMove) { val.lockMove = false; } } catch (Exception ex) { ModLog.Warning("Could not release the body: " + ex.Message); } } public void Release() { if (!Held) { return; } Held = false; if (!_ours) { return; } _ours = false; try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; FPSController val = ((localPlayerManager != null) ? localPlayerManager.fpsScript : null); if ((Object)(object)val != (Object)null) { val.lockMove = false; } } catch (Exception ex) { ModLog.Warning("Could not release the body: " + ex.Message); } } } internal sealed class BodyVisibility { private readonly List _parts = new List(); private readonly List _partsWere = new List(); private readonly List _hidden = new List(); private readonly List _hiddenWere = new List(); private bool _captured; public void Show() { ThirdPersonManager localBody = NetworkContext.LocalBody; if ((Object)(object)localBody == (Object)null) { return; } if (!_captured) { Capture(localBody); } for (int i = 0; i < _hidden.Count; i++) { try { if ((Object)(object)_hidden[i] != (Object)null && _hidden[i].activeSelf) { _hidden[i].SetActive(false); } } catch { } } for (int j = 0; j < _parts.Count; j++) { SkinnedMeshRenderer val = _parts[j]; try { if ((Object)(object)val != (Object)null && !((Renderer)val).enabled) { ((Renderer)val).enabled = true; } } catch { } } } public void Restore() { if (!_captured) { return; } for (int i = 0; i < _parts.Count; i++) { try { if ((Object)(object)_parts[i] != (Object)null) { ((Renderer)_parts[i]).enabled = _partsWere[i]; } } catch { } } for (int j = 0; j < _hidden.Count; j++) { try { if ((Object)(object)_hidden[j] != (Object)null) { _hidden[j].SetActive(_hiddenWere[j]); } } catch { } } ModLog.Debug($"Body restored: {_parts.Count} renderer(s), {_hidden.Count} first person object(s)."); Forget(); } public void Forget() { _hidden.Clear(); _hiddenWere.Clear(); _parts.Clear(); _partsWere.Clear(); _captured = false; } private void Conceal(GameObject obj) { if (!((Object)(object)obj == (Object)null)) { _hidden.Add(obj); _hiddenWere.Add(obj.activeSelf); } } private void Capture(ThirdPersonManager body) { _captured = true; try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; InventoryManager val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.inventoryMan : null); if ((Object)(object)val != (Object)null) { foreach (GameObject item in Interop.Safe((Il2CppArrayBase)(object)val.holdingObjs)) { Conceal(item); } } } catch (Exception ex) { ModLog.Warning("Could not reach the held items: " + ex.Message); } Transform val2 = (((Object)(object)body.bodyAnim != (Object)null) ? ((Component)body.bodyAnim).transform : null); foreach (SkinnedMeshRenderer item2 in Interop.Safe((Il2CppArrayBase)(object)body.models)) { Transform parent = ((Component)item2).transform.parent; if (!((Object)(object)val2 != (Object)null) || (!((Object)(object)parent == (Object)null) && !(((Il2CppObjectBase)parent).Pointer != ((Il2CppObjectBase)val2).Pointer))) { _parts.Add(item2); _partsWere.Add(((Renderer)item2).enabled); } } Report(); } private void Report() { if (ModLog.Verbose) { List list = new List(); for (int i = 0; i < _parts.Count; i++) { list.Add($"{(((Object)(object)_parts[i] != (Object)null) ? ((Object)_parts[i]).name : "null")}={_partsWere[i]}"); } ModLog.Debug("[body] " + ((list.Count == 0) ? "(no renderers found)" : string.Join(", ", list))); } } } internal sealed class DonorPuppet { private const string BonePrefix = "mixamorig:"; private GameObject _root; private Animator _animator; private int _stateHash; private readonly List _bones = new List(); public bool Valid => (Object)(object)_animator != (Object)null && (Object)(object)_root != (Object)null; public Transform Hips { get; private set; } public bool Build(GameObject donorPrefab, string clipName) { Destroy(); _root = LocalModel.Create(donorPrefab); if ((Object)(object)_root == (Object)null) { return false; } _animator = _root.GetComponent() ?? _root.GetComponentInChildren(true); if ((Object)(object)_animator == (Object)null) { ModLog.Warning("The puppet came out with no animator."); Destroy(); return false; } try { _animator.applyRootMotion = false; } catch { } Collect(); _stateHash = Animator.StringToHash(clipName); _animator.SetTrigger(clipName); ModLog.Debug($"Puppet playing '{clipName}' with {_bones.Count} bones."); return true; } public void Hold(string clipName) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!Valid) { return; } try { AnimatorStateInfo currentAnimatorStateInfo = _animator.GetCurrentAnimatorStateInfo(0); if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash != _stateHash) { _animator.SetTrigger(clipName); } } catch { } } public void Follow(Vector3 position) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_root != (Object)null) { _root.transform.position = position; } } public void Destroy() { if ((Object)(object)_root != (Object)null) { try { Object.Destroy((Object)(object)_root); } catch { } } _root = null; _animator = null; Hips = null; _bones.Clear(); } public void PoseOnto(Dictionary target) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) if (!Valid || target == null) { return; } for (int i = 0; i < _bones.Count; i++) { Transform val = _bones[i]; if (!((Object)(object)val == (Object)null) && target.TryGetValue(((Object)val).name, out var value) && !((Object)(object)value == (Object)null)) { value.localRotation = val.localRotation; if (!((Object)(object)Hips == (Object)null) && !(((Il2CppObjectBase)val).Pointer != ((Il2CppObjectBase)Hips).Pointer)) { Vector3 val2 = (((Object)(object)val.parent != (Object)null) ? Vector3.Scale(val.localPosition, val.parent.lossyScale) : val.localPosition); value.localPosition = (((Object)(object)value.parent != (Object)null) ? Divide(val2, value.parent.lossyScale) : val2); } } } } private static bool Under(Transform t, Transform ancestor) { Transform val = t; while ((Object)(object)val != (Object)null) { if (((Il2CppObjectBase)val).Pointer == ((Il2CppObjectBase)ancestor).Pointer) { return true; } val = val.parent; } return false; } private static Vector3 Divide(Vector3 value, Vector3 by) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) return new Vector3(Mathf.Approximately(by.x, 0f) ? value.x : (value.x / by.x), Mathf.Approximately(by.y, 0f) ? value.y : (value.y / by.y), Mathf.Approximately(by.z, 0f) ? value.z : (value.z / by.z)); } public static Dictionary Skeleton(Transform root, Transform exclude = null) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); if ((Object)(object)root == (Object)null) { return dictionary; } foreach (Transform item in Interop.Safe(((Component)root).GetComponentsInChildren(true))) { if (((Object)item).name.StartsWith("mixamorig:", StringComparison.Ordinal) && (!((Object)(object)exclude != (Object)null) || !Under(item, exclude)) && (!dictionary.TryGetValue(((Object)item).name, out var value) || Depth(value, root) > Depth(item, root))) { dictionary[((Object)item).name] = item; } } return dictionary; } private static int Depth(Transform t, Transform root) { int num = 0; Transform val = t; while ((Object)(object)val != (Object)null && ((Il2CppObjectBase)val).Pointer != ((Il2CppObjectBase)root).Pointer) { num++; val = val.parent; } return num; } private void Collect() { _bones.Clear(); foreach (Transform item in Interop.Safe(_root.GetComponentsInChildren(true))) { if (((Object)item).name.StartsWith("mixamorig:", StringComparison.Ordinal)) { _bones.Add(item); if ((Object)(object)Hips == (Object)null && ((Object)item).name.StartsWith("mixamorig:Hips", StringComparison.Ordinal)) { Hips = item; } } } } } internal sealed class Emote { public readonly string Name; public readonly string Clip; public readonly string Group; public Emote(string name, string clip, string group) { Name = name; Clip = clip; Group = group; } } internal static class EmoteCatalog { private const string Nuisance = "Nuisance"; private const string Dances = "Dances"; private static List _all; private const float ShortestBelievableClip = 1.1f; private const string ProbeClip = "Peeing"; private static GameObject _donor; private static bool _searched; public static List All => _all ?? (_all = Build()); public static List Groups { get { List list = new List(); foreach (Emote item in All) { if (!list.Contains(item.Group)) { list.Add(item.Group); } } return list; } } public static GameObject Donor => _donor; public static string DonorHipsPath { get; private set; } private static List Build() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) AtlasTuning.Set("Jackhammer", Vector3.zero, 0.01f); return new List { new Emote("Pee", "Peeing", "Nuisance"), new Emote("Puke", "Vomiting", "Nuisance"), new Emote("Airhorn", "Airhorning", "Nuisance"), new Emote("Sleep", "Sleeping", "Nuisance"), new Emote("Jackhammer", "Jackhammer", "Nuisance"), new Emote("Dance", "Dancing", "Dances"), new Emote("Breakdance", "Breakdancing", "Dances"), new Emote("Weird Dance", "Weird Dancing", "Dances") }; } public static List InGroup(string group) { List list = new List(); foreach (Emote item in All) { if (item.Group == group) { list.Add(item); } } return list; } public static Emote Find(string name) { if (string.IsNullOrEmpty(name)) { return null; } foreach (Emote item in All) { if (string.Equals(item.Name, name, StringComparison.OrdinalIgnoreCase)) { return item; } } return null; } public static void Forget() { _donor = null; _searched = false; } public static bool Resolve() { if ((Object)(object)_donor != (Object)null) { return true; } if (_searched) { return false; } _searched = true; Animator val = null; int num = 0; try { List list = new List(); foreach (Animator item in Interop.Safe(Resources.FindObjectsOfTypeAll())) { RuntimeAnimatorController runtimeAnimatorController; try { runtimeAnimatorController = item.runtimeAnimatorController; } catch { continue; } if ((Object)(object)runtimeAnimatorController == (Object)null || list.Contains(((Il2CppObjectBase)runtimeAnimatorController).Pointer)) { continue; } list.Add(((Il2CppObjectBase)runtimeAnimatorController).Pointer); if ((Object)(object)FindClip(runtimeAnimatorController, "Peeing") == (Object)null) { continue; } int num2 = 0; foreach (Emote item2 in All) { if ((Object)(object)FindClip(runtimeAnimatorController, item2.Clip) != (Object)null) { num2++; } } if (num2 > num) { num = num2; val = item; if (num == All.Count) { break; } } } } catch (Exception ex) { ModLog.Warning("Rig search failed: " + ex.Message); } if ((Object)(object)val == (Object)null) { ModLog.Warning("No humanoid rig with the nuisance animations is loaded yet. Emotes will come up once you are in a day."); _searched = false; return false; } _donor = ((Component)val).gameObject; DonorHipsPath = Rig.HipsPath(((Component)val).transform); Report(val.runtimeAnimatorController); ModLog.Msg($"Emotes taken from '{((Object)_donor).name}', which has {num} of {All.Count}."); ModLog.Debug(" donor hips path: '" + (DonorHipsPath ?? "(none)") + "'"); return true; } private static void Report(RuntimeAnimatorController controller) { List list = new List(); List list2 = new List(); for (int num = All.Count - 1; num >= 0; num--) { Emote emote = All[num]; AnimationClip val = FindClip(controller, emote.Clip); if ((Object)(object)val == (Object)null) { list2.Add(emote.Name + " (" + emote.Clip + ")"); All.RemoveAt(num); } else { ModLog.Debug($" '{emote.Clip}' {val.length:0.##}s"); if (val.length <= 1.1f) { list.Add(emote.Name); } } } if (list2.Count > 0) { ModLog.Warning("Not on this rig, dropped from the wheel: " + string.Join(", ", list2)); } if (list.Count > 0) { ModLog.Msg("The game ships " + string.Join(", ", list) + " as an empty animation - those emotes drop their prop but barely move. Not a fault of the mod."); } } private static AnimationClip FindClip(RuntimeAnimatorController controller, string name) { try { foreach (AnimationClip item in Interop.Safe((Il2CppArrayBase)(object)controller.animationClips)) { if (string.Equals(((Object)item).name, name, StringComparison.OrdinalIgnoreCase)) { return item; } } } catch { } return null; } } internal sealed class EmoteSync { private sealed class Wanted { public string Emote; public int Seq; public float Yaw; } private sealed class Playing { public readonly BodyEmote Body = new BodyEmote(); public string Name; public int Seq = -1; } private const string Key = "nuisance"; private const string Version = "2"; private const char Separator = '|'; private const float PollInterval = 0.25f; private readonly Dictionary _wanted = new Dictionary(); private readonly Dictionary _playing = new Dictionary(); private readonly List _seen = new List(); private float _nextPoll; private string _published; private int _localSeq; private float _localYaw; public string LocalChoice { get; private set; } public int Publishers { get; private set; } public int Members { get; private set; } public void Start(Emote emote) { if (emote != null) { LocalChoice = emote.Name; _localSeq++; _localYaw = LocalYaw(); _nextPoll = 0f; } } private static float LocalYaw() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) try { ThirdPersonManager localBody = NetworkContext.LocalBody; if ((Object)(object)localBody == (Object)null || (Object)(object)localBody.bodyAnim == (Object)null) { return 0f; } return ((Component)localBody.bodyAnim).transform.eulerAngles.y; } catch { return 0f; } } public void Stop() { LocalChoice = null; _nextPoll = 0f; } public void Tick() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) try { CSteamID val = Lobby(); if (val.m_SteamID != 0) { Publish(val); } if (!(Time.unscaledTime < _nextPoll)) { _nextPoll = Time.unscaledTime + 0.25f; if (val.m_SteamID != 0) { Poll(val); } ApplyLocal(); ApplyAll(); } } catch (Exception value) { ModLog.Error($"Sync: {value}"); } } public void LateTick() { foreach (Playing value in _playing.Values) { value.Body.Tick(); } } public void Clear() { foreach (Playing value in _playing.Values) { try { value.Body.Clear(); } catch { } } _playing.Clear(); _wanted.Clear(); _published = null; } private void Publish(CSteamID lobby) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) int localPlayerId = NetworkContext.LocalPlayerId; if (localPlayerId >= 0) { string text = (string.IsNullOrEmpty(LocalChoice) ? ("2|" + localPlayerId) : ("2|" + localPlayerId + "|" + LocalChoice + "|" + _localSeq + "|" + _localYaw.ToString("0.##", CultureInfo.InvariantCulture))); if (!(text == _published)) { SteamMatchmaking.SetLobbyMemberData(lobby, "nuisance", text); _published = text; } } } private void Poll(CSteamID lobby) { //IL_0016: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) _wanted.Clear(); Publishers = 0; Members = SteamMatchmaking.GetNumLobbyMembers(lobby); for (int i = 0; i < Members; i++) { CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(lobby, i); string lobbyMemberData = SteamMatchmaking.GetLobbyMemberData(lobby, lobbyMemberByIndex, "nuisance"); if (Mine(lobbyMemberData)) { Publishers++; if (Parse(lobbyMemberData, out var id, out var emote, out var seq, out var yaw)) { _wanted[id] = new Wanted { Emote = emote, Seq = seq, Yaw = yaw }; } } } } private void ApplyLocal() { int localPlayerId = NetworkContext.LocalPlayerId; if (localPlayerId >= 0) { if (string.IsNullOrEmpty(LocalChoice)) { _wanted.Remove(localPlayerId); return; } _wanted[localPlayerId] = new Wanted { Emote = LocalChoice, Seq = _localSeq, Yaw = _localYaw }; } } private static bool Mine(string raw) { return !string.IsNullOrEmpty(raw) && raw.StartsWith("2|", StringComparison.Ordinal); } private static bool Parse(string raw, out int id, out string emote, out int seq, out float yaw) { id = -1; seq = 0; yaw = 0f; emote = null; string[] array = raw.Split(new char[1] { '|' }, 5); if (array.Length != 5) { return false; } if (!int.TryParse(array[1], out id)) { return false; } if (!int.TryParse(array[3], out seq)) { return false; } if (!float.TryParse(array[4], NumberStyles.Float, CultureInfo.InvariantCulture, out yaw)) { return false; } if (string.IsNullOrEmpty(array[2])) { return false; } emote = array[2]; return true; } private void ApplyAll() { _seen.Clear(); foreach (ThirdPersonManager item in Interop.Safe(Resources.FindObjectsOfTypeAll())) { int num = FusionId(item); if (num < 0) { continue; } _seen.Add(num); if (!_wanted.TryGetValue(num, out var value)) { StopFor(num); continue; } Emote emote = EmoteCatalog.Find(value.Emote); if (emote == null) { StopFor(num); continue; } Playing playing = Track(num); if ((playing.Seq != value.Seq || !(playing.Name == emote.Name) || !playing.Body.Active) && playing.Body.Apply(item, emote, value.Yaw)) { playing.Seq = value.Seq; playing.Name = emote.Name; } } PruneDeparted(); } private Playing Track(int id) { if (!_playing.TryGetValue(id, out var value)) { value = new Playing(); _playing[id] = value; } return value; } private void StopFor(int id) { if (_playing.TryGetValue(id, out var value) && value.Body.Active) { value.Body.Clear(); value.Name = null; value.Seq = -1; } } private void PruneDeparted() { List list = null; foreach (KeyValuePair item in _playing) { if (!_seen.Contains(item.Key)) { (list ?? (list = new List())).Add(item.Key); } } if (list == null) { return; } foreach (int item2 in list) { try { _playing[item2].Body.Clear(); } catch { } _playing.Remove(item2); } } private static int FusionId(ThirdPersonManager body) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)body == (Object)null)) { Scene scene = ((Component)body).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { NetworkObject val = FindNetworkObject(((Component)body).transform); if ((Object)(object)val == (Object)null || !val.IsValid) { return -1; } PlayerRef inputAuthority = val.InputAuthority; return ((PlayerRef)(ref inputAuthority)).PlayerId; } } return -1; } catch { return -1; } } private static NetworkObject FindNetworkObject(Transform from) { Transform val = from; while ((Object)(object)val != (Object)null) { NetworkObject component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } val = val.parent; } return null; } private static CSteamID Lobby() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) try { PlatformManager instance = PlatformManager.Instance; if ((Object)(object)instance == (Object)null) { return default(CSteamID); } return new CSteamID { m_SteamID = instance._lobbyID }; } catch { return default(CSteamID); } } } internal sealed class EmoteWheel { public enum Result { Nothing, Play, Cancel } private const float Radius = 165f; private const float ItemWidth = 128f; private const float ItemHeight = 26f; private const float DeadZone = 0.35f; private const float AimGain = 0.08f; private int _column; private int _row; private bool _open; private Vector2 _aim; private const int Nothing = -1; private readonly WheelUI _ui = new WheelUI(); private readonly WheelInput _input = new WheelInput(); private const float HoldToOpen = 0.14f; private float _pressedAt; private bool _pressed; private bool _drawn; public bool Open => _open; public Emote Selected { get { List list = Column(); if (_row < 0 || list.Count == 0) { return null; } return list[Mathf.Clamp(_row, 0, list.Count - 1)]; } } public Result Tick(KeyCode key, out Emote chosen) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) chosen = null; if (Input.GetKeyDown(key)) { _pressed = true; _pressedAt = Time.unscaledTime; EmoteCatalog.Resolve(); return Result.Nothing; } if (_pressed && Input.GetKey(key)) { if (!_open && Time.unscaledTime - _pressedAt < 0.14f) { return Result.Nothing; } if (!_open) { _open = true; _aim = Vector2.zero; _row = -1; } _input.Hold(camera: true); Steer(); Present(); return Result.Nothing; } if (!_pressed) { return Result.Nothing; } _pressed = false; bool open = _open; Close(); if (!open) { return Result.Cancel; } chosen = Selected; return (chosen != null) ? Result.Play : Result.Cancel; } public void Close() { _open = false; _drawn = false; _ui.Hide(); _input.Release(); } public void Forget() { _ui.Destroy(); _input.Release(); } private void Present() { _drawn = false; List list = Groups(); if (list.Count != 0) { int num = Mathf.Clamp(_column, 0, list.Count - 1); _drawn = _ui.Show(Column(), _row, list[num], num > 0, num < list.Count - 1); } } private static List Groups() { return EmoteCatalog.Groups; } private List Column() { List list = Groups(); if (list.Count == 0) { return new List(); } return EmoteCatalog.InGroup(list[Mathf.Clamp(_column, 0, list.Count - 1)]); } private void Steer() { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0162: 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_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) List list = Groups(); if (list.Count == 0) { return; } int column = _column; if (Input.GetKeyDown((KeyCode)274)) { _column++; } if (Input.GetKeyDown((KeyCode)273)) { _column--; } float axis = Input.GetAxis("Mouse ScrollWheel"); if (axis < -0.001f) { _column++; } else if (axis > 0.001f) { _column--; } _column = Mathf.Clamp(_column, 0, list.Count - 1); if (_column != column) { _row = -1; _aim = Vector2.zero; } int count = Column().Count; if (count != 0) { if (Input.GetKeyDown((KeyCode)275)) { _row = Wrap(_row + 1, count); _aim = Vector2.zero; } if (Input.GetKeyDown((KeyCode)276)) { _row = Wrap(_row - 1, count); _aim = Vector2.zero; } _aim += new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")) * 0.08f; if (((Vector2)(ref _aim)).magnitude > 1f) { _aim = ((Vector2)(ref _aim)).normalized; } if (!(((Vector2)(ref _aim)).magnitude < 0.35f)) { float num = Mathf.Atan2(_aim.x, _aim.y) * 57.29578f; _row = Wrap(Mathf.RoundToInt(num / (360f / (float)count)), count); } } } private static int Wrap(int value, int count) { return (value % count + count) % count; } public void Draw() { //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_013a: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (!_open || _drawn) { return; } List list = Groups(); if (list.Count == 0) { return; } List list2 = Column(); if (list2.Count == 0) { return; } Color color = GUI.color; try { Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor((float)Screen.width * 0.5f, (float)Screen.height * 0.5f); DrawHub(val, list, list2); float num = 360f / (float)list2.Count; for (int i = 0; i < list2.Count; i++) { float num2 = (float)i * num * ((float)Math.PI / 180f); Vector2 at = val + new Vector2(Mathf.Sin(num2), 0f - Mathf.Cos(num2)) * 165f; bool flag = i == _row; GUI.color = (Color)(flag ? Color.white : new Color(1f, 1f, 1f, 0.55f)); GUI.Box(Rect(at, flag), list2[i].Name); } GUI.color = color; DrawAim(val); } catch (Exception ex) { GUI.color = color; _open = false; ModLog.Error("Emote wheel failed to draw, closing it: " + ex.Message); } } private static Rect Rect(Vector2 at, bool selected) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) float num = (selected ? 140f : 128f); float num2 = (selected ? 30f : 26f); return new Rect(at.x - num * 0.5f, at.y - num2 * 0.5f, num, num2); } private void DrawHub(Vector2 centre, List groups, List rows) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) string text = ((groups.Count > 1) ? $"{((_column > 0) ? "^" : " ")} {Title(groups[_column])} {((_column < groups.Count - 1) ? "v" : " ")}" : Title(groups[_column])); string text2 = ((_row < 0) ? "Cancel" : rows[Mathf.Clamp(_row, 0, rows.Count - 1)].Name); GUI.Box(new Rect(centre.x - 80f, centre.y - 26f, 160f, 52f), text + "\n" + text2); } private void DrawAim(Vector2 centre) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (!(((Vector2)(ref _aim)).magnitude < 0.35f)) { Vector2 val = centre + ((Vector2)(ref _aim)).normalized * 105f; GUI.Box(new Rect(val.x - 4f, val.y - 4f, 8f, 8f), string.Empty); } } private static string Title(string group) { return string.IsNullOrEmpty(group) ? "EMOTES" : group.ToUpperInvariant(); } } internal static class InputBlock { private const string Id = "clementinise.shiftatmidnight.nuisance.input"; public static bool FreezeHotbar; private static Harmony _harmony; public static void Install() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown if (_harmony != null) { return; } try { _harmony = new Harmony("clementinise.shiftatmidnight.nuisance.input"); MethodInfo methodInfo = AccessTools.Method(typeof(InventoryManager), "ChangeInventorySlot", (Type[])null, (Type[])null); if (methodInfo == null) { ModLog.Warning("InventoryManager.ChangeInventorySlot not found - the hotbar will stay live during emotes."); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(InputBlock), "BeforeChangeSlot", (Type[])null, (Type[])null); _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ModLog.Debug("Hotbar switching patched."); } catch (Exception ex) { ModLog.Warning("Could not patch the hotbar: " + ex.Message); _harmony = null; } } public static void Remove() { FreezeHotbar = false; try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { ModLog.Warning("Could not unpatch the hotbar: " + ex.Message); } _harmony = null; } private static bool BeforeChangeSlot() { return !FreezeHotbar; } } internal static class Interop { public static IEnumerable Safe(Il2CppArrayBase array) where T : Il2CppObjectBase { if (array == null) { yield break; } for (int i = 0; i < array.Length; i++) { T v = array[i]; if (v != null) { yield return v; } } } public static IEnumerable Safe(List list) { if (list == null) { yield break; } for (int i = 0; i < list.Count; i++) { T v = list[i]; if (v != null) { yield return v; } } } } internal static class LocalModel { private const int MaxComponents = 4000; public static GameObject Create(GameObject prefab) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if ((Object)(object)prefab == (Object)null) { return null; } GameObject val = null; try { val = new GameObject("NuisanceHolder"); val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); GameObject val2 = Object.Instantiate(prefab, val.transform); int length = val2.GetComponentsInChildren(true).Length; if (length > 4000) { ModLog.Warning($"'{((Object)prefab).name}' has {length} components - too large to " + "strip safely, skipping to avoid freezing the game."); return null; } Strip(val2); ReportSurvivors(val2); val2.transform.SetParent((Transform)null, false); ((Object)val2).name = "NuisancePuppet_" + ((Object)prefab).name; val2.SetActive(true); Object.DontDestroyOnLoad((Object)(object)val2); ModLog.Debug($"Puppet '{((Object)prefab).name}': {length} components stripped."); return val2; } catch (Exception value) { ModLog.Error($"Failed to build a puppet from '{((Object)prefab).name}': {value}"); return null; } finally { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } private static void ReportSurvivors(GameObject clone) { List list = new List(); foreach (Component componentsInChild in clone.GetComponentsInChildren(true)) { if (!((Object)(object)componentsInChild == (Object)null) && !((Object)(object)((Il2CppObjectBase)componentsInChild).TryCast() != (Object)null) && !((Object)(object)((Il2CppObjectBase)componentsInChild).TryCast() != (Object)null)) { list.Add(((MemberInfo)((Object)componentsInChild).GetIl2CppType()).Name); } } if (list.Count > 0) { ModLog.Warning($"Puppet kept {list.Count} component(s): {string.Join(", ", list)}"); } } private static void Strip(GameObject root) { foreach (Component componentsInChild in root.GetComponentsInChildren(true)) { if (!((Object)(object)componentsInChild == (Object)null) && !((Object)(object)((Il2CppObjectBase)componentsInChild).TryCast() != (Object)null) && !((Object)(object)((Il2CppObjectBase)componentsInChild).TryCast() != (Object)null)) { try { Object.DestroyImmediate((Object)(object)componentsInChild, true); } catch { } } } } } internal static class ModLog { public static ManualLogSource Source; public static bool Verbose; public static void Debug(string message) { if (Verbose) { ManualLogSource source = Source; if (source != null) { source.LogInfo((object)message); } } } public static void Msg(string message) { ManualLogSource source = Source; if (source != null) { source.LogInfo((object)message); } } public static void Warning(string message) { ManualLogSource source = Source; if (source != null) { source.LogWarning((object)message); } } public static void Error(string message) { ManualLogSource source = Source; if (source != null) { source.LogError((object)message); } } } internal static class NetworkContext { public static NetworkRunner Runner { get { FusionNetworkManager instance = FusionNetworkManager.Instance; if ((Object)(object)instance == (Object)null) { return null; } NetworkRunner runner = instance._runner; if ((Object)(object)runner == (Object)null || !runner.IsRunning) { return null; } return runner; } } public static int LocalPlayerId { get { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) NetworkRunner runner = Runner; if ((Object)(object)runner == (Object)null) { return -1; } try { PlayerRef localPlayer = runner.LocalPlayer; return ((PlayerRef)(ref localPlayer)).PlayerId; } catch { return -1; } } } public static PlayerManager LocalPlayerManager { get { ClientPlayer instance = ClientPlayer.Instance; return ((Object)(object)instance == (Object)null) ? null : instance.playerMan; } } public static ThirdPersonManager LocalBody { get { PlayerManager localPlayerManager = LocalPlayerManager; return ((Object)(object)localPlayerManager == (Object)null) ? null : localPlayerManager.thirdPersonMan; } } } internal static class NuisanceAtlas { internal sealed class AttachedEffect { public GameObject Obj; public Transform Mount; public string Clip; public Vector3 BaseLocalPosition; public Vector3 BaseLocalScale; } private static readonly Dictionary EffectByClip = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "Vomiting", "vomit particles" }, { "Sleeping", "sleep particles" }, { "Airhorning", "airhorn" }, { "Jackhammer", "Jackhammer" }, { "Graffiti", "Graffiti Can" }, { "Swirly", "Slushie Machine" } }; private const string BonePrefix = "mixamorig:"; private static GameObject _customer; private static bool _searched; private static readonly List Blamed = new List(); private static bool _complained; public static void Forget() { _customer = null; _searched = false; } public static List Attach(Emote emote, Dictionary skeleton, Dictionary spare, Transform fallback) { List list = new List(); if (emote == null || skeleton == null) { return list; } try { GameObject val = Customer(); if ((Object)(object)val == (Object)null) { return list; } NuisanceCustomer component = val.GetComponent(); if ((Object)(object)component == (Object)null) { return list; } if (!EffectByClip.TryGetValue(emote.Clip, out var value)) { return list; } GameObject val2 = FindObject(component, value); if ((Object)(object)val2 == (Object)null) { ModLog.Debug("'" + value + "' is not on this customer."); return list; } AttachedEffect attachedEffect = CloneOnto(val2, emote.Clip, skeleton, spare, fallback); if (attachedEffect != null) { list.Add(attachedEffect); ModLog.Debug($"Attached '{value}' for '{emote.Clip}'."); } } catch (Exception ex) { ModLog.Warning("Could not attach the '" + emote.Name + "' effect: " + ex.Message); } return list; } private static AttachedEffect CloneOnto(GameObject original, string emoteClip, Dictionary skeleton, Dictionary spare, Transform fallback) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) Transform val = NearestBone(original.transform); if ((Object)(object)val == (Object)null) { ModLog.Debug("'" + ((Object)original).name + "' hangs from no bone."); return null; } Transform value; bool flag = skeleton.TryGetValue(((Object)val).name, out value) && (Object)(object)value != (Object)null; if (!flag && spare != null) { flag = spare.TryGetValue(((Object)val).name, out value) && (Object)(object)value != (Object)null; } if (!flag) { value = fallback; } if ((Object)(object)value == (Object)null) { return null; } Vector3 value2 = Quaternion.Inverse(val.rotation) * (original.transform.position - val.position); Quaternion localRotation = Quaternion.Inverse(val.rotation) * original.transform.rotation; GameObject val2 = Object.Instantiate(original, value, false); if ((Object)(object)val2 == (Object)null) { return null; } val2.transform.localPosition = Divide(value2, value.lossyScale); val2.transform.localRotation = localRotation; bool flag2 = (Object)(object)val2.GetComponentInChildren(true) != (Object)null; val2.transform.localScale = (flag2 ? original.transform.localScale : Divide(original.transform.lossyScale, value.lossyScale)); NuisanceProps.Detach(val2); Wake(val2); DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(35, 6); defaultInterpolatedStringHandler.AppendLiteral(" '"); defaultInterpolatedStringHandler.AppendFormatted(((Object)original).name); defaultInterpolatedStringHandler.AppendLiteral("' -> "); defaultInterpolatedStringHandler.AppendFormatted(flag ? ((Object)val).name : (((Object)value).name + " (no '" + ((Object)val).name + "' on the player)")); defaultInterpolatedStringHandler.AppendLiteral(", "); defaultInterpolatedStringHandler.AppendLiteral("world "); Vector3 val3 = val2.transform.position; defaultInterpolatedStringHandler.AppendFormatted(((Vector3)(ref val3)).ToString("0.##")); defaultInterpolatedStringHandler.AppendLiteral(" vs bone "); val3 = value.position; defaultInterpolatedStringHandler.AppendFormatted(((Vector3)(ref val3)).ToString("0.##")); defaultInterpolatedStringHandler.AppendLiteral(", "); defaultInterpolatedStringHandler.AppendLiteral("scale "); val3 = val2.transform.lossyScale; defaultInterpolatedStringHandler.AppendFormatted(((Vector3)(ref val3)).ToString("0.###")); defaultInterpolatedStringHandler.AppendLiteral(", "); defaultInterpolatedStringHandler.AppendFormatted(Describe(val2)); ModLog.Debug(defaultInterpolatedStringHandler.ToStringAndClear()); return new AttachedEffect { Obj = val2, Mount = value, Clip = emoteClip, BaseLocalPosition = val2.transform.localPosition, BaseLocalScale = val2.transform.localScale }; } public static void Keep(List attached) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if (attached == null) { return; } for (int i = 0; i < attached.Count; i++) { AttachedEffect attachedEffect = attached[i]; if (attachedEffect != null && !((Object)(object)attachedEffect.Obj == (Object)null) && !((Object)(object)attachedEffect.Mount == (Object)null)) { AtlasTuning.Placement placement = AtlasTuning.For(attachedEffect.Clip); attachedEffect.Obj.transform.localPosition = attachedEffect.BaseLocalPosition + Divide(placement.Offset, attachedEffect.Mount.lossyScale); attachedEffect.Obj.transform.localScale = attachedEffect.BaseLocalScale * placement.Scale; if (!attachedEffect.Obj.activeInHierarchy) { attachedEffect.Obj.SetActive(true); Blame(attachedEffect); } } } } private static void Blame(AttachedEffect effect) { if (!ModLog.Verbose || Blamed.Contains(effect.Clip)) { return; } Blamed.Add(effect.Clip); string value = "nothing above it"; Transform parent = effect.Obj.transform.parent; while ((Object)(object)parent != (Object)null) { if (!((Component)parent).gameObject.activeSelf) { value = ((Object)parent).name; break; } parent = parent.parent; } ModLog.Debug($"'{effect.Clip}' effect was switched off; first inactive ancestor: {value}."); } private static void Complain(Exception e) { if (!_complained) { _complained = true; ModLog.Warning("ParticleSystem.Emit is not usable in this build: " + e.Message); } } private static string Describe(GameObject clone) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; foreach (Renderer item in Interop.Safe(clone.GetComponentsInChildren(true))) { num2++; if (item.enabled && ((Component)item).gameObject.activeInHierarchy) { num++; } } foreach (ParticleSystem item2 in Interop.Safe(clone.GetComponentsInChildren(true))) { num4++; try { if (item2.isPlaying) { num3++; } } catch { } } return $"{num}/{num2} renderer(s) live, {num3}/{num4} particle system(s) playing"; } private static void Wake(GameObject clone) { foreach (Transform item in Interop.Safe(clone.GetComponentsInChildren(true))) { if (!((Component)item).gameObject.activeSelf) { ((Component)item).gameObject.SetActive(true); } } foreach (Renderer item2 in Interop.Safe(clone.GetComponentsInChildren(true))) { item2.enabled = true; } } private static int Renderers(GameObject clone) { int num = 0; foreach (Renderer item in Interop.Safe(clone.GetComponentsInChildren(true))) { if (item.enabled) { num++; } } return num; } private static Vector3 Divide(Vector3 value, Vector3 by) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) return new Vector3(Mathf.Approximately(by.x, 0f) ? value.x : (value.x / by.x), Mathf.Approximately(by.y, 0f) ? value.y : (value.y / by.y), Mathf.Approximately(by.z, 0f) ? value.z : (value.z / by.z)); } private static Transform NearestBone(Transform from) { Transform parent = from.parent; while ((Object)(object)parent != (Object)null) { if (((Object)parent).name.StartsWith("mixamorig:", StringComparison.Ordinal)) { return parent; } parent = parent.parent; } return null; } private static GameObject FindObject(NuisanceCustomer source, string name) { Il2CppReferenceArray objectAtlases = source.objectAtlases; if (objectAtlases == null) { return null; } foreach (ObjectAtlas item in Interop.Safe((Il2CppArrayBase)(object)objectAtlases)) { if (item.objects == null) { continue; } foreach (GameObject item2 in Interop.Safe((Il2CppArrayBase)(object)item.objects)) { if (string.Equals(((Object)item2).name, name, StringComparison.OrdinalIgnoreCase)) { return item2; } } } return null; } private static GameObject Customer() { if ((Object)(object)_customer != (Object)null || _searched) { return _customer; } _searched = true; try { StoreManager instance = StoreManager.Instance; if ((Object)(object)instance == (Object)null) { return null; } foreach (GameObject item in Interop.Safe(instance.allNuisanceNpcs)) { if ((Object)(object)item.GetComponent() == (Object)null) { continue; } _customer = item; break; } if ((Object)(object)_customer == (Object)null) { ModLog.Debug("No NuisanceCustomer prefab to borrow effects from."); return null; } Report(_customer.GetComponent()); } catch (Exception ex) { ModLog.Warning("Could not reach the nuisance customers: " + ex.Message); } return _customer; } private static void Report(NuisanceCustomer source) { if (!ModLog.Verbose || (Object)(object)source == (Object)null) { return; } Il2CppReferenceArray objectAtlases = source.objectAtlases; if (objectAtlases == null) { ModLog.Debug("[atlas] none on this customer."); return; } ModLog.Debug($"[atlas] '{((Object)_customer).name}' has {((Il2CppArrayBase)(object)objectAtlases).Length} atlas(es):"); for (int i = 0; i < ((Il2CppArrayBase)(object)objectAtlases).Length; i++) { ObjectAtlas val = ((Il2CppArrayBase)(object)objectAtlases)[i]; if ((Object)(object)val == (Object)null || val.objects == null) { ModLog.Debug($" [{i}] (empty)"); continue; } List list = new List(); foreach (GameObject item in Interop.Safe((Il2CppArrayBase)(object)val.objects)) { Transform parent = item.transform.parent; list.Add(((Object)item).name + "@" + (((Object)(object)parent != (Object)null) ? ((Object)parent).name : "root")); } ModLog.Debug($" [{i}] {((list.Count == 0) ? "(empty)" : string.Join(", ", list))}"); } } } [BepInPlugin("clementinise.shiftatmidnight.nuisance", "Nuisance", "1.0.0")] public class NuisancePlugin : BasePlugin { public const string Guid = "clementinise.shiftatmidnight.nuisance"; internal static ConfigEntry WheelKey; public override void Load() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) ModLog.Source = ((BasePlugin)this).Log; WheelKey = ((BasePlugin)this).Config.Bind("Keybinds", "Wheel", (KeyCode)113, "Hold to open the emote wheel, aim with the mouse and release to play. Tap it to stop the emote you are doing. Scroll or the up and down arrows change group; left and right step round the ring."); Settings.Bind(((BasePlugin)this).Config); InputBlock.Install(); ClassInjector.RegisterTypeInIl2Cpp(); ((BasePlugin)this).AddComponent(); ModLog.Msg($"Nuisance ready. {EmoteCatalog.All.Count} emote(s). Hold {WheelKey.Value} to pick one, tap it to stop."); } } public class NuisanceBehaviour : MonoBehaviour { private EmoteSync _sync; private BodyLock _lock; private readonly WheelInput _hands = new WheelInput(); private ThirdPersonView _camera; private readonly EmoteWheel _wheel = new EmoteWheel(); private Emote _active; private float _startedAt; private int _lastSceneHandle; private int _reportedPublishers = -1; private int _reportedMembers = -1; public NuisanceBehaviour(IntPtr handle) : base(handle) { } private void Awake() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) _sync = new EmoteSync(); _lock = new BodyLock(); _camera = new ThirdPersonView(); Scene activeScene = SceneManager.GetActiveScene(); _lastSceneHandle = ((Scene)(ref activeScene)).handle; } private void Update() { try { ReadKeys(); } catch (Exception value) { ModLog.Error($"Update: {value}"); } try { DetectSceneChange(); HoldOrRelease(); _sync.Tick(); _camera.Tick(); Report(); } catch (Exception value2) { ModLog.Error($"Tick: {value2}"); } } private void OnGUI() { try { _wheel.Draw(); } catch (Exception value) { ModLog.Error($"OnGUI: {value}"); } } private void LateUpdate() { try { _sync.LateTick(); _camera.LateTick(); } catch (Exception value) { ModLog.Error($"LateUpdate: {value}"); } } private void OnDestroy() { try { Stop(); } catch { } try { _hands.Release(); } catch { } try { InputBlock.Remove(); } catch { } try { _wheel.Forget(); } catch { } try { _sync.Clear(); } catch { } } private void ReadKeys() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) Emote chosen; switch (_wheel.Tick(NuisancePlugin.WheelKey.Value, out chosen)) { case EmoteWheel.Result.Play: Start(chosen); break; case EmoteWheel.Result.Cancel: Release(); break; } } private void Release() { Stop(); _lock.ForceRelease(); _hands.Release(); _wheel.Close(); } private void Start(Emote emote) { if ((Object)(object)NetworkContext.LocalBody == (Object)null) { ModLog.Msg("Not in a body yet."); } else if (EmoteCatalog.Resolve()) { _active = emote; _startedAt = Time.time; _sync.Start(emote); if (Settings.PullCameraBack) { _camera.Enable(); } ModLog.Debug("Started '" + emote.Name + "'."); } } private void Stop() { if (_active != null) { _active = null; _sync.Stop(); _lock.Release(); _hands.Release(); _camera.Disable(); } } private void HoldOrRelease() { if (_active == null) { _lock.Release(); _hands.Release(); return; } if (Time.time - _startedAt > Settings.MaxDuration) { Stop(); return; } if (Downed()) { Stop(); return; } _hands.Hold(camera: false); if (Settings.StandStill) { _lock.Hold(); } else { _lock.Release(); } } private static bool Downed() { try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { return true; } return localPlayerManager.downed || localPlayerManager.dead; } catch { return false; } } private void DetectSceneChange() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); int handle = ((Scene)(ref activeScene)).handle; if (handle != _lastSceneHandle) { _lastSceneHandle = handle; Stop(); _camera.Disable(); _sync.Clear(); NuisanceAtlas.Forget(); EmoteCatalog.Forget(); _wheel.Forget(); } } private void Report() { if (_sync.Members != _reportedMembers || _sync.Publishers != _reportedPublishers) { _reportedMembers = _sync.Members; _reportedPublishers = _sync.Publishers; if (_sync.Members > 1) { ModLog.Msg((_sync.Publishers >= _sync.Members) ? $"All {_sync.Members} players can see your emotes." : ($"{_sync.Publishers} of {_sync.Members} players can see your emotes. " + "The rest do not have the mod.")); } } } } internal static class NuisanceProps { private const float GroundProbeHeight = 1f; private const float GroundProbeDepth = 3f; private static bool _reportedMissingManager; private static bool _reportedTable; public static GameObject Drop(Emote emote, Transform body) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (emote == null || (Object)(object)body == (Object)null) { return null; } try { GameObject val = Find(emote); if ((Object)(object)val == (Object)null) { return null; } Vector3 val2 = Ground(body.position) + Vector3.up * Settings.PropHeight; Quaternion val3 = Quaternion.Euler(0f, body.eulerAngles.y, 0f); GameObject val4 = Object.Instantiate(val, val2, val3); if ((Object)(object)val4 == (Object)null) { return null; } Detach(val4); val4.transform.SetParent(body, true); ModLog.Debug($"Dropped '{((Object)val).name}' at {((Vector3)(ref val2)).ToString("0.##")}."); return val4; } catch (Exception ex) { ModLog.Warning("Could not drop the '" + emote.Name + "' prop: " + ex.Message); return null; } } public static void Retire(GameObject prop, float lifetime) { if ((Object)(object)prop == (Object)null) { return; } try { foreach (ParticleSystem item in Interop.Safe(prop.GetComponentsInChildren(true))) { item.Stop(true, (ParticleSystemStopBehavior)0); } } catch { } try { prop.transform.SetParent((Transform)null, true); Object.Destroy((Object)(object)prop, lifetime); } catch { } } private static GameObject Find(Emote emote) { NuisanceCustomerManager instance = NuisanceCustomerManager.Instance; if ((Object)(object)instance == (Object)null) { if (!_reportedMissingManager) { _reportedMissingManager = true; ModLog.Debug("No NuisanceCustomerManager here - emotes will play without their props."); } return null; } Il2CppStringArray nuisanceAnimations = instance.nuisanceAnimations; Il2CppReferenceArray nuisanceObjects = instance.nuisanceObjects; if (nuisanceAnimations == null || nuisanceObjects == null) { return null; } Report(nuisanceAnimations, nuisanceObjects); for (int i = 0; i < ((Il2CppArrayBase)(object)nuisanceAnimations).Length && i < ((Il2CppArrayBase)(object)nuisanceObjects).Length; i++) { if (string.Equals(((Il2CppArrayBase)(object)nuisanceAnimations)[i], emote.Clip, StringComparison.OrdinalIgnoreCase)) { return ((Il2CppArrayBase)(object)nuisanceObjects)[i]; } } ModLog.Debug("No prop in the nuisance table for '" + emote.Clip + "'."); return null; } private static void Report(Il2CppStringArray names, Il2CppReferenceArray objects) { if (!_reportedTable && ModLog.Verbose) { _reportedTable = true; ModLog.Debug($"[nuisance] {((Il2CppArrayBase)(object)names).Length} animation(s), {((Il2CppArrayBase)(object)objects).Length} object(s):"); int num = Math.Max(((Il2CppArrayBase)(object)names).Length, ((Il2CppArrayBase)(object)objects).Length); for (int i = 0; i < num; i++) { string value = ((i < ((Il2CppArrayBase)(object)names).Length) ? ((Il2CppArrayBase)(object)names)[i] : "(past end)"); string value2 = ((i < ((Il2CppArrayBase)(object)objects).Length && (Object)(object)((Il2CppArrayBase)(object)objects)[i] != (Object)null) ? ((Object)((Il2CppArrayBase)(object)objects)[i]).name : "(none)"); ModLog.Debug($" [{i}] '{value}' -> {value2}"); } } } public static void Detach(GameObject prop) { Remove(prop); Remove(prop); } private static void Remove(GameObject root) where T : Component { try { foreach (T item in Interop.Safe(root.GetComponentsInChildren(true))) { try { Object.DestroyImmediate((Object)(object)item, true); } catch { } } } catch { } } private static Vector3 Ground(Vector3 near) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = near + Vector3.up * 1f; RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, Vector3.down, ref val2, 4f)) { return ((RaycastHit)(ref val2)).point; } return near; } } internal static class Png { private static readonly byte[] Signature = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 }; private const byte Rgb = 2; private const byte Rgba = 6; public static bool TryDecode(byte[] file, out int width, out int height, out byte[] rgba, out string problem) { width = (height = 0); rgba = null; problem = null; if (file == null || file.Length < Signature.Length) { problem = "empty file"; return false; } for (int i = 0; i < Signature.Length; i++) { if (file[i] != Signature[i]) { problem = "not a PNG"; return false; } } byte b = 0; MemoryStream memoryStream = new MemoryStream(); int num2; int num3; for (int num = Signature.Length; num + 8 <= file.Length; num = num3 + num2 + 4) { num2 = BigEndian(file, num); string text = Encoding.ASCII.GetString(file, num + 4, 4); num3 = num + 8; if (num3 + num2 > file.Length) { problem = "truncated chunk"; return false; } switch (text) { case "IHDR": { width = BigEndian(file, num3); height = BigEndian(file, num3 + 4); byte b2 = file[num3 + 8]; b = file[num3 + 9]; byte b3 = file[num3 + 12]; if (b2 != 8) { problem = $"{b2} bits per channel, expected 8"; return false; } if (b3 != 0) { problem = "interlaced"; return false; } if (b != 2 && b != 6) { problem = $"colour type {b}, expected 2 or 6"; return false; } continue; } case "IDAT": memoryStream.Write(file, num3, num2); continue; default: continue; case "IEND": break; } break; } if (width <= 0 || height <= 0) { problem = "no IHDR"; return false; } if (memoryStream.Length == 0) { problem = "no IDAT"; return false; } try { byte[] raw = Inflate(memoryStream.ToArray()); rgba = Unfilter(raw, width, height, (b == 6) ? 4 : 3); return rgba != null; } catch (Exception ex) { problem = ex.Message; return false; } } private static byte[] Inflate(byte[] zlib) { using MemoryStream stream = new MemoryStream(zlib, 2, zlib.Length - 2); using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(); deflateStream.CopyTo(memoryStream); return memoryStream.ToArray(); } private static byte[] Unfilter(byte[] raw, int width, int height, int channels) { int num = width * channels; if (raw.Length < (num + 1) * height) { return null; } byte[] array = new byte[num]; byte[] array2 = new byte[num]; byte[] array3 = new byte[width * height * 4]; for (int i = 0; i < height; i++) { int num2 = i * (num + 1); byte b = raw[num2]; Buffer.BlockCopy(raw, num2 + 1, array, 0, num); for (int j = 0; j < num; j++) { int num3 = ((j >= channels) ? array[j - channels] : 0); int num4 = array2[j]; int c = ((j >= channels) ? array2[j - channels] : 0); int num5; switch (b) { case 0: num5 = 0; break; case 1: num5 = num3; break; case 2: num5 = num4; break; case 3: num5 = (num3 + num4) / 2; break; case 4: num5 = Paeth(num3, num4, c); break; default: return null; } array[j] = (byte)((array[j] + num5) & 0xFF); } int num6 = (height - 1 - i) * width * 4; for (int k = 0; k < width; k++) { int num7 = k * channels; int num8 = num6 + k * 4; array3[num8] = array[num7]; array3[num8 + 1] = array[num7 + 1]; array3[num8 + 2] = array[num7 + 2]; array3[num8 + 3] = ((channels == 4) ? array[num7 + 3] : byte.MaxValue); } Buffer.BlockCopy(array, 0, array2, 0, num); } return array3; } private static int Paeth(int a, int b, int c) { int num = a + b - c; int num2 = Math.Abs(num - a); int num3 = Math.Abs(num - b); int num4 = Math.Abs(num - c); if (num2 <= num3 && num2 <= num4) { return a; } return (num3 <= num4) ? b : c; } private static int BigEndian(byte[] data, int at) { return (data[at] << 24) | (data[at + 1] << 16) | (data[at + 2] << 8) | data[at + 3]; } } internal static class Rig { private const string BonePrefix = "mixamorig:"; private const string HipsName = "mixamorig:Hips"; public static Transform FindHips(Transform root) { if ((Object)(object)root == (Object)null) { return null; } Queue queue = new Queue(); queue.Enqueue(root); while (queue.Count > 0) { Transform val = queue.Dequeue(); if ((Object)(object)val != (Object)(object)root && ((Object)val).name.StartsWith("mixamorig:Hips", StringComparison.Ordinal)) { return val; } for (int i = 0; i < val.childCount; i++) { queue.Enqueue(val.GetChild(i)); } } return null; } public static string HipsPath(Transform root) { Transform val = FindHips(root); if ((Object)(object)val == (Object)null) { return null; } string text = ((Object)val).name; Transform parent = val.parent; while ((Object)(object)parent != (Object)null && ((Il2CppObjectBase)parent).Pointer != ((Il2CppObjectBase)root).Pointer) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return ((Object)(object)parent == (Object)null) ? null : text; } public static Transform AttachPoint(Transform bodyRoot, string donorHipsPath) { Transform val = FindHips(bodyRoot); if ((Object)(object)val == (Object)null) { return null; } if (string.IsNullOrEmpty(donorHipsPath)) { return val.parent; } int num = donorHipsPath.Split('/').Length; Transform val2 = val; for (int i = 0; i < num; i++) { if (!((Object)(object)val2 != (Object)null)) { break; } val2 = val2.parent; } return val2; } } internal static class Settings { public static float PropLifetime => 0f; public static float PropHeight => 1f; public static float MaxDuration => 60f; public static bool PullCameraBack => true; public static bool StandStill => true; public static void Bind(ConfigFile config) { } } internal sealed class ThirdPersonView { private const float Distance = 2.6f; private const float CollisionPadding = 0.3f; private const float ClosestAllowed = 0.4f; private const float PivotHeight = 1.4f; private Camera _camera; private Transform _originalParent; private Vector3 _originalLocalPos; private Quaternion _originalLocalRot; private readonly BodyVisibility _body = new BodyVisibility(); public bool Active => (Object)(object)_camera != (Object)null; public void Enable() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (Active) { return; } PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if (!((Object)(object)localPlayerManager == (Object)null)) { Camera val = FindGameCamera(localPlayerManager); if ((Object)(object)val == (Object)null) { ModLog.Warning("No player camera to pull back."); return; } _camera = val; _originalParent = ((Component)val).transform.parent; _originalLocalPos = ((Component)val).transform.localPosition; _originalLocalRot = ((Component)val).transform.localRotation; } } public void Disable() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_camera == (Object)null)) { try { ((Component)_camera).transform.SetParent(_originalParent, false); ((Component)_camera).transform.localPosition = _originalLocalPos; ((Component)_camera).transform.localRotation = _originalLocalRot; } catch (Exception ex) { ModLog.Warning("Restoring the camera failed: " + ex.Message); } _body.Restore(); _camera = null; _originalParent = null; } } public void Tick() { if (Active) { _body.Show(); } } public void LateTick() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_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_0054: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return; } PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { Disable(); return; } Vector3 val = ((Component)localPlayerManager).transform.position + Vector3.up * 1.4f; Quaternion rotation = ((Component)_camera).transform.rotation; Vector3 val2 = val + rotation * new Vector3(0f, 0f, -2.6f); RaycastHit val3 = default(RaycastHit); if (Physics.Linecast(val, val2, ref val3)) { float num = Mathf.Max(((RaycastHit)(ref val3)).distance - 0.3f, 0.4f); val2 = val + rotation * new Vector3(0f, 0f, 0f - num); } ((Component)_camera).transform.position = val2; } private static Camera FindGameCamera(PlayerManager pm) { try { FPSController fpsScript = pm.fpsScript; if ((Object)(object)fpsScript != (Object)null && (Object)(object)fpsScript.playerCamera != (Object)null) { return fpsScript.playerCamera; } InteractManager interactMan = pm.interactMan; if ((Object)(object)interactMan != (Object)null && (Object)(object)interactMan.mainCamera != (Object)null) { return interactMan.mainCamera; } } catch { } return Camera.main; } } internal static class WheelArt { private const string Folder = "Nuisance"; private static readonly Dictionary Cache = new Dictionary(StringComparer.OrdinalIgnoreCase); private const int SectorSize = 512; private const float SectorOuter = 244f; private const float SectorInner = 134f; private const int Samples = 3; private static readonly Dictionary Sectors = new Dictionary(); private const int ArrowSize = 64; private static Sprite _arrow; public static Sprite Backdrop => Load("backdrop"); private static string Root => Path.Combine(Paths.PluginPath, "Nuisance"); public static Sprite Sector(int segments, float gap) { if (segments < 1) { return null; } int key = segments * 1000 + Mathf.RoundToInt(gap); if (Sectors.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } value = Draw(segments, gap); Sectors[key] = value; return value; } public static Sprite Arrow() { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_arrow != (Object)null) { return _arrow; } try { byte[] array = new byte[16384]; for (int i = 0; i < 64; i++) { int num = (63 - i) * 64 * 4; float num2 = (float)i * 32f / 64f; for (int j = 0; j < 64; j++) { if (!(Mathf.Abs((float)j - 32f) > num2)) { int num3 = num + j * 4; int num4 = num3 + 1; byte b; array[num3 + 2] = (b = byte.MaxValue); array[num3] = (array[num4] = b); array[num3 + 3] = byte.MaxValue; } } } Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); val.LoadRawTextureData(Il2CppStructArray.op_Implicit(array)); val.Apply(); ((Texture)val).filterMode = (FilterMode)1; _arrow = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); Keep(val, _arrow); return _arrow; } catch (Exception ex) { ModLog.Warning("Could not build the arrow sprite: " + ex.Message); return null; } } private static Sprite Draw(int segments, float gap) { //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) try { float num = 180f / (float)segments; float num2 = gap * 0.5f; byte[] array = new byte[1048576]; float num3 = 256f; for (int i = 0; i < 512; i++) { int num4 = (511 - i) * 512 * 4; for (int j = 0; j < 512; j++) { int num5 = 0; for (int k = 0; k < 3; k++) { for (int l = 0; l < 3; l++) { float num6 = (float)j + ((float)l + 0.5f) / 3f - num3; float num7 = num3 - ((float)i + ((float)k + 0.5f) / 3f); float num8 = Mathf.Sqrt(num6 * num6 + num7 * num7); if (!(num8 < 134f) && !(num8 > 244f)) { float num9 = Mathf.Abs(Mathf.Atan2(num6, num7) * 57.29578f); if (!(num9 > num) && !(num8 * Mathf.Sin((num - num9) * ((float)Math.PI / 180f)) < num2)) { num5++; } } } } if (num5 != 0) { int num10 = num4 + j * 4; array[num10] = byte.MaxValue; array[num10 + 1] = byte.MaxValue; array[num10 + 2] = byte.MaxValue; array[num10 + 3] = (byte)(255 * num5 / 9); } } } Texture2D val = new Texture2D(512, 512, (TextureFormat)4, false); val.LoadRawTextureData(Il2CppStructArray.op_Implicit(array)); val.Apply(); ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, 512f, 512f), new Vector2(0.5f, 0.5f)); Keep(val, val2); ModLog.Debug($"Built a {segments}-segment sector sprite with a {gap:0.#}px gap."); return val2; } catch (Exception ex) { ModLog.Warning("Could not build the sector sprite: " + ex.Message); return null; } } private static void Keep(Texture2D texture, Sprite sprite) { try { ((Object)texture).hideFlags = (HideFlags)61; if ((Object)(object)sprite != (Object)null) { ((Object)sprite).hideFlags = (HideFlags)61; } } catch { } } private static Sprite Load(string relative) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_0133: 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) if (Cache.TryGetValue(relative, out var value)) { if ((Object)(object)value != (Object)null) { return value; } Cache.Remove(relative); ModLog.Debug("'" + relative + ".png' was unloaded, reloading it."); } Cache[relative] = null; try { byte[] array = Bytes(relative); if (array == null) { return null; } if (!Png.TryDecode(array, out var width, out var height, out var rgba, out var problem)) { ModLog.Warning($"Could not decode '{relative}.png': {problem}."); return null; } Texture2D val = new Texture2D(width, height, (TextureFormat)4, false); val.LoadRawTextureData(Il2CppStructArray.op_Implicit(rgba)); val.Apply(); ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); Keep(val, value); Cache[relative] = value; return value; } catch (Exception ex) { ModLog.Warning("Could not load '" + relative + ".png': " + ex.Message); return null; } } private static byte[] Bytes(string relative) { string text = Path.Combine(Root, relative + ".png"); try { if (File.Exists(text)) { ModLog.Debug($"Using '{text}' instead of the built-in '{relative}'."); return File.ReadAllBytes(text); } } catch (Exception ex) { ModLog.Warning("Could not read '" + text + "', falling back to the built-in copy: " + ex.Message); } return Embedded(relative); } private static byte[] Embedded(string relative) { string text = "Nuisance." + relative + ".png"; try { Assembly assembly = typeof(WheelArt).Assembly; using Stream stream = assembly.GetManifestResourceStream(text); if (stream == null) { ModLog.Warning($"'{text}' is not compiled into this build - the wheel will be missing its {relative}. Available: {Available(assembly)}"); return null; } byte[] array = new byte[stream.Length]; int i; int num; for (i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } if (i == array.Length) { return array; } ModLog.Warning($"'{text}' read short: {i} of {array.Length} bytes."); return null; } catch (Exception ex) { ModLog.Warning("Could not read the built-in '" + relative + "': " + ex.Message); return null; } } private static string Available(Assembly assembly) { try { return string.Join(", ", assembly.GetManifestResourceNames()); } catch { return "(unreadable)"; } } } internal sealed class WheelInput { private bool _ourCam; private bool _ourItem; public bool Held { get; private set; } public void Hold(bool camera) { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { return; } try { FPSController fpsScript = localPlayerManager.fpsScript; InventoryManager inventoryMan = localPlayerManager.inventoryMan; if (!Held) { _ourCam = camera && (Object)(object)fpsScript != (Object)null && !fpsScript.lockCam; _ourItem = (Object)(object)inventoryMan != (Object)null; Held = true; if (_ourItem) { inventoryMan.PauseInventory(); } } InputBlock.FreezeHotbar = true; if (_ourCam && (Object)(object)fpsScript != (Object)null && !fpsScript.lockCam) { fpsScript.lockCam = true; } if (_ourItem && (Object)(object)inventoryMan != (Object)null && inventoryMan.canControlItem) { inventoryMan.canControlItem = false; } } catch (Exception ex) { ModLog.Warning("Could not hold the camera still: " + ex.Message); Release(); } } public void Release() { InputBlock.FreezeHotbar = false; if (!Held) { return; } Held = false; try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; if ((Object)(object)localPlayerManager == (Object)null) { return; } if (_ourCam && (Object)(object)localPlayerManager.fpsScript != (Object)null) { localPlayerManager.fpsScript.lockCam = false; } if (_ourItem && (Object)(object)localPlayerManager.inventoryMan != (Object)null) { localPlayerManager.inventoryMan.canControlItem = true; localPlayerManager.inventoryMan.UnpauseInventory(); } } catch (Exception ex) { ModLog.Warning("Could not release the camera: " + ex.Message); } _ourCam = false; _ourItem = false; } } internal sealed class WheelUI { private const string ButtonTemplate = "Button Vertical Layout Group/Audio Button"; private static readonly Vector2 Reference = new Vector2(1920f, 1080f); private const float BackdropSize = 620f; private const float BandOuter = 0.4766f; private const float BandInner = 0.2617f; private const float Radius = 225f; private const float GapPixels = 7f; private const float LabelWidth = 200f; private const float LabelHeight = 40f; private static readonly Color Highlight = new Color(1f, 1f, 1f, 0.92f); private const int SortingOrder = 5000; private static readonly Color Dimmed = new Color(1f, 1f, 1f, 0.45f); private const float SelectedScale = 1.15f; private GameObject _canvas; private GameObject _hub; private TextMeshProUGUI _hubLabel; private GameObject _up; private GameObject _down; private readonly List _items = new List(); private readonly List _labels = new List(); private readonly List _arcs = new List(); private string _builtFor; private bool _unavailable; private const float ArrowSize = 26f; private const float ArrowLift = 96f; private const string Nothing = "Cancel"; public bool Available => !_unavailable; public bool Show(List items, int selected, string group, bool canUp, bool canDown) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) if (_unavailable) { return false; } try { if (!Build(items, group)) { return false; } _canvas.SetActive(true); if ((Object)(object)_hubLabel != (Object)null) { ((TMP_Text)_hubLabel).text = Hub(group, items, selected); } if ((Object)(object)_up != (Object)null) { _up.SetActive(canUp); } if ((Object)(object)_down != (Object)null) { _down.SetActive(canDown); } for (int i = 0; i < _arcs.Count; i++) { if ((Object)(object)_arcs[i] != (Object)null) { ((Graphic)_arcs[i]).color = ((i == selected) ? Highlight : Dimmed); } } for (int j = 0; j < _items.Count; j++) { bool flag = j == selected; _items[j].transform.localScale = Vector3.one * (flag ? 1.15f : 1f); if (j < _labels.Count && (Object)(object)_labels[j] != (Object)null) { ((Graphic)_labels[j]).color = (flag ? Color.black : Color.white); } } return true; } catch (Exception ex) { ModLog.Warning("Wheel UI failed, falling back to the plain ring: " + ex.Message); Destroy(); _unavailable = true; return false; } } public void Hide() { if ((Object)(object)_canvas != (Object)null) { _canvas.SetActive(false); } } public void Destroy() { if ((Object)(object)_canvas != (Object)null) { try { Object.Destroy((Object)(object)_canvas); } catch { } } _unavailable = false; _canvas = null; _hub = null; _hubLabel = null; _up = null; _down = null; _items.Clear(); _arcs.Clear(); _labels.Clear(); _builtFor = null; } private bool Build(List items, string group) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) string text = group + "/" + items.Count; if ((Object)(object)_canvas != (Object)null && _builtFor == text) { return true; } Destroy(); Transform val = FindTemplate(); if ((Object)(object)val == (Object)null) { ModLog.Warning("No pause menu button to take a font from - the wheel needs you to be in a day."); return false; } TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren(true); _canvas = new GameObject("NuisanceWheel"); Object.DontDestroyOnLoad((Object)(object)_canvas); Canvas val2 = _canvas.AddComponent(); val2.renderMode = (RenderMode)0; val2.sortingOrder = 5000; CanvasScaler val3 = _canvas.AddComponent(); val3.uiScaleMode = (ScaleMode)1; val3.referenceResolution = Reference; AddArt("Backdrop", WheelArt.Backdrop, 620f); Sprite sector = WheelArt.Sector(items.Count, 7f); float num = 360f / (float)Mathf.Max(1, items.Count); for (int i = 0; i < items.Count; i++) { _arcs.Add(AddArc(sector, (float)(-i) * num)); float num2 = (float)i * num * ((float)Math.PI / 180f); Vector2 at = new Vector2(Mathf.Sin(num2), Mathf.Cos(num2)) * 225f; GameObject val4 = MakeLabel(componentInChildren, _canvas.transform, at, items[i].Name); if (!((Object)(object)val4 == (Object)null)) { _items.Add(val4); _labels.Add(val4.GetComponent()); } } _hub = MakeLabel(componentInChildren, _canvas.transform, Vector2.zero, group); _hubLabel = (((Object)(object)_hub != (Object)null) ? _hub.GetComponent() : null); _up = AddArrow(0f, 96f); _down = AddArrow(180f, -96f); _builtFor = text; ModLog.Debug($"Wheel built: {_items.Count} item(s) cloned from '{((Object)val).name}'."); return true; } private RectTransform AddArt(string name, Sprite sprite, float size) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sprite == (Object)null) { return null; } GameObject val = new GameObject(name); val.transform.SetParent(_canvas.transform, false); RectTransform val2 = val.AddComponent(); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 0.5f); val2.pivot = val3; Vector2 anchorMin = (val2.anchorMax = val3); val2.anchorMin = anchorMin; val2.anchoredPosition = Vector2.zero; val2.sizeDelta = new Vector2(size, size); Image val5 = val.AddComponent(); val5.sprite = sprite; ((Graphic)val5).raycastTarget = false; return val2; } private GameObject AddArrow(float rotation, float lift) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) RectTransform val = AddArt("Arrow", WheelArt.Arrow(), 26f); if ((Object)(object)val == (Object)null) { return null; } val.anchoredPosition = new Vector2(0f, lift); ((Transform)val).localRotation = Quaternion.Euler(0f, 0f, rotation); Image component = ((Component)val).GetComponent(); ((Graphic)component).color = Dimmed; return ((Component)val).gameObject; } private Image AddArc(Sprite sector, float rotation) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) RectTransform val = AddArt("Arc", sector, 620f); if ((Object)(object)val == (Object)null) { return null; } ((Transform)val).localRotation = Quaternion.Euler(0f, 0f, rotation); Image component = ((Component)val).GetComponent(); ((Graphic)component).color = Dimmed; return component; } private static GameObject MakeLabel(TextMeshProUGUI style, Transform parent, Vector2 at, string text) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0061: 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) GameObject val = new GameObject("Label"); val.transform.SetParent(parent, false); RectTransform val2 = val.AddComponent(); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 0.5f); val2.pivot = val3; Vector2 anchorMin = (val2.anchorMax = val3); val2.anchorMin = anchorMin; val2.anchoredPosition = at; val2.sizeDelta = new Vector2(200f, 40f); TextMeshProUGUI val5 = val.AddComponent(); if ((Object)(object)style != (Object)null) { ((TMP_Text)val5).font = ((TMP_Text)style).font; ((TMP_Text)val5).fontSharedMaterial = ((TMP_Text)style).fontSharedMaterial; ((TMP_Text)val5).fontSize = ((TMP_Text)style).fontSize; ((TMP_Text)val5).fontStyle = ((TMP_Text)style).fontStyle; } ((TMP_Text)val5).alignment = (TextAlignmentOptions)514; ((TMP_Text)val5).enableWordWrapping = false; ((Graphic)val5).raycastTarget = false; ((TMP_Text)val5).text = text; return val; } private static string Hub(string group, List items, int selected) { string text = (string.IsNullOrEmpty(group) ? "EMOTES" : group.ToUpperInvariant()); if (items.Count == 0) { return text; } return text + "\n" + ((selected < 0) ? "Cancel" : items[Mathf.Clamp(selected, 0, items.Count - 1)].Name); } private static Transform FindTemplate() { try { PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager; GameObject val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.pauseMenu : null); if ((Object)(object)val == (Object)null) { return null; } return val.transform.Find("Button Vertical Layout Group/Audio Button"); } catch { return null; } } } }