Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DeepNorthStaffVisuals v1.0.1
DeepNorthStaffVisuals.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("DeepNorthStaffVisuals")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+dcd1a19a5036bc7f9bca0a78bc825712e3af73c6")] [assembly: AssemblyProduct("DeepNorthStaffVisuals")] [assembly: AssemblyTitle("DeepNorthStaffVisuals")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DeepNorthStaffVisuals { internal static class Copier { public static void Copy(Transform part, Transform donorModel, Transform container, Fit fit, MeshRenderer surface, double rateBoost, double ringRate, double ringLife) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0204: 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_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) Transform transform = Object.Instantiate<GameObject>(((Component)part).gameObject, container, false).transform; Matrix4x4 worldToLocalMatrix = donorModel.worldToLocalMatrix; Quaternion val = Quaternion.Inverse(donorModel.rotation); Quaternion val2 = Quaternion.LookRotation(ToUnity(fit.Rotate(new V3(0.0, 0.0, 1.0))), ToUnity(fit.Rotate(new V3(0.0, 1.0, 0.0)))); Matrix4x4 val3 = worldToLocalMatrix * part.localToWorldMatrix; Vector4 column = ((Matrix4x4)(ref val3)).GetColumn(0); float magnitude = ((Vector4)(ref column)).magnitude; column = ((Matrix4x4)(ref val3)).GetColumn(1); float magnitude2 = ((Vector4)(ref column)).magnitude; column = ((Matrix4x4)(ref val3)).GetColumn(2); transform.localScale = new Vector3(magnitude, magnitude2, ((Vector4)(ref column)).magnitude); Transform[] componentsInChildren = ((Component)part).GetComponentsInChildren<Transform>(true); Transform[] componentsInChildren2 = ((Component)transform).GetComponentsInChildren<Transform>(true); for (int i = 0; i < componentsInChildren.Length && i < componentsInChildren2.Length; i++) { Vector3 val4 = ((Matrix4x4)(ref worldToLocalMatrix)).MultiplyPoint3x4(componentsInChildren[i].position); componentsInChildren2[i].position = container.TransformPoint(ToUnity(fit.Point(new V3(val4.x, val4.y, val4.z)))); componentsInChildren2[i].rotation = container.rotation * val2 * (val * componentsInChildren[i].rotation); } ParticleSystem[] componentsInChildren3 = ((Component)part).GetComponentsInChildren<ParticleSystem>(true); ParticleSystem[] componentsInChildren4 = ((Component)transform).GetComponentsInChildren<ParticleSystem>(true); List<ParticleSystem> list = new List<ParticleSystem>(); for (int j = 0; j < componentsInChildren3.Length && j < componentsInChildren4.Length; j++) { string name = ((Object)((Component)componentsInChildren3[j]).gameObject).name; if ((Object)(object)surface != (Object)null && Looks.FollowsWeapon(name)) { Trace(componentsInChildren4[j], surface, fit); } else { Stretch(componentsInChildren4[j], val * ((Component)componentsInChildren3[j]).transform.rotation, fit); } EmissionModule emission = componentsInChildren4[j].emission; if (Looks.SpreadsAlongWeapon(name)) { EmissionModule emission2 = componentsInChildren3[j].emission; ((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission2)).rateOverTimeMultiplier; Scale(componentsInChildren4[j], ringRate); MainModule main = componentsInChildren4[j].main; ((MainModule)(ref main)).startLifetime = Times(((MainModule)(ref main)).startLifetime, ringLife); list.Add(componentsInChildren4[j]); } else { ((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission)).rateOverTimeMultiplier * (float)rateBoost; } } foreach (ParticleSystem item in list) { Spread(item, container, fit); } } private static void Spread(ParticleSystem ring, Transform container, Fit fit) { //IL_0013: 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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)ring).transform; Vector3 val = ToUnity(fit.Target.Unit(0)); Vector3 val2 = container.InverseTransformPoint(transform.position); double num = fit.Target.Size(0); double num2 = fit.Target.Fraction(FromUnity(val2), 0); Quaternion rotation = transform.rotation; bool flag = Leans(ring, container, fit); if (flag) { Scale(ring, 0.5); } Quaternion rotation2 = Quaternion.AngleAxis(180f, container.TransformDirection(val)) * rotation; List<double> list = Fit.RingFractions(num, Drift(ring)); for (int i = 0; i < list.Count; i++) { Vector3 position = container.TransformPoint(val2 + val * (float)((list[i] - num2) * num)); Place((i == 0) ? transform : Object.Instantiate<GameObject>(((Component)transform).gameObject, transform.parent, false).transform, position, rotation); if (flag) { Place(Object.Instantiate<GameObject>(((Component)transform).gameObject, transform.parent, false).transform, position, rotation2); } } } private static void Place(Transform copy, Vector3 position, Quaternion rotation) { //IL_0001: 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) copy.position = position; copy.rotation = rotation; } private static bool Leans(ParticleSystem ring, Transform container, Fit fit) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (!IsCone(ring)) { return false; } Quaternion rotation = ((Component)ring).transform.rotation; ShapeModule shape = ring.shape; Vector3 v = container.InverseTransformDirection(rotation * Quaternion.Euler(((ShapeModule)(ref shape)).rotation) * Vector3.forward); return fit.Leans(FromUnity(v)); } private static void Scale(ParticleSystem system, double factor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) EmissionModule emission = system.emission; ((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission)).rateOverTimeMultiplier * (float)factor; for (int i = 0; i < ((EmissionModule)(ref emission)).burstCount; i++) { Burst burst = ((EmissionModule)(ref emission)).GetBurst(i); ((Burst)(ref burst)).probability = ((Burst)(ref burst)).probability * (float)factor; ((EmissionModule)(ref emission)).SetBurst(i, burst); } } private static bool IsCone(ParticleSystem system) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 ShapeModule shape = system.shape; ParticleSystemShapeType shapeType = ((ShapeModule)(ref shape)).shapeType; if ((int)shapeType != 4) { return (int)shapeType == 8; } return true; } private static double Drift(ParticleSystem ring) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) VelocityOverLifetimeModule velocityOverLifetime = ring.velocityOverLifetime; bool firedAlongAxis = IsCone(ring); MainModule main = ring.main; double startSpeed = Mean(((MainModule)(ref main)).startSpeed); double velocityAlongAxis = (((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled ? Mean(((VelocityOverLifetimeModule)(ref velocityOverLifetime)).z) : 0f); double radial = (((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled ? Mean(((VelocityOverLifetimeModule)(ref velocityOverLifetime)).radial) : 0f); main = ring.main; return Fit.Drift(firedAlongAxis, startSpeed, velocityAlongAxis, radial, Mean(((MainModule)(ref main)).startLifetime)); } private static MinMaxCurve Times(MinMaxCurve curve, double factor) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0010: Invalid comparison between Unknown and I4 //IL_0054: Unknown result type (might be due to invalid IL or missing references) float num = (float)factor; ParticleSystemCurveMode mode = ((MinMaxCurve)(ref curve)).mode; if ((int)mode != 0) { if ((int)mode == 3) { ((MinMaxCurve)(ref curve)).constantMin = ((MinMaxCurve)(ref curve)).constantMin * num; ((MinMaxCurve)(ref curve)).constantMax = ((MinMaxCurve)(ref curve)).constantMax * num; } else { ((MinMaxCurve)(ref curve)).curveMultiplier = ((MinMaxCurve)(ref curve)).curveMultiplier * num; } } else { ((MinMaxCurve)(ref curve)).constant = ((MinMaxCurve)(ref curve)).constant * num; } return curve; } private static float Mean(MinMaxCurve curve) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 ParticleSystemCurveMode mode = ((MinMaxCurve)(ref curve)).mode; if ((int)mode != 0) { if ((int)mode == 3) { return (((MinMaxCurve)(ref curve)).constantMin + ((MinMaxCurve)(ref curve)).constantMax) / 2f; } return ((MinMaxCurve)(ref curve)).curveMultiplier; } return ((MinMaxCurve)(ref curve)).constant; } private static void Trace(ParticleSystem system, MeshRenderer surface, Fit fit) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) ShapeModule shape = system.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)13; ((ShapeModule)(ref shape)).meshRenderer = surface; ((ShapeModule)(ref shape)).meshShapeType = (ParticleSystemMeshShapeType)1; ((ShapeModule)(ref shape)).useMeshColors = false; ((ShapeModule)(ref shape)).position = Vector3.zero; ((ShapeModule)(ref shape)).rotation = Vector3.zero; ((ShapeModule)(ref shape)).scale = Vector3.one; EmissionModule emission = system.emission; ((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission)).rateOverTimeMultiplier * (float)fit.TraceRateFactor; MainModule main = system.main; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; } private static void Stretch(ParticleSystem system, Quaternion donorRotation, Fit fit) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_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_0044: 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) ShapeModule shape = system.shape; Quaternion rotation = donorRotation * Quaternion.Euler(((ShapeModule)(ref shape)).rotation); ((ShapeModule)(ref shape)).scale = Vector3.Scale(((ShapeModule)(ref shape)).scale, Along(rotation, fit)); ((ShapeModule)(ref shape)).position = Vector3.Scale(((ShapeModule)(ref shape)).position, Along(donorRotation, fit)); EmissionModule emission = system.emission; ((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission)).rateOverTimeMultiplier * (float)fit.RateFactor; } private static Vector3 Along(Quaternion rotation, Fit fit) { //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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) return new Vector3((float)fit.EmitterStretch(FromUnity(rotation * Vector3.right)), (float)fit.EmitterStretch(FromUnity(rotation * Vector3.up)), (float)fit.EmitterStretch(FromUnity(rotation * Vector3.forward))); } private static Vector3 ToUnity(V3 v) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) return new Vector3((float)v.X, (float)v.Y, (float)v.Z); } private static V3 FromUnity(Vector3 v) { //IL_0000: 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) return new V3(v.x, v.y, v.z); } } [HarmonyPatch] internal static class Dresser { private sealed class Worn { public string Look; } private sealed class StandLooks { public ArmorStand Stand; public bool Read; public uint Revision; public readonly string[] ByModel = new string[4]; } private static readonly int s_lookKey = StringExtensionMethods.GetStableHashCode("DeepNorthStaffVisuals_look"); private static FieldRef<VisEquipment, GameObject>[] s_models; private static FieldRef<VisEquipment, int>[] s_hashes; private static FieldRef<VisEquipment, ZNetView> s_nview; private static FieldRef<Humanoid, ItemData>[] s_items; private static readonly VisSlot[] s_modelSlots; private static ConditionalWeakTable<GameObject, Worn> s_worn; private static ConditionalWeakTable<VisEquipment, StandLooks> s_stands; private static bool s_updateOff; private static bool Prepare() { s_models = new FieldRef<VisEquipment, GameObject>[4] { AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance"), AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_leftItemInstance"), AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightBackItemInstance"), AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_leftBackItemInstance") }; s_hashes = new FieldRef<VisEquipment, int>[4] { AccessTools.FieldRefAccess<VisEquipment, int>("m_currentRightItemHash"), AccessTools.FieldRefAccess<VisEquipment, int>("m_currentLeftItemHash"), AccessTools.FieldRefAccess<VisEquipment, int>("m_currentRightBackItemHash"), AccessTools.FieldRefAccess<VisEquipment, int>("m_currentLeftBackItemHash") }; s_nview = AccessTools.FieldRefAccess<VisEquipment, ZNetView>("m_nview"); s_items = new FieldRef<Humanoid, ItemData>[4] { AccessTools.FieldRefAccess<Humanoid, ItemData>("m_rightItem"), AccessTools.FieldRefAccess<Humanoid, ItemData>("m_leftItem"), AccessTools.FieldRefAccess<Humanoid, ItemData>("m_hiddenRightItem"), AccessTools.FieldRefAccess<Humanoid, ItemData>("m_hiddenLeftItem") }; return true; } internal static void Reset() { s_worn = new ConditionalWeakTable<GameObject, Worn>(); s_stands = new ConditionalWeakTable<VisEquipment, StandLooks>(); s_updateOff = false; } [HarmonyPatch(typeof(VisEquipment), "CustomUpdate")] [HarmonyPostfix] private static void CustomUpdate(VisEquipment __instance) { if (s_updateOff) { return; } try { CheckLook(__instance); } catch (Exception arg) { s_updateOff = true; Plugin.ErrorOnce("update", $"Looks stop changing until the next world (a game update?): {arg}"); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void CheckLook(VisEquipment vis) { if (!vis.m_isPlayer || (Object)(object)ObjectDB.instance == (Object)null) { return; } ZNetView val = s_nview.Invoke(vis); ZDO val2 = (((Object)(object)val != (Object)null) ? val.GetZDO() : null); if (val2 == null) { return; } if (vis.m_isArmorStand) { CheckArmorStand(vis, val2); return; } if (IsLocalPlayer(vis)) { int num = Looks.Code(Looks.FromNote(StaffOnShow()?.m_customData)); if (val2.GetInt(s_lookKey, 0) != num) { val2.Set(s_lookKey, num, false); } } string look = Looks.FromCode(val2.GetInt(s_lookKey, 0)); for (int i = 0; i < s_models.Length; i++) { WearModel(vis, i, look); } } private static void CheckArmorStand(VisEquipment vis, ZDO record) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) StandLooks value = s_stands.GetValue(vis, (VisEquipment v) => new StandLooks { Stand = ((Component)v).GetComponentInParent<ArmorStand>() }); if ((Object)(object)value.Stand == (Object)null) { return; } if (!value.Read || value.Revision != record.DataRevision) { for (int num = 0; num < value.ByModel.Length; num++) { value.ByModel[num] = "Plain"; } List<ArmorStandSlot> slots = value.Stand.m_slots; for (int num2 = 0; num2 < slots.Count; num2++) { int num3 = Array.IndexOf(s_modelSlots, slots[num2].m_slot); if (num3 >= 0 && record.GetInt(StringExtensionMethods.GetStableHashCode(num2 + "_item"), 0) != 0) { value.ByModel[num3] = Looks.FromNote(NotesOf(record, num2)); } } value.Read = true; value.Revision = record.DataRevision; } for (int num4 = 0; num4 < s_models.Length; num4++) { WearModel(vis, num4, value.ByModel[num4]); } } internal static Dictionary<string, string> NotesOf(ZDO record, int slot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown ItemData val = new ItemData(); ItemDrop.LoadFromZDO(val, record, slot); return val.m_customData; } private static void WearModel(VisEquipment vis, int i, string look) { GameObject val = s_models[i].Invoke(vis); if ((Object)(object)val != (Object)null) { Wear(val, ObjectDB.instance.GetItemPrefab(s_hashes[i].Invoke(vis)), look); } } internal static void Wear(GameObject model, GameObject prefab, string look) { Worn orCreateValue = s_worn.GetOrCreateValue(model); if (orCreateValue.Look == look) { return; } orCreateValue.Look = look; try { Dress(model.transform, prefab, look); } catch (Exception arg) { Plugin.ErrorOnce("dress", $"Couldn't put the look on a weapon (it stays plain): {arg}"); } } private static bool IsLocalPlayer(VisEquipment vis) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { return (Object)(object)((Component)vis).gameObject == (Object)(object)((Component)localPlayer).gameObject; } return false; } private static ItemData StaffOnShow() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } FieldRef<Humanoid, ItemData>[] array = s_items; for (int i = 0; i < array.Length; i++) { ItemData val = array[i].Invoke((Humanoid)(object)localPlayer); if (val != null && EffectKit.LookKind(val.m_dropPrefab) != Kind.None) { return val; } } return null; } internal static void OnKey() { if (s_updateOff) { return; } ItemData val = StaffOnShow(); if (val != null) { string text = Looks.StepNote(val.m_customData, EffectKit.IsAvailable); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, false); } } } internal static bool HasLookable(bool handsOnly) { if (s_updateOff) { return false; } VisEquipment val = LocalVisEquipment(); if ((Object)(object)val == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } for (int i = 0; i < (handsOnly ? 2 : s_models.Length); i++) { if ((Object)(object)s_models[i].Invoke(val) != (Object)null && EffectKit.LookKind(ObjectDB.instance.GetItemPrefab(s_hashes[i].Invoke(val))) != Kind.None) { return true; } } return false; } private static VisEquipment LocalVisEquipment() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer != (Object)null)) { return null; } return ((Component)localPlayer).GetComponent<VisEquipment>(); } private static void Dress(Transform model, GameObject prefab, string look) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown foreach (Transform item in model) { Transform val = item; if (((Object)val).name == "DeepNorthStaffVisuals_look") { Object.Destroy((Object)(object)((Component)val).gameObject); } } if (look == "Plain") { return; } Kind kind = EffectKit.LookKind(prefab); if (kind == Kind.None) { return; } Fix fix = Fixes.For(((Object)prefab).name, look); EffectKit.Donor donor = EffectKit.DonorFor(look, (fix != null && fix.DonorKind != Kind.None) ? fix.DonorKind : kind); if (donor == null || !EffectKit.ModelFrameOf(model, kind, out var frame, out var main)) { return; } Fit fit = new Fit(donor.Frame, frame, WeaponKinds.GameEffectStart(donor.Kind), WeaponKinds.EffectStart(kind), fix); MeshRenderer val2 = ((Component)main).GetComponent<MeshRenderer>(); if ((Object)(object)val2 == (Object)null || !EffectKit.CanEmitFrom(model, main)) { val2 = null; } GameObject val3 = new GameObject("DeepNorthStaffVisuals_look"); val3.SetActive(false); val3.transform.SetParent(model, false); foreach (Transform part in donor.Parts) { Copier.Copy(part, donor.Model, val3.transform, fit, val2, Looks.RateBoost(look), Looks.RingRate(look), Looks.RingLife(look)); } val3.SetActive(true); } static Dresser() { VisSlot[] array = new VisSlot[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); s_modelSlots = (VisSlot[])(object)array; s_worn = new ConditionalWeakTable<GameObject, Worn>(); s_stands = new ConditionalWeakTable<VisEquipment, StandLooks>(); } } internal static class EffectKit { internal sealed class Donor { public string Name; public Kind Kind; public Transform Model; public ModelFrame Frame; public List<Transform> Parts; } public const string Container = "DeepNorthStaffVisuals_look"; private static readonly HashSet<string> s_skip = new HashSet<string> { "UpgraderGlow", "equiped", "DeepNorthStaffVisuals_look" }; private static readonly Dictionary<string, Kind> s_kinds = new Dictionary<string, Kind>(); private static readonly Dictionary<string, Donor> s_donors = new Dictionary<string, Donor>(); private static readonly Dictionary<string, bool> s_available = new Dictionary<string, bool>(); public static void Clear() { s_kinds.Clear(); s_donors.Clear(); s_available.Clear(); } public static Kind LookKind(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return Kind.None; } if (s_kinds.TryGetValue(((Object)prefab).name, out var value)) { return value; } Kind kind = ReadLookKind(prefab); s_kinds[((Object)prefab).name] = kind; return kind; } private static Kind ReadLookKind(GameObject prefab) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || !WeaponKinds.CanTakeLook(((Object)prefab).name)) { return Kind.None; } SharedData shared = component.m_itemData.m_shared; Kind kind = WeaponKinds.KindOf(shared.m_itemType, shared.m_skillType, ((Object)prefab).name); if (kind == Kind.None) { return Kind.None; } Transform val = HeldModel(prefab.transform); if ((Object)(object)val == (Object)null || ((Object)val).name != "attach") { return Kind.None; } if (HasOwnEffects(val)) { return Kind.None; } if (!ModelFrameOf(val, kind, out var _, out var _)) { return Kind.None; } return kind; } private static Transform HeldModel(Transform prefab) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in prefab) { Transform val = item; if (((Object)val).name == "attach" || ((Object)val).name == "attach_skin") { return val; } } return null; } private static bool HasOwnEffects(Transform t) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown if ((Object)(object)((Component)t).GetComponent<ParticleSystem>() != (Object)null || (Object)(object)((Component)t).GetComponent<Light>() != (Object)null) { return true; } foreach (Transform item in t) { Transform val = item; if (!s_skip.Contains(((Object)val).name) && HasOwnEffects(val)) { return true; } } return false; } public static bool ModelFrameOf(Transform model, Kind kind, out ModelFrame frame, out MeshFilter main) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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) frame = null; main = null; List<V3> list = new List<V3>(); V3[] array = null; double[] meshSizes = null; double num = -1.0; Matrix4x4 worldToLocalMatrix = model.worldToLocalMatrix; MeshFilter[] componentsInChildren = ((Component)model).GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter val in componentsInChildren) { if (!((Object)(object)val.sharedMesh == (Object)null) && !IsSkipped(((Component)val).transform, model)) { Matrix4x4 val2 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix; Bounds bounds = val.sharedMesh.bounds; for (int j = 0; j < 8; j++) { Vector3 val3 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1)))); Vector3 val4 = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(val3); list.Add(new V3(val4.x, val4.y, val4.z)); } V3[] array2 = new V3[3]; double[] array3 = new double[3]; for (int k = 0; k < 3; k++) { Vector3 val5 = Vector4.op_Implicit(((Matrix4x4)(ref val2)).GetColumn(k)); array2[k] = new V3(val5.x, val5.y, val5.z); int num2 = k; Vector3 extents = ((Bounds)(ref bounds)).extents; array3[num2] = 2f * ((Vector3)(ref extents))[k] * ((Vector3)(ref val5)).magnitude; } double num3 = Math.Max(array3[0], Math.Max(array3[1], array3[2])); if (num3 > num) { num = num3; array = array2; meshSizes = array3; main = val; } } } if (array == null) { return false; } frame = new ModelFrame(array, meshSizes, WeaponKinds.HeadSign(kind), list); return true; } public static bool CanEmitFrom(Transform model, MeshFilter main) { //IL_004e: 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) Mesh val = (((Object)(object)main != (Object)null) ? main.sharedMesh : null); if ((Object)(object)val == (Object)null) { return false; } if (val.isReadable) { return true; } Transform val2 = model.Find("UpgraderGlow"); if ((Object)(object)val2 == (Object)null) { return false; } ParticleSystem[] componentsInChildren = ((Component)val2).GetComponentsInChildren<ParticleSystem>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ShapeModule shape = componentsInChildren[i].shape; if ((Object)(object)((ShapeModule)(ref shape)).mesh == (Object)(object)val) { return true; } } return false; } private static bool IsSkipped(Transform t, Transform model) { while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)model) { if (s_skip.Contains(((Object)t).name)) { return true; } t = t.parent; } return false; } public static Donor DonorFor(string look, Kind kind) { foreach (string item in Looks.DonorsFor(look, kind)) { Donor donor = GetDonor(item); if (donor != null) { return donor; } } return null; } public static bool IsAvailable(string look) { if (s_available.TryGetValue(look, out var value)) { return value; } value = DonorFor(look, Kind.None) != null; if (!value) { Plugin.WarnOnce("look:" + look, "The look " + look + " has no donor weapon in this game version: skipped"); } s_available[look] = value; return value; } private static Donor GetDonor(string name) { if (s_donors.TryGetValue(name, out var value)) { return value; } value = ReadDonor(name); if (value == null) { Plugin.WarnOnce("donor:" + name, "Donor weapon " + name + " or its effects weren't found (a game update?): skipped"); } s_donors[name] = value; return value; } private static Donor ReadDonor(string name) { //IL_006d: 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) GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(name) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); Transform val3 = (((Object)(object)val != (Object)null) ? val.transform.Find("attach") : null); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { return null; } SharedData shared = val2.m_itemData.m_shared; Kind kind = WeaponKinds.KindOf(shared.m_itemType, shared.m_skillType, name); if (!ModelFrameOf(val3, kind, out var frame, out var _)) { return null; } List<Transform> list = new List<Transform>(); FindParts(val3, list); if (list.Count == 0) { return null; } return new Donor { Name = name, Kind = kind, Model = val3, Frame = frame, Parts = list }; } private static void FindParts(Transform t, List<Transform> parts) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in t) { Transform val = item; if (!s_skip.Contains(((Object)val).name) && (((Component)val).GetComponentsInChildren<ParticleSystem>(true).Length != 0 || ((Component)val).GetComponentsInChildren<Light>(true).Length != 0)) { if (((Component)val).GetComponentsInChildren<MeshFilter>(true).Length == 0) { parts.Add(val); } else { FindParts(val, parts); } } } } } internal readonly struct V3 { public readonly double X; public readonly double Y; public readonly double Z; public double this[int axis] => axis switch { 1 => Y, 0 => X, _ => Z, }; public double Length => Math.Sqrt(X * X + Y * Y + Z * Z); public V3(double x, double y, double z) { X = x; Y = y; Z = z; } public static V3 operator +(V3 a, V3 b) { return new V3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); } public static V3 operator *(double s, V3 v) { return new V3(s * v.X, s * v.Y, s * v.Z); } public static double Dot(V3 a, V3 b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } public static V3 Axis(int axis, int sign) { return new V3((axis == 0) ? sign : 0, (axis == 1) ? sign : 0, (axis == 2) ? sign : 0); } public static V3 Cross(V3 a, V3 b) { return new V3(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X); } public V3 Normalized() { if (!(Length < 1E-12)) { return 1.0 / Length * this; } return this; } public double Largest() { if (!(Math.Abs(X) >= Math.Abs(Y)) || !(Math.Abs(X) >= Math.Abs(Z))) { if (!(Math.Abs(Y) >= Math.Abs(Z))) { return Z; } return Y; } return X; } public override string ToString() { return $"({X:0.###}, {Y:0.###}, {Z:0.###})"; } } internal readonly struct Box { public readonly V3 Min; public readonly V3 Max; public Box(V3 min, V3 max) { Min = min; Max = max; } public double Size(int axis) { return Max[axis] - Min[axis]; } } internal sealed class ModelFrame { private const double Tiny = 1E-06; public readonly V3[] Axes = new V3[3]; public readonly double[] Min = new double[3]; public readonly double[] Max = new double[3]; public ModelFrame(V3[] meshAxes, double[] meshSizes, int headSign, IEnumerable<V3> corners) { int[] array = (from i in Enumerable.Range(0, 3) orderby meshSizes[i] descending, i select i).ToArray(); V3 v = meshAxes[array[0]].Normalized(); V3 v2 = meshAxes[array[1]].Normalized(); if (((Math.Abs(v.Z) >= 0.1) ? v.Z : v.Largest()) < 0.0 != headSign < 0) { v = -1.0 * v; } if (v2.Largest() < 0.0) { v2 = -1.0 * v2; } Axes[0] = v; Axes[1] = v2; Axes[2] = V3.Cross(v, v2); for (int num = 0; num < 3; num++) { Min[num] = double.MaxValue; Max[num] = double.MinValue; } foreach (V3 corner in corners) { for (int num2 = 0; num2 < 3; num2++) { double num3 = V3.Dot(corner, Axes[num2]); if (num3 < Min[num2]) { Min[num2] = num3; } if (num3 > Max[num2]) { Max[num2] = num3; } } } } public ModelFrame(Box box, int headSign) : this(new V3[3] { V3.Axis(0, 1), V3.Axis(1, 1), V3.Axis(2, 1) }, new double[3] { box.Size(0), box.Size(1), box.Size(2) }, headSign, from i in Enumerable.Range(0, 8) select new V3(((i & 1) == 0) ? box.Min.X : box.Max.X, ((i & 2) == 0) ? box.Min.Y : box.Max.Y, ((i & 4) == 0) ? box.Min.Z : box.Max.Z)) { } public double Size(int k) { return Max[k] - Min[k]; } public V3 Unit(int k) { return Axes[k]; } public double Fraction(V3 p, int k) { double num = Size(k); if (!(num < 1E-06)) { return (V3.Dot(p, Axes[k]) - Min[k]) / num; } return 0.5; } public double Coordinate(int k, double fraction) { return Min[k] + fraction * Size(k); } } internal sealed class Fit { public const double MinLengthStretch = 0.25; public const double MaxLengthStretch = 4.0; public const double MinSideStretch = 0.5; public const double MaxSideStretch = 2.0; public const double MinRate = 0.5; public const double MaxRate = 2.0; public readonly ModelFrame Donor; public readonly ModelFrame Target; private readonly double[] m_stretch = new double[3]; private readonly double[] m_shift = new double[3]; private readonly double m_donorStart; private readonly double m_targetStart; public readonly double RateFactor; public readonly double TraceRateFactor; public const double LeanDegrees = 1.0; public Fit(ModelFrame donor, ModelFrame target, double donorStart, double targetStart, Fix fix) { Donor = donor; Target = target; m_donorStart = donorStart; m_targetStart = targetStart; double num = fix?.Stretch ?? 1.0; double v = BusinessEndRatio(); m_stretch[0] = Clamp(v, 0.25, 4.0) * num; for (int i = 1; i < 3; i++) { m_stretch[i] = Clamp(Ratio(i), 0.5, 2.0) * num; } RateFactor = Clamp(v, 0.5, 2.0); double num2 = (1.0 - donorStart) * donor.Size(0); TraceRateFactor = ((num2 < 1E-06) ? 1.0 : Clamp(target.Size(0) / num2, 0.5, 2.0)); m_shift[0] = fix?.Along ?? 0.0; m_shift[1] = fix?.Across ?? 0.0; } private double Ratio(int k) { double num = Donor.Size(k); if (!(num < 1E-06)) { return Target.Size(k) / num; } return 1.0; } private double BusinessEndRatio() { double num = (1.0 - m_donorStart) * Donor.Size(0); if (!(num < 1E-06)) { return (1.0 - m_targetStart) * Target.Size(0) / num; } return 1.0; } private double MapLength(double f) { if (f < m_donorStart && m_donorStart > 1E-06) { return f * m_targetStart / m_donorStart; } double num = 1.0 - m_donorStart; if (!(num < 1E-06)) { return m_targetStart + (f - m_donorStart) * (1.0 - m_targetStart) / num; } return f; } private static double Clamp(double v, double min, double max) { if (!(v < min)) { if (!(v > max)) { return v; } return max; } return min; } public static double Drift(bool firedAlongAxis, double startSpeed, double velocityAlongAxis, double radial, double lifetime) { return Math.Max(0.0, (firedAlongAxis ? Math.Abs(startSpeed) : 0.0) + Math.Abs(velocityAlongAxis) + radial) * lifetime; } public static List<double> RingFractions(double length, double drift = 0.0, double spacing = 0.4, double from = 0.08, double to = 0.95) { if (length > 1E-06) { to = Math.Min(to, 1.0 - drift / length); } if (to < from) { to = from; } int num = Math.Max(1, (int)Math.Round((to - from) * length / spacing) + 1); List<double> list = new List<double>(); if (num == 1) { list.Add((from + to) / 2.0); return list; } for (int i = 0; i < num; i++) { list.Add(from + (double)i * (to - from) / (double)(num - 1)); } return list; } public bool Leans(V3 aim) { double length = aim.Length; if (length < 1E-09) { return false; } return Math.Abs(V3.Dot(aim, Target.Unit(0))) / length < Math.Cos(Math.PI / 180.0); } public V3 Point(V3 p) { V3 result = new V3(0.0, 0.0, 0.0); for (int i = 0; i < 3; i++) { double num = Donor.Fraction(p, i); if (i == 0) { num = MapLength(num); } result += Target.Coordinate(i, num + m_shift[i]) * Target.Unit(i); } return result; } public V3 Rotate(V3 d) { V3 result = new V3(0.0, 0.0, 0.0); for (int i = 0; i < 3; i++) { result += V3.Dot(d, Donor.Unit(i)) * Target.Unit(i); } return result; } public double EmitterStretch(V3 d) { double length = d.Length; if (length < 1E-09) { return 1.0; } V3 v = new V3(0.0, 0.0, 0.0); for (int i = 0; i < 3; i++) { v += V3.Dot(d, Donor.Unit(i)) * m_stretch[i] * Target.Unit(i); } return v.Length / length; } } internal sealed class Fix { public double Along { get; set; } public double Across { get; set; } public double Stretch { get; set; } = 1.0; public Kind DonorKind { get; set; } } internal static class Fixes { private static readonly Dictionary<string, Fix> s_fixes = new Dictionary<string, Fix>(); public static Fix For(string prefab, string look) { if (!s_fixes.TryGetValue(prefab + "/" + look, out var value) && !s_fixes.TryGetValue(prefab, out value)) { return null; } return value; } } [HarmonyPatch] internal static class HintPatches { internal const string RowName = "DeepNorthStaffVisuals_hint"; internal const string Label = "Change look"; private static KeyHints s_hints; private static GameObject s_row; private static bool s_off; [HarmonyPatch(typeof(KeyHints), "UpdateHints")] [HarmonyPostfix] private static void UpdateHints(KeyHints __instance) { if (s_off) { return; } try { Refresh(__instance); } catch (Exception arg) { TurnOff($"The 'Change look' key hint failed; no hint from now on: {arg}"); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void Refresh(KeyHints hints) { if ((Object)(object)hints != (Object)(object)s_hints) { s_hints = hints; s_row = null; } GameObject combatHints = hints.m_combatHints; bool flag = (Object)(object)combatHints != (Object)null && combatHints.activeSelf && Dresser.HasLookable(handsOnly: true); if ((Object)(object)s_row == (Object)null) { if (!flag) { return; } s_row = BuildRow(combatHints.transform); if ((Object)(object)s_row == (Object)null) { TurnOff("The key hint's Block row wasn't found (a game update?): no 'Change look' hint"); return; } } if (s_row.activeSelf != flag) { s_row.SetActive(flag); } } private static GameObject BuildRow(Transform combat) { Transform val = combat.Find("Keyboard/Block"); if ((Object)(object)val == (Object)null) { return null; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, val.parent, false); ((Object)val2).name = "DeepNorthStaffVisuals_hint"; Transform val3 = val2.transform.Find("Text"); Transform val4 = val2.transform.Find("key_bkg/Key"); TMP_Text val5 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<TMP_Text>() : null); TMP_Text val6 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<TMP_Text>() : null); if ((Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null) { Object.Destroy((Object)(object)val2); return null; } val5.text = "Change look"; val6.text = Plugin.KeyName; return val2; } private static void TurnOff(string message) { s_off = true; Plugin.Log.LogWarning((object)message); if ((Object)(object)s_row != (Object)null) { s_row.SetActive(false); } } } internal static class Looks { public const string Plain = "Plain"; public static readonly string[] Order = new string[7] { "Frostfire", "Thunderblood", "Bleeding", "Storming", "Primal", "Dyrnwyn", "Frostner" }; private static readonly Dictionary<string, Dictionary<Kind, string>> s_donors = new Dictionary<string, Dictionary<Kind, string>> { ["Frostfire"] = DeepNorth("FrostFire"), ["Thunderblood"] = DeepNorth("BloodLightning"), ["Bleeding"] = Ashlands("SwordNiedhoggBlood", "THSwordSlayerBlood", "MaceEldnerBlood", "SpearSplitner_Blood", "BowAshlandsBlood", "CrossbowRipperBlood"), ["Storming"] = Ashlands("SwordNiedhoggLightning", "THSwordSlayerLightning", "MaceEldnerLightning", "SpearSplitner_Lightning", "BowAshlandsStorm", "CrossbowRipperLightning"), ["Primal"] = Ashlands("SwordNiedhoggNature", "THSwordSlayerNature", "MaceEldnerNature", "SpearSplitner_Nature", "BowAshlandsRoot", "CrossbowRipperNature"), ["Dyrnwyn"] = new Dictionary<Kind, string> { [Kind.Sword] = "SwordDyrnwyn" }, ["Frostner"] = new Dictionary<Kind, string> { [Kind.Mace] = "MaceSilver" } }; private static readonly Dictionary<Kind, Kind[]> s_fallbacks = new Dictionary<Kind, Kind[]> { [Kind.Sword] = new Kind[2] { Kind.Greatsword, Kind.Knife }, [Kind.Greatsword] = new Kind[1] { Kind.Sword }, [Kind.Knife] = new Kind[1] { Kind.Sword }, [Kind.Axe] = new Kind[2] { Kind.Battleaxe, Kind.Mace }, [Kind.Battleaxe] = new Kind[3] { Kind.Axe, Kind.Sledge, Kind.Mace }, [Kind.Mace] = new Kind[1] { Kind.Sledge }, [Kind.Sledge] = new Kind[1] { Kind.Mace }, [Kind.Spear] = new Kind[1] { Kind.Atgeir }, [Kind.Atgeir] = new Kind[1] { Kind.Spear }, [Kind.Staff] = new Kind[2] { Kind.Atgeir, Kind.Spear }, [Kind.Bow] = new Kind[1] { Kind.Crossbow }, [Kind.Crossbow] = new Kind[1] { Kind.Bow } }; private static readonly string[] s_followers = new string[11] { "flames", "fx_Torch_Basic", "Burny vfx", "Clouds", "Spores", "Spores_World", "soft cloud", "vfx_BloodHit 1", "blood drip", "Sparcs", "Splats" }; private static readonly string[] s_spreaders = new string[2] { "Swirls", "Lightning" }; public const string NoteKey = "DeepNorthStaffVisuals_look"; private static Dictionary<Kind, string> DeepNorth(string variant) { return new Dictionary<Kind, string> { [Kind.Sword] = "SwordGold_" + variant, [Kind.Greatsword] = "THSwordGold_" + variant, [Kind.Knife] = "KnifeGold_" + variant, [Kind.Axe] = "AxeGold_" + variant, [Kind.Battleaxe] = "BattleaxeGold_" + variant, [Kind.Mace] = "MaceGold_" + variant, [Kind.Sledge] = "SledgeGold_" + variant, [Kind.Spear] = "SpearGold_" + variant, [Kind.Atgeir] = "AtgeirGold_" + variant, [Kind.Bow] = "BowGold_" + variant, [Kind.Crossbow] = "CrossbowGold_" + variant }; } private static Dictionary<Kind, string> Ashlands(string sword, string greatsword, string mace, string spear, string bow, string crossbow) { return new Dictionary<Kind, string> { [Kind.Sword] = sword, [Kind.Greatsword] = greatsword, [Kind.Mace] = mace, [Kind.Spear] = spear, [Kind.Bow] = bow, [Kind.Crossbow] = crossbow }; } public static List<string> DonorsFor(string look, Kind kind) { List<string> names = new List<string>(); if (look == null || !s_donors.TryGetValue(look, out var donors)) { return names; } Add(kind); if (s_fallbacks.TryGetValue(kind, out var value)) { Kind[] array = value; for (int i = 0; i < array.Length; i++) { Add(array[i]); } } foreach (Kind value3 in Enum.GetValues(typeof(Kind))) { Add(value3); } return names; void Add(Kind k) { if (donors.TryGetValue(k, out var value2) && !names.Contains(value2)) { names.Add(value2); } } } public static bool FollowsWeapon(string emitterName) { return Array.IndexOf(s_followers, BaseName(emitterName)) >= 0; } public static bool SpreadsAlongWeapon(string emitterName) { return Array.IndexOf(s_spreaders, BaseName(emitterName)) >= 0; } private static string BaseName(string emitterName) { if (string.IsNullOrEmpty(emitterName)) { return ""; } int num = emitterName.LastIndexOf(" (", StringComparison.Ordinal); if (num <= 0 || !emitterName.EndsWith(")", StringComparison.Ordinal)) { return emitterName; } return emitterName.Substring(0, num); } public static double RateBoost(string look) { if (!(look == "Bleeding")) { return 1.0; } return 2.5; } public static double RingRate(string look) { if (!(look == "Thunderblood")) { return 1.0; } return 0.6; } public static double RingLife(string look) { if (!(look == "Thunderblood")) { return 1.0; } return 0.6; } public static int Code(string look) { if (Array.IndexOf(Order, look) < 0) { return 0; } return StringExtensionMethods.GetStableHashCode(look); } public static string FromCode(int code) { if (code == 0) { return "Plain"; } string[] order = Order; foreach (string text in order) { if (StringExtensionMethods.GetStableHashCode(text) == code) { return text; } } return "Plain"; } public static string FromNote(IDictionary<string, string> notes) { if (notes == null || !notes.TryGetValue("DeepNorthStaffVisuals_look", out var value) || Array.IndexOf(Order, value) < 0) { return "Plain"; } return value; } public static void SetNote(IDictionary<string, string> notes, string look) { if (Array.IndexOf(Order, look) >= 0) { notes["DeepNorthStaffVisuals_look"] = look; } else { notes.Remove("DeepNorthStaffVisuals_look"); } } public static string StepNote(IDictionary<string, string> notes, Func<string, bool> isAvailable) { string text = Next(FromNote(notes), isAvailable); SetNote(notes, text); return text; } public static string TooltipLine(string look) { if (Array.IndexOf(Order, look) < 0) { return ""; } return "\nLook: <color=orange>" + look + "</color>"; } public static string Next(string current, Func<string, bool> isAvailable) { for (int i = Array.IndexOf(Order, current) + 1; i < Order.Length; i++) { if (isAvailable(Order[i])) { return Order[i]; } } return "Plain"; } } [BepInPlugin("algo7.deepnorthstaffvisuals", "DeepNorthStaffVisuals", "1.0.1")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "algo7.deepnorthstaffvisuals"; public const string Name = "DeepNorthStaffVisuals"; public const string PluginVersion = "1.0.1"; internal static ManualLogSource Log; private static ConfigEntry<KeyboardShortcut> s_key; private static Func<Player, bool> s_takeInput; private static bool s_running; private static readonly HashSet<string> s_logged = new HashSet<string>(); internal static string KeyName => ((object)s_key.Value/*cast due to .constrained prefix*/).ToString(); private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; if (Application.isBatchMode) { Log.LogInfo((object)"DeepNorthStaffVisuals loaded (v1.0.1): dedicated server, nothing to do"); return; } s_key = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Change look key", new KeyboardShortcut((KeyCode)108, Array.Empty<KeyCode>()), "Changes the look of your equipped staff (also while it's on your back)."); try { s_takeInput = AccessTools.MethodDelegate<Func<Player, bool>>(AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null), (object)null, true); } catch (Exception arg) { Log.LogError((object)$"Looks are off: the game's input check wasn't found (a game update?): {arg}"); return; } Harmony harmony = new Harmony("algo7.deepnorthstaffvisuals"); if (!TryPatch(harmony, typeof(Dresser), "equipment hook")) { Log.LogError((object)"Looks are off: without the equipment hook nothing can be shown"); return; } if (!TryPatch(harmony, typeof(HintPatches), "key hint hook")) { Log.LogWarning((object)"No 'Change look' key hint (the key still works)"); } if (!TryPatch(harmony, typeof(StandPatches), "item stand hook")) { Log.LogWarning((object)"No looks on item stands (the rest works)"); } if (!TryPatch(harmony, typeof(GroundPatches), "dropped item hook")) { Log.LogWarning((object)"No looks on dropped staffs (the rest works)"); } if (!TryPatch(harmony, typeof(TooltipPatches), "tooltip hook")) { Log.LogWarning((object)"No look line in tooltips (the rest works)"); } SceneManager.sceneLoaded += OnSceneLoaded; s_running = true; Log.LogInfo((object)"DeepNorthStaffVisuals loaded (v1.0.1)"); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { Dresser.Reset(); StandPatches.Reset(); EffectKit.Clear(); } private void Update() { if (!s_running) { return; } try { CheckKey(); } catch (Exception arg) { ErrorOnce("key", $"Changing the look failed: {arg}"); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void CheckKey() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && KeyPressed() && s_takeInput(localPlayer)) { Dresser.OnKey(); } } private static bool KeyPressed() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0035: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = s_key.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!ZInput.GetKey(modifier, false)) { return false; } } return true; } private static bool TryPatch(Harmony harmony, Type patches, string what) { try { harmony.PatchAll(patches); return true; } catch (Exception arg) { Log.LogError((object)$"Could not install the {what}: {arg}"); return false; } } internal static void ErrorOnce(string kind, string message) { if (s_logged.Add("error:" + kind)) { Log.LogError((object)message); } } internal static void WarnOnce(string kind, string message) { if (s_logged.Add("warn:" + kind)) { Log.LogWarning((object)message); } } } [HarmonyPatch] internal static class StandPatches { private sealed class StandLook { public bool Read; public uint Revision; public string Look; } private static FieldRef<ItemStand, GameObject> s_model; private static FieldRef<ItemStand, int> s_modelItem; private static FieldRef<ItemStand, ZNetView> s_nview; private static ConditionalWeakTable<ItemStand, StandLook> s_looks = new ConditionalWeakTable<ItemStand, StandLook>(); private static bool Prepare() { s_model = AccessTools.FieldRefAccess<ItemStand, GameObject>("m_visualItem"); s_modelItem = AccessTools.FieldRefAccess<ItemStand, int>("m_visualHash"); s_nview = AccessTools.FieldRefAccess<ItemStand, ZNetView>("m_nview"); return true; } internal static void Reset() { s_looks = new ConditionalWeakTable<ItemStand, StandLook>(); } [HarmonyPatch(typeof(ItemStand), "SetVisualItem")] [HarmonyPostfix] private static void SetVisualItem(ItemStand __instance) { Check(__instance); } [HarmonyPatch(typeof(ItemStand), "UpdateVisual")] [HarmonyPostfix] private static void UpdateVisual(ItemStand __instance) { Check(__instance); } private static void Check(ItemStand stand) { try { Wear(stand); } catch (Exception arg) { Plugin.ErrorOnce("stand", $"Couldn't show the look on an item stand (the staff stays plain): {arg}"); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void Wear(ItemStand stand) { GameObject val = s_model.Invoke(stand); ZNetView val2 = s_nview.Invoke(stand); ZDO val3 = (((Object)(object)val2 != (Object)null) ? val2.GetZDO() : null); if ((Object)(object)val == (Object)null || val3 == null || (Object)(object)ObjectDB.instance == (Object)null) { return; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(s_modelItem.Invoke(stand)); if (EffectKit.LookKind(itemPrefab) != Kind.None) { StandLook orCreateValue = s_looks.GetOrCreateValue(stand); if (!orCreateValue.Read || orCreateValue.Revision != val3.DataRevision) { orCreateValue.Look = Looks.FromNote(Dresser.NotesOf(val3, -1)); orCreateValue.Read = true; orCreateValue.Revision = val3.DataRevision; } Dresser.Wear(val, itemPrefab, orCreateValue.Look); } } } [HarmonyPatch] internal static class GroundPatches { [HarmonyPatch(typeof(ItemDrop), "Start")] [HarmonyPostfix] private static void Start(ItemDrop __instance) { try { Wear(__instance); } catch (Exception arg) { Plugin.ErrorOnce("ground", $"Couldn't show the look on a dropped staff (it stays plain): {arg}"); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void Wear(ItemDrop drop) { ItemData itemData = drop.m_itemData; if (itemData == null || EffectKit.LookKind(itemData.m_dropPrefab) == Kind.None) { return; } string text = Looks.FromNote(itemData.m_customData); if (!(text == "Plain")) { Transform val = ((Component)drop).transform.Find("attach"); if ((Object)(object)val != (Object)null) { Dresser.Wear(((Component)val).gameObject, itemData.m_dropPrefab, text); } } } } [HarmonyPatch] internal static class TooltipPatches { [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] [HarmonyPostfix] private static void GetTooltip(ItemData item, bool crafting, ref string __result) { if (crafting) { return; } try { __result += LookLine(item); } catch (Exception arg) { Plugin.ErrorOnce("tooltip", $"Couldn't add the look to a tooltip: {arg}"); } } [MethodImpl(MethodImplOptions.NoInlining)] private static string LookLine(ItemData item) { if (item == null || EffectKit.LookKind(item.m_dropPrefab) == Kind.None) { return ""; } return Looks.TooltipLine(Looks.FromNote(item.m_customData)); } } internal enum Kind { None, Sword, Greatsword, Knife, Axe, Battleaxe, Mace, Sledge, Spear, Atgeir, Bow, Crossbow, Staff } internal static class WeaponKinds { private static readonly string[] s_notWeapons = new string[4] { "Tankard", "TankardAnniversary", "TankardOdin", "Tankard_dvergr" }; private static readonly string[] s_takeLooks = new string[2] { "StaffOrbofAhri", "StaffThunderBlood" }; public static Kind KindOf(ItemType type, SkillType skill, string prefabName) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected I4, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if (Array.IndexOf(s_notWeapons, prefabName) >= 0) { return Kind.None; } if ((int)type != 3 && (int)type != 14 && (int)type != 22 && (int)type != 4) { return Kind.None; } bool flag = (int)type == 14; switch (skill - 1) { case 0: if (!flag) { return Kind.Sword; } return Kind.Greatsword; case 1: return Kind.Knife; case 2: if (!flag) { return Kind.Mace; } return Kind.Sledge; case 3: return Kind.Atgeir; case 4: return Kind.Spear; case 6: if (!flag) { return Kind.Axe; } return Kind.Battleaxe; case 7: return Kind.Bow; case 13: return Kind.Crossbow; case 8: case 9: return Kind.Staff; default: return Kind.None; } } public static bool CanTakeLook(string prefabName) { return Array.IndexOf(s_takeLooks, prefabName) >= 0; } public static int HeadSign(Kind kind) { if (kind != Kind.Spear) { return 1; } return -1; } public static double EffectStart(Kind kind) { return kind switch { Kind.Sword => 0.21, Kind.Greatsword => 0.27, Kind.Knife => 0.26, Kind.Axe => 0.58, Kind.Battleaxe => 0.74, Kind.Mace => 0.81, Kind.Sledge => 0.74, Kind.Spear => 0.66, Kind.Atgeir => 0.4, Kind.Staff => 0.55, Kind.Crossbow => 0.69, _ => 0.0, }; } public static double GameEffectStart(Kind kind) { if (kind != Kind.Atgeir) { return EffectStart(kind); } return 0.55; } } internal static class PluginInfo { public const string Version = "1.0.1"; } }