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 SpiritAnimism v0.5.0
plugins/SpiritAnimism.dll
Decompiled 18 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [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("Brruid")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0+b484c870d91cfd57226fb8b24318bf034cb58e23")] [assembly: AssemblyProduct("SpiritAnimism")] [assembly: AssemblyTitle("SpiritAnimism")] [assembly: AssemblyVersion("0.5.0.0")] namespace SpiritAnimism; internal static class Dismiss { public static void MySummons() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } int num = 0; bool flag = false; foreach (Summon item in Summons.Mine()) { if (!Saddles.DismissWhileRiding.Value && Saddles.IsRiding(localPlayer, item)) { flag = true; continue; } if (!item.View.HasOwner()) { item.View.ClaimOwnership(); } item.View.InvokeRPC(ZNetView.Everybody, "RPC_UnSummon", Array.Empty<object>()); num++; } Plugin.Log.LogInfo((object)$"Dismissed {num} summon(s)"); string text = ((num > 0) ? string.Format("Dismissed {0} spirit{1}", num, (num == 1) ? "" : "s") : ""); if (flag) { text = ((text == "") ? "" : (text + ". ")) + "Dismount to dismiss your mount"; } if (text != "") { ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } public static bool InputIsFree() { if (!Console.IsVisible() && !Menu.IsVisible()) { if (!((Object)(object)Chat.instance == (Object)null)) { return !Chat.instance.HasFocus(); } return true; } return false; } } internal readonly struct Slot { public readonly float Right; public readonly float Forward; public readonly SummonType Kind; public Slot(float right, float forward, SummonType kind = null) { Right = right; Forward = forward; Kind = kind; } public Vector3 WorldPosition(Vector3 origin, Vector3 forward) { //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_0006: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.Cross(Vector3.up, forward); return origin + val * Right + forward * Forward; } } internal abstract class Formation { public const float RowSpacing = 3f; public static readonly Formation Leader = new LeaderFormation(); public static readonly Formation Defense = new DefenseFormation(); public static readonly Formation Bubble = new BubbleFormation(); public static readonly Formation[] BuiltIn = new Formation[3] { Leader, Defense, Bubble }; public abstract string Name { get; } public abstract List<Slot> Layout(int count, float distance, float gap); public static Formation BuiltInNamed(string name) { Formation[] builtIn = BuiltIn; foreach (Formation formation in builtIn) { if (string.Equals(formation.Name, name, StringComparison.OrdinalIgnoreCase)) { return formation; } } return null; } protected static void Ring(List<Slot> slots, int n, float r) { for (int i = 0; i < n; i++) { float num = (float)i * 2f * (float)Math.PI / (float)n; slots.Add(new Slot(r * Mathf.Sin(num), r * Mathf.Cos(num))); } } } internal sealed class LeaderFormation : Formation { private const float ArcRadians = 2.7925267f; public override string Name => "Leader"; public override List<Slot> Layout(int count, float distance, float gap) { List<Slot> list = new List<Slot>(count); int num = 0; while (list.Count < count) { float num2 = distance + (float)num * 3f; int num3 = Mathf.Max(1, Mathf.FloorToInt(num2 * 2.7925267f / gap) + 1); int num4 = Mathf.Min(count - list.Count, num3); float num5 = gap / num2; List<float> list2 = new List<float>(num4); for (int i = 0; i < num4; i++) { list2.Add(((float)i - (float)(num4 - 1) / 2f) * num5); } list2.Sort((float a, float b) => Mathf.Abs(a).CompareTo(Mathf.Abs(b))); foreach (float item in list2) { list.Add(new Slot(num2 * Mathf.Sin(item), (0f - num2) * Mathf.Cos(item))); } num++; } return list; } } internal sealed class DefenseFormation : Formation { public override string Name => "Defense"; public override List<Slot> Layout(int count, float distance, float gap) { List<Slot> list = new List<Slot>(count); int num = 0; while (list.Count < count) { float num2 = distance + (float)num * 3f; int num3 = Mathf.Max(1, Mathf.FloorToInt((float)Math.PI * 2f * num2 / gap)); Formation.Ring(list, Mathf.Min(count - list.Count, num3), num2); num++; } return list; } } internal sealed class BubbleFormation : Formation { public override string Name => "Bubble"; public override List<Slot> Layout(int count, float distance, float gap) { List<Slot> list = new List<Slot>(count); Formation.Ring(list, count, Mathf.Max(distance, (float)count * gap / ((float)Math.PI * 2f))); return list; } } internal sealed class CustomFormation : Formation { private readonly string _name; public readonly List<Slot> Slots; public override string Name => _name; public CustomFormation(string name, List<Slot> slots) { _name = name; Slots = slots; } public override List<Slot> Layout(int count, float distance, float gap) { List<Slot> list = new List<Slot>(Slots); if (count > list.Count) { float num = 0f; foreach (Slot slot in Slots) { if (!(slot.Forward > gap)) { num = Mathf.Max(num, Mathf.Sqrt(slot.Right * slot.Right + slot.Forward * slot.Forward)); } } float distance2 = Mathf.Max(distance, num + Mathf.Max(3f, gap)); list.AddRange(Formation.Leader.Layout(count - list.Count, distance2, gap)); } return list; } } internal static class Formations { private sealed class FollowState { public Vector3 LastPosition; public float StillSince; public bool Settled; public Vector3 AnchorPosition; public Vector3 AnchorForward; public float NextRefresh; public readonly Dictionary<ZDOID, Vector3> Targets = new Dictionary<ZDOID, Vector3>(); } [HarmonyPatch(typeof(BaseAI), "Follow")] private static class FollowPatch { private static readonly Dictionary<ZDOID, float> _passSide = new Dictionary<ZDOID, float>(); private const float UndecidedAcross = 0.5f; private static bool Prefix(BaseAI __instance, GameObject go, float dt, Character ___m_character) { //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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)___m_character == (Object)null || (Object)(object)go == (Object)null) { return true; } SummonType summonType = Summons.SpeciesOf(((Object)((Component)___m_character).gameObject).name); if (summonType == null) { return true; } Player component = go.GetComponent<Player>(); if ((Object)(object)component == (Object)null) { return true; } ZNetView component2 = ((Component)___m_character).GetComponent<ZNetView>(); if ((Object)(object)component2 == (Object)null || !component2.IsValid()) { return true; } Summon summon = new Summon(___m_character, summonType, component2); Vector3? val = TargetFor(summon, component); if (!val.HasValue) { return true; } Vector3 position = ((Component)___m_character).transform.position; if (!((Character)component).IsAttached() && InFrontOf(component, position) && !AheadOf(component, val.Value)) { __instance.StopMoving(); return false; } float num = Utils.DistanceXZ(val.Value, position); if (num < 2f) { __instance.StopMoving(); return false; } Vector3 arg = ((Buffer.Value > 0f) ? AroundOthers(summon, position, val.Value) : val.Value); MoveTo(__instance, dt, arg, 1f, num > 10f); return false; } private static bool InFrontOf(Player player, Vector3 point) { //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_0019: Unknown result type (might be due to invalid IL or missing references) if (Vector3.Distance(point, ((Component)player).transform.position) < 5f) { return AheadOf(player, point); } return false; } private static bool AheadOf(Player player, Vector3 point) { //IL_0006: 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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) return Vector3.Dot(Flat(((Component)player).transform.forward), Flat(point - ((Component)player).transform.position)) > 0.8f; } private static Vector3 AroundOthers(Summon summon, Vector3 from, Vector3 target) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) float num = Utils.DistanceXZ(target, from); if (num < 0.01f) { return target; } Vector3 val = Flat(target - from); Vector3 val2 = Vector3.Cross(Vector3.up, val); Character character = summon.Character; Character val3 = null; float num2 = num; float num3 = 0f; float num4 = 0f; foreach (Character allCharacter in Character.GetAllCharacters()) { if ((Object)(object)allCharacter == (Object)(object)character || allCharacter.IsDead()) { continue; } Vector3 val4 = ((Component)allCharacter).transform.position - from; val4.y = 0f; float num5 = Vector3.Dot(val4, val); if (!(num5 <= 0f) && !(num5 >= num)) { float num6 = Vector3.Dot(val4, val2); float num7 = character.GetRadius() + allCharacter.GetRadius() + Buffer.Value; if (!(Mathf.Abs(num6) >= num7) && !(num5 - num7 >= num2)) { val3 = allCharacter; num2 = num5 - num7; num3 = num6; num4 = num7; } } } if ((Object)(object)val3 == (Object)null) { return target; } ZDOID uid = summon.Zdo.m_uid; if (Mathf.Abs(num3) >= 0.5f || !_passSide.TryGetValue(uid, out var value)) { value = ((num3 >= 0f) ? (-1f) : 1f); } _passSide[uid] = value; return ((Component)val3).transform.position + val2 * (value * num4); } } private const string FileName = "Brruid.SpiritAnimism.Formations.cfg"; internal static readonly int FormationKey = StringExtensionMethods.GetStableHashCode("SpiritAnimism.Formation"); private const string SpecVersion = "1"; private const float RefreshSeconds = 0.25f; private const float FilePollSeconds = 1f; private const float DeadZone = 2f; private const float ArriveWithin = 1f; private const float RunBeyond = 10f; private const float SettleAfterSeconds = 1f; private const float SettleBreakMargin = 3f; private const float FreezeDistance = 5f; private const float FreezeFacingDot = 0.8f; internal static ConfigEntry<string> Chosen; internal static ConfigEntry<float> Distance; internal static ConfigEntry<float> Buffer; private static string _filePath; private static DateTime _fileLastWrite; private static float _nextFilePoll; private static readonly Dictionary<string, CustomFormation> _custom = new Dictionary<string, CustomFormation>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> _warnedUnknown = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, FollowState> _states = new Dictionary<string, FollowState>(); private static readonly Func<BaseAI, float, Vector3, float, bool, bool> MoveTo = (Func<BaseAI, float, Vector3, float, bool, bool>)Delegate.CreateDelegate(typeof(Func<BaseAI, float, Vector3, float, bool, bool>), AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null)); private const string DefaultFile = "## SpiritAnimism formations. Each [Name] below is a formation you can pick with\n## Formation = Name in Brruid.SpiritAnimism.cfg. One line per slot:\n## SlotN = right, forward metres from you; negative = left / behind\n## SlotN = Kind, right, forward reserved for one kind: Bear, Boar, Moose or Wolf\n## You stand at 0, 0 and the shape turns with you. A reserved slot stays empty when\n## that kind is not out. Summons beyond the listed slots form a Leader arc behind you.\n## Leader, Defense and Bubble are built in and cannot be redefined here.\n## Edits apply while you play.\n\n[Escort]\nSlot1 = Bear, 3, 10\nSlot2 = Bear, -3, 10\nSlot3 = Wolf, 3, -2\nSlot4 = Wolf, -3, -2\nSlot5 = 0, -5\nSlot6 = 2.5, -6\nSlot7 = -2.5, -6\n"; public static void Init(ConfigFile config) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown Chosen = config.Bind<string>("Formations", "Formation", "Leader", "How your summons arrange themselves around you while following. Leader = an arc behind you. Defense = a ring around you, more rings when full. Bubble = one ring that widens to fit. Or the name of a formation from Brruid.SpiritAnimism.Formations.cfg beside this file."); Distance = config.Bind<float>("Formations", "Distance", 5f, new ConfigDescription("How far the nearest row or ring stands from you, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 20f), Array.Empty<object>())); Buffer = config.Bind<float>("Formations", "Buffer", 1f, new ConfigDescription("Air between animals, in metres: the gap between their spots in formation, and how wide a walking animal steers around anyone standing in its way, you and your mount included. 0 = bodies touch and nobody steers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); _filePath = Path.Combine(Path.GetDirectoryName(config.ConfigFilePath), "Brruid.SpiritAnimism.Formations.cfg"); if (!File.Exists(_filePath)) { File.WriteAllText(_filePath, "## SpiritAnimism formations. Each [Name] below is a formation you can pick with\n## Formation = Name in Brruid.SpiritAnimism.cfg. One line per slot:\n## SlotN = right, forward metres from you; negative = left / behind\n## SlotN = Kind, right, forward reserved for one kind: Bear, Boar, Moose or Wolf\n## You stand at 0, 0 and the shape turns with you. A reserved slot stays empty when\n## that kind is not out. Summons beyond the listed slots form a Leader arc behind you.\n## Leader, Defense and Bubble are built in and cannot be redefined here.\n## Edits apply while you play.\n\n[Escort]\nSlot1 = Bear, 3, 10\nSlot2 = Bear, -3, 10\nSlot3 = Wolf, 3, -2\nSlot4 = Wolf, -3, -2\nSlot5 = 0, -5\nSlot6 = 2.5, -6\nSlot7 = -2.5, -6\n"); Plugin.Log.LogInfo((object)("Formations file created at " + _filePath)); } LoadFile(); } public static void Update() { if (!(Time.unscaledTime < _nextFilePoll)) { _nextFilePoll = Time.unscaledTime + 1f; if (!File.Exists(_filePath)) { File.WriteAllText(_filePath, "## SpiritAnimism formations. Each [Name] below is a formation you can pick with\n## Formation = Name in Brruid.SpiritAnimism.cfg. One line per slot:\n## SlotN = right, forward metres from you; negative = left / behind\n## SlotN = Kind, right, forward reserved for one kind: Bear, Boar, Moose or Wolf\n## You stand at 0, 0 and the shape turns with you. A reserved slot stays empty when\n## that kind is not out. Summons beyond the listed slots form a Leader arc behind you.\n## Leader, Defense and Bubble are built in and cannot be redefined here.\n## Edits apply while you play.\n\n[Escort]\nSlot1 = Bear, 3, 10\nSlot2 = Bear, -3, 10\nSlot3 = Wolf, 3, -2\nSlot4 = Wolf, -3, -2\nSlot5 = 0, -5\nSlot6 = 2.5, -6\nSlot7 = -2.5, -6\n"); LoadFile(); Plugin.Log.LogInfo((object)"Formations file recreated"); } else if (File.GetLastWriteTimeUtc(_filePath) != _fileLastWrite) { LoadFile(); } } } private static void LoadFile() { string[] array; try { array = File.ReadAllLines(_filePath); } catch (IOException ex) { Plugin.Log.LogWarning((object)("Formations file not read yet: " + ex.Message)); return; } _fileLastWrite = File.GetLastWriteTimeUtc(_filePath); _custom.Clear(); _warnedUnknown.Clear(); string text = null; List<Slot> list = null; for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#")) { continue; } if (text2.StartsWith("[") && text2.EndsWith("]")) { text = text2.Substring(1, text2.Length - 2).Trim(); if (Formation.BuiltInNamed(text) != null) { Plugin.Log.LogWarning((object)$"Formations file line {i + 1}: {text} is built in and cannot be redefined"); text = null; list = null; } else { list = new List<Slot>(); _custom[text] = new CustomFormation(text, list); } } else { if (list == null) { continue; } int num = text2.IndexOf('='); if (num < 0) { continue; } string[] array2 = text2.Substring(num + 1).Split(new char[1] { ',' }); SummonType summonType = null; int num2 = 0; if (array2.Length == 3) { summonType = Summons.Named(array2[0].Trim()); if (summonType == null) { Plugin.Log.LogWarning((object)$"Formations file line {i + 1}: unknown kind {array2[0].Trim()}; use Bear, Boar, Moose or Wolf"); continue; } num2 = 1; } else if (array2.Length != 2) { Plugin.Log.LogWarning((object)$"Formations file line {i + 1}: expected 'right, forward' or 'Kind, right, forward'"); continue; } if (!TryParseMetres(array2[num2], out var value) || !TryParseMetres(array2[num2 + 1], out var value2)) { Plugin.Log.LogWarning((object)$"Formations file line {i + 1}: coordinates must be numbers in metres"); } else { list.Add(new Slot(value, value2, summonType)); } } } Plugin.Log.LogInfo((object)$"Formations file loaded: {_custom.Count} custom formation(s)"); } private static bool TryParseMetres(string text, out float value) { if (float.TryParse(text.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out value) && !float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static Formation Named(string name) { Formation formation = Formation.BuiltInNamed(name); if (formation != null) { return formation; } if (_custom.TryGetValue(name, out var value)) { return value; } if (_warnedUnknown.Add(name)) { Plugin.Log.LogWarning((object)("Unknown formation " + name + "; using Leader")); } return Formation.Leader; } private static bool SpecFor(Summon summon, Player summoner, out Formation formation, out float distance) { ZDO zdo = summon.Zdo; if ((Object)(object)summoner == (Object)(object)Player.m_localPlayer) { formation = Named(Chosen.Value); distance = Distance.Value; string text = "1;" + formation.Name + ";" + distance.ToString("0.#", CultureInfo.InvariantCulture); if (summon.View.IsOwner() && zdo.GetString(FormationKey, "") != text) { zdo.Set(FormationKey, text); } return true; } string[] array = zdo.GetString(FormationKey, "").Split(new char[1] { ';' }); if (array.Length != 3 || array[0] != "1" || !TryParseMetres(array[2], out distance)) { formation = null; distance = 0f; return false; } formation = Named(array[1]); distance = Mathf.Clamp(distance, 3f, 20f); return true; } private static Vector3? TargetFor(Summon summon, Player summoner) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if (!SpecFor(summon, summoner, out var formation, out var distance)) { return null; } string playerName = summoner.GetPlayerName(); if (!_states.TryGetValue(playerName, out var value)) { value = new FollowState { LastPosition = ((Component)summoner).transform.position, StillSince = Time.time }; _states[playerName] = value; } if (Time.time >= value.NextRefresh) { value.NextRefresh = Time.time + 0.25f; Refresh(value, summoner, formation, distance); } if (!value.Targets.TryGetValue(summon.Zdo.m_uid, out var value2)) { return null; } return value2; } private static void Refresh(FollowState state, Player summoner, Formation formation, float distance) { //IL_0006: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_007e: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00b2: 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_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: 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_01d9: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)summoner).transform.position; Vector3 val = Flat(((Component)summoner).transform.forward); if (Vector3.Distance(position, state.LastPosition) > 0.2f) { state.LastPosition = position; state.StillSince = Time.time; } if (!state.Settled && Time.time - state.StillSince >= 1f) { state.Settled = true; state.AnchorPosition = position; state.AnchorForward = val; } else if (state.Settled && Vector3.Distance(position, state.AnchorPosition) > distance + 3f) { state.Settled = false; } Vector3 origin = (state.Settled ? state.AnchorPosition : position); Vector3 forward = (state.Settled ? state.AnchorForward : val); List<Summon> list = new List<Summon>(); string playerName = summoner.GetPlayerName(); float num = 0f; foreach (Summon item in Summons.Standing()) { if (item.CalledBy(playerName) && item.Zdo.GetLong(ZDOVars.s_user, 0L) == 0L) { list.Add(item); num = Mathf.Max(num, item.Character.GetRadius()); } } list.Sort((Summon a, Summon b) => Age(b).CompareTo(Age(a))); float gap = 2f * num + Buffer.Value; state.Targets.Clear(); List<Slot> slots = formation.Layout(list.Count, distance, gap); foreach (KeyValuePair<Summon, Slot> item2 in Assign(list, slots)) { state.Targets[item2.Key.Zdo.m_uid] = item2.Value.WorldPosition(origin, forward); } } private static TimeSpan Age(Summon summon) { BaseAI component = ((Component)summon.Character).GetComponent<BaseAI>(); if (!((Object)(object)component != (Object)null)) { return TimeSpan.Zero; } return component.GetTimeSinceSpawned(); } private static List<KeyValuePair<Summon, Slot>> Assign(List<Summon> followers, List<Slot> slots) { List<KeyValuePair<Summon, Slot>> list = new List<KeyValuePair<Summon, Slot>>(followers.Count); List<Summon> list2 = new List<Summon>(followers); List<Slot> list3 = new List<Slot>(); foreach (Slot slot in slots) { if (slot.Kind == null) { list3.Add(slot); continue; } int num = list2.FindIndex((Summon s) => s.Species == slot.Kind); if (num >= 0) { list.Add(new KeyValuePair<Summon, Slot>(list2[num], slot)); list2.RemoveAt(num); } } for (int num2 = 0; num2 < list2.Count && num2 < list3.Count; num2++) { list.Add(new KeyValuePair<Summon, Slot>(list2[num2], list3[num2])); } return list; } private static Vector3 Flat(Vector3 direction) { //IL_0022: 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) direction.y = 0f; if (!(((Vector3)(ref direction)).sqrMagnitude < 0.001f)) { return ((Vector3)(ref direction)).normalized; } return Vector3.forward; } } internal static class Picker { public const string Random = "Random"; private const string StaffItemName = "$item_staff_spiritcaller"; private const string StaffPrefabName = "StaffSpiritCaller"; private const string OtherPickerGuid = "algo7.pickyourspirit"; private const string PickKey = "SpiritAnimism.Pick"; internal static ConfigEntry<string> Order; internal static ConfigEntry<bool> SkipFull; private static bool _disabled; public static bool Enabled => !_disabled; public static void Init(ConfigFile config) { Order = config.Bind<string>("Pick", "Order", "Random, Bear, Moose, Boar, Wolf", "What the secondary attack cycles through with the Spirit Caller in hand, in this order. Random is the game's own roll. The current pick is remembered with your character."); SkipFull = config.Bind<bool>("Pick", "SkipFull", true, "Skip animals you already have at your staff's limit, both when cycling and in the Random roll, so a cast never sends your oldest one home. When every kind is full the game's own roll applies."); if (Chainloader.PluginInfos.ContainsKey("algo7.pickyourspirit")) { _disabled = true; Plugin.Log.LogWarning((object)"PickYourSpirit is loaded; SpiritAnimism's own picker is switched off to avoid fighting over the cast"); } } public static bool IsSpiritCaller(ItemData item) { if (item == null) { return false; } if (item.m_shared != null && item.m_shared.m_name == "$item_staff_spiritcaller") { return true; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name == "StaffSpiritCaller"; } return false; } public static SummonType CurrentType() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer != (Object)null) || !localPlayer.m_customData.TryGetValue("SpiritAnimism.Pick", out var value)) { return null; } return Summons.Named(value); } public static void Cycle() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } List<string> list = Steps(); if (list.Count == 0) { return; } SummonType summonType = CurrentType(); string currentName = ((summonType != null) ? summonType.Name : "Random"); int num = list.FindIndex((string step) => string.Equals(step, currentName, StringComparison.OrdinalIgnoreCase)); for (int num2 = 1; num2 <= list.Count; num2++) { SummonType summonType2 = Summons.Named(list[(num + num2) % list.Count]); if (summonType2 == null || !SkipFull.Value || !IsAtCap(summonType2)) { localPlayer.m_customData["SpiritAnimism.Pick"] = ((summonType2 != null) ? summonType2.Name : "Random"); break; } } ((Character)localPlayer).Message((MessageType)2, "Spirit: " + DisplayName(CurrentType()), 0, (Sprite)null, false); } public static string DisplayName(SummonType type) { if (type == null) { return "Random"; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(type.WildPrefabName) : null); Character val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Character>() : null); if ((Object)(object)val2 == (Object)null || string.IsNullOrEmpty(val2.m_name)) { return type.Name; } return Localization.instance.Localize(val2.m_name); } public static bool IsAtCap(SummonType type) { int num = 0; int num2 = 0; foreach (Summon item in Summons.Mine()) { if (item.Species == type) { num++; if (num2 == 0) { num2 = item.Zdo.GetInt(ZDOVars.s_maxInstances, 0); } } } if (num2 > 0) { return num >= num2; } return false; } public static GameObject[] WithRoom(GameObject[] spawnList) { List<GameObject> list = new List<GameObject>(); foreach (GameObject val in spawnList) { if (!((Object)(object)val == (Object)null)) { SummonType summonType = Summons.SpeciesOf(((Object)val).name); if (summonType == null || !IsAtCap(summonType)) { list.Add(val); } } } if (list.Count <= 0 || list.Count >= spawnList.Length) { return spawnList; } return list.ToArray(); } private static List<string> Steps() { List<string> list = new List<string>(); string[] array = Order.Value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0) { if (!string.Equals(text, "Random", StringComparison.OrdinalIgnoreCase) && Summons.Named(text) == null) { Plugin.Log.LogWarning((object)("Pick order entry '" + text + "' is not Random, Bear, Moose, Boar or Wolf; ignored")); } else { list.Add(text); } } } return list; } } [HarmonyPatch(typeof(SpawnAbility), "Setup")] internal static class SpawnAbilitySetupPatch { private static void Prefix(SpawnAbility __instance, Character owner, ItemData item) { if (!Picker.Enabled || (Object)(object)owner == (Object)null || (Object)(object)owner != (Object)(object)Player.m_localPlayer || !Picker.IsSpiritCaller(item) || __instance.m_spawnPrefab == null) { return; } SummonType summonType = Picker.CurrentType(); if (summonType == null) { if (Picker.SkipFull.Value) { __instance.m_spawnPrefab = Picker.WithRoom(__instance.m_spawnPrefab); } return; } GameObject[] spawnPrefab = __instance.m_spawnPrefab; foreach (GameObject val in spawnPrefab) { if (!((Object)(object)val == (Object)null) && !(((Object)val).name != summonType.PrefabName)) { __instance.m_spawnPrefab = (GameObject[])(object)new GameObject[1] { val }; return; } } Plugin.Log.LogWarning((object)(summonType.PrefabName + " is not in the staff's spawn list; this cast stays random")); } } [HarmonyPatch(typeof(Player), "SetControls")] internal static class PlayerSetControlsPatch { private static void Postfix(Player __instance, bool secondaryAttack) { if (secondaryAttack && Picker.Enabled && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Picker.IsSpiritCaller(((Humanoid)__instance).GetCurrentWeapon())) { Picker.Cycle(); } } } [BepInPlugin("Brruid.SpiritAnimism", "SpiritAnimism", "0.5.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "Brruid.SpiritAnimism"; public const string Name = "SpiritAnimism"; public const string Version = "0.5.0"; internal static ManualLogSource Log; internal static ConfigFile Settings; internal static ConfigEntry<KeyboardShortcut> DismissKey; private const float ConfigPollSeconds = 1f; private float _nextConfigPoll; private DateTime _configLastWrite; private void Awake() { //IL_001b: 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) Log = ((BaseUnityPlugin)this).Logger; Settings = ((BaseUnityPlugin)this).Config; new Harmony("Brruid.SpiritAnimism").PatchAll(); BindLooks(); DismissKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Dismiss", "Key", new KeyboardShortcut((KeyCode)120, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Dismisses all spirit summons you called, with the vanilla despawn effect."); Saddles.Init(((BaseUnityPlugin)this).Config); Formations.Init(((BaseUnityPlugin)this).Config); Picker.Init(((BaseUnityPlugin)this).Config); SummonPanel.Init(((BaseUnityPlugin)this).Config); _configLastWrite = File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath); Log.LogInfo((object)"SpiritAnimism 0.5.0 loaded"); } private void BindLooks() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown Color32 val = default(Color32); ((Color32)(ref val))..ctor((byte)64, (byte)200, byte.MaxValue, byte.MaxValue); SummonType[] types = Summons.Types; foreach (SummonType summonType in types) { bool flag = summonType == Summons.Types[0]; summonType.Look = ((BaseUnityPlugin)this).Config.Bind<Look>(summonType.Name, "Look", Look.Spirit, flag ? "Spirit = the vanilla translucent ghost in your tint. Natural = the wild animal's own opaque body with a glow in your tint. Every animal's section takes the same settings." : ""); summonType.Tint = ((BaseUnityPlugin)this).Config.Bind<Color>(summonType.Name, "Tint", Color32.op_Implicit(val), flag ? "Body colour of the Spirit look, glow colour of the Natural look. Hex RRGGBBAA; alpha is ignored." : ""); summonType.Glow = ((BaseUnityPlugin)this).Config.Bind<float>(summonType.Name, "Glow", 0.3f, new ConfigDescription(flag ? "Body glow strength of the Natural look. 0 = plain wild animal." : "", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); if (summonType.HasEyeMask) { summonType.EyeGlow = ((BaseUnityPlugin)this).Config.Bind<float>(summonType.Name, "EyeGlow", 0f, new ConfigDescription("Eye glow strength of the Natural look, drawn from the moose's own eye mask. Combine with Glow: body only, eyes only, or both at their own strengths.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); } } } private void Update() { //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) SummonLooks.Update(); SummonPanel.Update(); KeyboardShortcut value = DismissKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && Dismiss.InputIsFree()) { Dismiss.MySummons(); } Saddles.Update(); Formations.Update(); ReloadConfigIfEdited(); } private void ReloadConfigIfEdited() { if (Time.unscaledTime < _nextConfigPoll) { return; } _nextConfigPoll = Time.unscaledTime + 1f; string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (!File.Exists(configFilePath)) { ((BaseUnityPlugin)this).Config.Save(); _configLastWrite = File.GetLastWriteTimeUtc(configFilePath); Log.LogInfo((object)"Config file recreated with the current settings"); } else if (!(File.GetLastWriteTimeUtc(configFilePath) == _configLastWrite)) { try { ((BaseUnityPlugin)this).Config.Reload(); } catch (IOException ex) { Log.LogWarning((object)("Config not reloaded yet: " + ex.Message)); return; } _configLastWrite = File.GetLastWriteTimeUtc(configFilePath); Log.LogInfo((object)"Config reloaded"); } } } [HarmonyPatch(typeof(ConfigFile), "Save")] internal static class ConfigFileSavePatch { private static void Postfix(ConfigFile __instance) { if (__instance != Plugin.Settings) { return; } List<string> list = new List<string>(); foreach (ConfigDefinition key in __instance.Keys) { if (!list.Contains(key.Section)) { list.Add(key.Section); } } List<string> list2 = new List<string>(); Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(); List<string> value = list2; string[] array = File.ReadAllLines(__instance.ConfigFilePath); foreach (string text in array) { string text2 = text.Trim(); if (text2.StartsWith("[") && text2.EndsWith("]")) { string text3 = text2.Substring(1, text2.Length - 2); if (!dictionary.TryGetValue(text3, out value)) { value = (dictionary[text3] = new List<string>()); } if (!list.Contains(text3)) { list.Add(text3); } } value.Add(text); } List<string> list4 = new List<string>(list2); foreach (string item in list) { if (dictionary.TryGetValue(item, out var value2)) { list4.AddRange(value2); } } File.WriteAllLines(__instance.ConfigFilePath, list4, Utility.UTF8NoBom); } } internal static class Saddles { private sealed class Pending { public long Id; public string PrefabName; public Vector3 Position; public Queue<string> Recipients; public float Deadline; } [HarmonyPatch(typeof(Tameable), "RPC_AddSaddle")] private static class AddSaddlePatch { private static void Prefix(Tameable __instance, ZNetView ___m_nview, out bool __state) { __state = ___m_nview.IsValid() && HasSaddle(__instance, ___m_nview); } private static void Postfix(Tameable __instance, ZNetView ___m_nview, long sender, bool __state) { if (!__state && ___m_nview.IsValid() && ___m_nview.IsOwner() && Summons.SpeciesOf(((Object)((Component)__instance).gameObject).name) != null && HasSaddle(__instance, ___m_nview)) { string text = SenderName(sender); ___m_nview.GetZDO().Set("SpiritAnimism.Fitter", text); Plugin.Log.LogInfo((object)("Saddle fitted by " + ((text == "") ? "an unknown player" : text))); } } } [HarmonyPatch(typeof(Tameable), "RPC_UnSummon")] private static class UnSummonPatch { private static void Prefix(Tameable __instance, ZNetView ___m_nview) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (ReturnSaddle.Value && !((Object)(object)___m_nview == (Object)null) && ___m_nview.IsValid() && ___m_nview.IsOwner() && Summons.SpeciesOf(((Object)((Component)__instance).gameObject).name) != null && HasSaddle(__instance, ___m_nview)) { ZDO zDO = ___m_nview.GetZDO(); Return(((Object)((Component)__instance.m_saddleItem).gameObject).name, ((Component)__instance).transform.position, zDO.GetString("SpiritAnimism.Fitter", ""), zDO.GetString(ZDOVars.s_follow, "")); } } } private const string FitterKey = "SpiritAnimism.Fitter"; private const string TakeRpc = "SpiritAnimism_TakeSaddle"; private const string TakenRpc = "SpiritAnimism_SaddleTaken"; private const float ReplySeconds = 2f; internal static ConfigEntry<bool> ReturnSaddle; internal static ConfigEntry<bool> DismissWhileRiding; private static readonly List<Pending> _pending = new List<Pending>(); private static ZRoutedRpc _registeredOn; private static long _nextId = 1L; public static void Init(ConfigFile config) { ReturnSaddle = config.Bind<bool>("Dismiss", "ReturnSaddle", true, "A saddle on a dismissed or unsummoned animal goes back to the player who fitted it, failing that to the summoner, failing that it drops where the animal stood. Off = the saddle is lost, as in the unmodded game."); DismissWhileRiding = config.Bind<bool>("Dismiss", "DismissWhileRiding", true, "Whether Dismiss also removes the animal you are riding. Off = your mount stays and the others go."); } public static void Update() { RegisterRpcs(); if (_pending.Count == 0) { return; } for (int num = _pending.Count - 1; num >= 0; num--) { if (Time.unscaledTime >= _pending[num].Deadline) { Advance(_pending[num]); } } } private static void RegisterRpcs() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && instance != _registeredOn) { instance.Register<string, string, long>("SpiritAnimism_TakeSaddle", (Action<long, string, string, long>)OnTakeSaddle); instance.Register<long>("SpiritAnimism_SaddleTaken", (Action<long, long>)OnSaddleTaken); _registeredOn = instance; _pending.Clear(); } } public static void Return(string prefabName, Vector3 position, string fitter, string summoner) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) Queue<string> queue = new Queue<string>(); if (!string.IsNullOrEmpty(fitter)) { queue.Enqueue(fitter); } if (!string.IsNullOrEmpty(summoner) && summoner != fitter) { queue.Enqueue(summoner); } Pending pending = new Pending { Id = _nextId++, PrefabName = prefabName, Position = position, Recipients = queue }; _pending.Add(pending); Advance(pending); } private static void Advance(Pending pending) { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) while (pending.Recipients.Count > 0) { string text = pending.Recipients.Dequeue(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && localPlayer.GetPlayerName() == text) { Take(localPlayer, pending.PrefabName); _pending.Remove(pending); return; } if (IsConnected(text)) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SpiritAnimism_TakeSaddle", new object[3] { text, pending.PrefabName, pending.Id }); pending.Deadline = Time.unscaledTime + 2f; Plugin.Log.LogInfo((object)("Asked " + text + " to take a " + pending.PrefabName)); return; } } Drop(pending.PrefabName, pending.Position); _pending.Remove(pending); } private static void OnTakeSaddle(long sender, string recipient, string prefabName, long id) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !(localPlayer.GetPlayerName() != recipient)) { Take(localPlayer, prefabName); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SpiritAnimism_SaddleTaken", new object[1] { id }); } } private static void OnSaddleTaken(long sender, long id) { if (_pending.RemoveAll((Pending p) => p.Id == id) > 0) { Plugin.Log.LogInfo((object)"Saddle taken by its recipient"); } } private static void Take(Player player, string prefabName) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_004b: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)("Unknown saddle prefab " + prefabName)); return; } GameObject val = Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position + Vector3.up * 0.5f, Quaternion.identity); ((Humanoid)player).Pickup(val, false, false); } private static void Drop(string prefabName, Vector3 position) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)("Unknown saddle prefab " + prefabName)); return; } Rigidbody component = Object.Instantiate<GameObject>(prefab, position + Vector3.up, Quaternion.identity).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.AddForce(Vector3.up * 5f, (ForceMode)2); } Plugin.Log.LogInfo((object)("Dropped a " + prefabName + " where the summon stood")); } private static bool IsConnected(string playerName) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null) { return false; } foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { if (player.m_name == playerName) { return true; } } return false; } private static string SenderName(long sender) { //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_0053: 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_0059: 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) if (sender == ZNet.GetUID()) { if (!((Object)(object)Player.m_localPlayer != (Object)null)) { return ""; } return Player.m_localPlayer.GetPlayerName(); } if ((Object)(object)ZNet.instance == (Object)null) { return ""; } foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { ZDOID characterID = player.m_characterID; if (((ZDOID)(ref characterID)).UserID == sender) { return player.m_name; } } return ""; } public static bool HasSaddle(Tameable tameable, ZNetView view) { if ((Object)(object)tameable.m_saddle != (Object)null && (Object)(object)tameable.m_saddleItem != (Object)null) { return view.GetZDO().GetBool(ZDOVars.s_haveSaddleHash, false); } return false; } public static bool IsRiding(Player player, Summon summon) { IDoodadController doodadController = player.GetDoodadController(); Sadle val = (Sadle)(object)((doodadController is Sadle) ? doodadController : null); if ((Object)(object)val == (Object)null) { return false; } Tameable component = ((Component)summon.Character).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null) { return (Object)(object)component.m_saddle == (Object)(object)val; } return false; } } internal struct LookSpec { public const float MaxGlow = 5f; private const string Version = "2"; public Look Look; public Color Tint; public float Glow; public float EyeGlow; public static LookSpec FromConfig(SummonType type) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) return new LookSpec { Look = type.Look.Value, Tint = type.Tint.Value, Glow = type.Glow.Value, EyeGlow = ((type.EyeGlow != null) ? type.EyeGlow.Value : 0f) }; } public string Serialize() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) return string.Format("{0};{1};{2};{3};{4}", "2", Look, ColorUtility.ToHtmlStringRGB(Tint), Strength(Glow), Strength(EyeGlow)); } private static string Strength(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } public static bool TryParse(string text, out LookSpec spec) { spec = default(LookSpec); if (string.IsNullOrEmpty(text)) { return false; } string[] array = text.Split(new char[1] { ';' }); if (array.Length != 5 || array[0] != "2") { return false; } if (!Enum.TryParse<Look>(array[1], out spec.Look) || !Enum.IsDefined(typeof(Look), spec.Look)) { return false; } if (!ColorUtility.TryParseHtmlString("#" + array[2], ref spec.Tint)) { return false; } if (TryParseStrength(array[3], out spec.Glow)) { return TryParseStrength(array[4], out spec.EyeGlow); } return false; } private static bool TryParseStrength(string text, out float value) { if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { return false; } if (float.IsNaN(value) || float.IsInfinity(value)) { return false; } value = Mathf.Clamp(value, 0f, 5f); return true; } } internal static class SummonLooks { internal static readonly int TintColorId = Shader.PropertyToID("_TintColor"); internal static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor"); internal static readonly int EmissionMapId = Shader.PropertyToID("_EmissionMap"); private static readonly int MainTexId = Shader.PropertyToID("_MainTex"); internal static readonly int LookKey = StringExtensionMethods.GetStableHashCode("SpiritAnimism.Look"); private const float RefreshSeconds = 0.25f; private static float _nextRefresh; public static void Update() { if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.25f; if ((Object)(object)ZNetScene.instance == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; string playerName = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetPlayerName() : null); foreach (Summon item in Summons.Standing()) { if (!LookUpAssets(item.Species)) { continue; } ZDO zdo = item.Zdo; string text = zdo.GetString(LookKey, ""); LookSpec? spec; string text2; LookSpec spec2; if (item.CalledBy(playerName)) { LookSpec value = LookSpec.FromConfig(item.Species); spec = value; text2 = value.Serialize(); if (item.View.IsOwner() && text != text2) { zdo.Set(LookKey, text2); } } else if (LookSpec.TryParse(text, out spec2)) { spec = spec2; text2 = text; } else { spec = null; text2 = "vanilla"; } (((Component)item.Character).GetComponent<SummonLook>() ?? ((Component)item.Character).gameObject.AddComponent<SummonLook>()).Apply(item.Species, spec, text2); } } private static bool LookUpAssets(SummonType species) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: 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) if (species.AssetsLookedUp) { return (Object)(object)species.SpiritMaterial != (Object)null; } species.AssetsLookedUp = true; GameObject prefab = ZNetScene.instance.GetPrefab(species.PrefabName); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)("Prefab " + species.PrefabName + " not found")); return false; } Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; foreach (Material val in sharedMaterials) { if (!((Object)(object)val == (Object)null) && val.HasProperty(TintColorId) && species.OwnsMaterial(val)) { species.SpiritMaterial = val; species.VanillaTint = val.GetColor(TintColorId); break; } } if ((Object)(object)species.SpiritMaterial != (Object)null) { break; } } if ((Object)(object)species.SpiritMaterial == (Object)null) { Plugin.Log.LogWarning((object)("No spirit body material on " + species.PrefabName)); return false; } GameObject prefab2 = ZNetScene.instance.GetPrefab(species.WildPrefabName); Texture texture = species.SpiritMaterial.GetTexture(MainTexId); string text = (((Object)(object)texture != (Object)null) ? ((Object)texture).name : null); if ((Object)(object)prefab2 != (Object)null) { componentsInChildren = prefab2.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null) && !val2.HasProperty(TintColorId) && val2.HasProperty(MainTexId)) { Texture texture2 = val2.GetTexture(MainTexId); if (!((Object)(object)texture2 == (Object)null) && !(((Object)texture2).name != text)) { species.WildMaterial = val2; species.VanillaEmissionMap = (val2.HasProperty(EmissionMapId) ? val2.GetTexture(EmissionMapId) : null); species.VanillaEmissionColor = val2.GetColor(EmissionColorId); break; } } } if ((Object)(object)species.WildMaterial != (Object)null) { break; } } } if ((Object)(object)species.WildMaterial == (Object)null) { Plugin.Log.LogWarning((object)("No wild body material for " + species.Name + "; its Natural look falls back to Spirit")); } Plugin.Log.LogInfo((object)(species.Name + ": spirit material " + ((Object)species.SpiritMaterial).name + ", wild material " + (((Object)(object)species.WildMaterial != (Object)null) ? ((Object)species.WildMaterial).name : "none"))); return true; } public static Color MatchIntensity(Color tint, Color original) { //IL_0008: 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_001a: 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_0038: 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_0061: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(new float[3] { original.r, original.g, original.b }); float num2 = Mathf.Max(new float[3] { tint.r, tint.g, tint.b }); float num3 = ((num2 > 0f) ? (num / num2) : 1f); return new Color(tint.r * num3, tint.g * num3, tint.b * num3, original.a); } } internal sealed class SummonLook : MonoBehaviour { private struct BodySlot { public Renderer Renderer; public int Index; public Material Vanilla; } public const string VanillaKey = "vanilla"; private SummonType _species; private readonly List<BodySlot> _slots = new List<BodySlot>(); private string _applied; private Material _spirit; private Material _natural; private Texture2D _mixedGlow; private float _mixedBody; private float _mixedEyes; public void Apply(SummonType species, LookSpec? spec, string key) { if (key == _applied) { return; } if (_species == null) { _species = species; FindBodySlots(); } _applied = key; foreach (BodySlot slot in _slots) { if ((Object)(object)slot.Renderer == (Object)null) { continue; } Material[] sharedMaterials = slot.Renderer.sharedMaterials; if (slot.Index < sharedMaterials.Length) { Material val = (spec.HasValue ? Styled(spec.Value, slot.Vanilla) : slot.Vanilla); if (!((Object)(object)sharedMaterials[slot.Index] == (Object)(object)val)) { sharedMaterials[slot.Index] = val; slot.Renderer.sharedMaterials = sharedMaterials; } } } } private void FindBodySlots() { string name = ((Object)_species.SpiritMaterial).name; Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null) && ((Object)sharedMaterials[j]).name.StartsWith(name, StringComparison.Ordinal)) { _slots.Add(new BodySlot { Renderer = val, Index = j, Vanilla = sharedMaterials[j] }); } } } if (_slots.Count == 0) { Plugin.Log.LogWarning((object)(_species.Name + " summon " + ((Object)this).name + " has no body material slot; it stays vanilla")); } } private Material Styled(LookSpec spec, Material vanilla) { //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Expected O, but got Unknown //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_0066: Expected O, but got Unknown //IL_0116: 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_012c: 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_0141: 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) if (spec.Look == Look.Natural && (Object)(object)_species.WildMaterial != (Object)null) { if ((Object)(object)_natural == (Object)null) { _natural = new Material(_species.WildMaterial) { name = ((Object)_species.WildMaterial).name + "_spiritanimism" }; _natural.EnableKeyword("_EMISSION"); } float glow = spec.Glow; float num = (((Object)(object)_species.VanillaEmissionMap != (Object)null) ? spec.EyeGlow : 0f); if (glow <= 0f && num <= 0f) { _natural.SetTexture(SummonLooks.EmissionMapId, _species.VanillaEmissionMap); _natural.SetColor(SummonLooks.EmissionColorId, _species.VanillaEmissionColor); } else { float num2 = Mathf.Max(glow, num); _natural.SetTexture(SummonLooks.EmissionMapId, GlowMap(glow / num2, num / num2)); _natural.SetColor(SummonLooks.EmissionColorId, new Color(spec.Tint.r, spec.Tint.g, spec.Tint.b, 1f) * num2); } return _natural; } if ((Object)(object)_spirit == (Object)null) { _spirit = new Material(vanilla) { name = ((Object)_species.SpiritMaterial).name + "_spiritanimism" }; } _spirit.SetColor(SummonLooks.TintColorId, SummonLooks.MatchIntensity(spec.Tint, _species.VanillaTint)); return _spirit; } private Texture GlowMap(float body, float eyes) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014a: 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_015b: Expected O, but got Unknown if (eyes <= 0f) { return (Texture)(object)Texture2D.whiteTexture; } if (body <= 0f) { return _species.VanillaEmissionMap; } if ((Object)(object)_mixedGlow != (Object)null && body == _mixedBody && eyes == _mixedEyes) { return (Texture)(object)_mixedGlow; } Texture vanillaEmissionMap = _species.VanillaEmissionMap; if ((Object)(object)_species.ReadableEyeMask == (Object)null) { _species.ReadableEyeMask = Textures.ReadableCopy(vanillaEmissionMap); } Color32[] pixels = _species.ReadableEyeMask.GetPixels32(); for (int i = 0; i < pixels.Length; i++) { float num = (float)Mathf.Max(new int[3] { pixels[i].r, pixels[i].g, pixels[i].b }) / 255f * eyes; byte b = (byte)Mathf.RoundToInt(255f * Mathf.Max(num, body)); pixels[i] = new Color32(b, b, b, byte.MaxValue); } if ((Object)(object)_mixedGlow == (Object)null) { _mixedGlow = new Texture2D(vanillaEmissionMap.width, vanillaEmissionMap.height, (TextureFormat)4, true) { name = ((Object)vanillaEmissionMap).name + "_spiritanimism", wrapMode = vanillaEmissionMap.wrapMode, filterMode = vanillaEmissionMap.filterMode }; } _mixedGlow.SetPixels32(pixels); _mixedGlow.Apply(); _mixedBody = body; _mixedEyes = eyes; return (Texture)(object)_mixedGlow; } private void OnDestroy() { if ((Object)(object)_spirit != (Object)null) { Object.Destroy((Object)(object)_spirit); } if ((Object)(object)_natural != (Object)null) { Object.Destroy((Object)(object)_natural); } if ((Object)(object)_mixedGlow != (Object)null) { Object.Destroy((Object)(object)_mixedGlow); } } } internal static class Textures { public static Texture2D ReadableCopy(Texture source) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0); RenderTexture active = RenderTexture.active; try { Graphics.Blit(source, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(source.width, source.height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0); val.Apply(); return val; } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); } } } internal static class SummonPanel { private sealed class Row { public GameObject Root; public TMP_Text Text; public RectTransform Fill; } internal static ConfigEntry<bool> Show; internal static ConfigEntry<float> OffsetX; internal static ConfigEntry<float> OffsetY; internal static ConfigEntry<float> Scale; private const float RefreshSeconds = 0.25f; private const float RowHeight = 32f; private const float RowIndent = 32f; private const float BarWidth = 160f; private const float BarHeight = 6f; private const string PreferredFont = "Valheim-AveriaSansLibre"; private static readonly Color HeaderColor = new Color(0.94f, 0.76f, 0.35f); private static readonly Color NameColor = new Color(0.9f, 0.9f, 0.9f); private static readonly Color ActivityColor = new Color(0.65f, 0.65f, 0.65f); private static readonly Color BarBackground = new Color(0f, 0f, 0f, 0.5f); private static readonly Color BarFill = new Color(0.4f, 0.8f, 0.25f); private static GameObject _root; private static TMP_Text _header; private static TMP_FontAsset _font; private static Material _fontMaterial; private static bool _fontMissing; private static readonly List<Row> Rows = new List<Row>(); private static float _nextRefresh; public static void Init(ConfigFile config) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown Show = config.Bind<bool>("Panel", "Show", true, "Show the list of your standing summons at the top left."); OffsetX = config.Bind<float>("Panel", "OffsetX", 20f, "Distance from the left edge of the screen."); OffsetY = config.Bind<float>("Panel", "OffsetY", 220f, "Distance from the top edge of the screen."); Scale = config.Bind<float>("Panel", "Scale", 1f, new ConfigDescription("Size of the panel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f), Array.Empty<object>())); } public static void Update() { //IL_00be: 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_00d9: 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_00f2: 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_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.25f; Player localPlayer = Player.m_localPlayer; if ((Object)(object)Hud.instance == (Object)null || (Object)(object)localPlayer == (Object)null) { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } } else { if ((Object)(object)_root == (Object)null && !Build()) { return; } List<Summon> list = new List<Summon>(Summons.Mine()); bool flag = Show.Value && Hud.instance.IsVisible() && (list.Count > 0 || Picker.IsSpiritCaller(((Humanoid)localPlayer).GetCurrentWeapon())); _root.SetActive(flag); if (!flag) { return; } RectTransform val = (RectTransform)_root.transform; val.anchoredPosition = new Vector2(OffsetX.Value, 0f - OffsetY.Value); ((Transform)val).localScale = Vector3.one * Scale.Value; _header.text = $"SPIRITS [{list.Count}] <color=#{ColorUtility.ToHtmlStringRGB(HeaderColor)}>> {Picker.DisplayName(Picker.CurrentType())}</color>"; while (Rows.Count < list.Count) { Rows.Add(BuildRow(Rows.Count)); } for (int i = 0; i < Rows.Count; i++) { Row row = Rows[i]; if (i >= list.Count) { row.Root.SetActive(false); continue; } Summon summon = list[i]; row.Root.SetActive(true); row.Text.text = Picker.DisplayName(summon.Species) + " <color=#" + ColorUtility.ToHtmlStringRGB(ActivityColor) + ">" + Activity(summon.Character) + "</color>"; row.Fill.sizeDelta = new Vector2(160f * Mathf.Clamp01(summon.Character.GetHealthPercentage()), 6f); } } } private static string Activity(Character character) { MonsterAI component = ((Component)character).GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null) { return ""; } if ((Object)(object)((BaseAI)component).GetTargetCreature() != (Object)null) { return "Fighting"; } if (((BaseAI)component).IsAlerted()) { return "Alert"; } if ((Object)(object)component.GetFollowTarget() != (Object)null) { return "Following"; } return "Idle"; } private static bool Build() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0065: 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_006b: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (_fontMissing || !PickFont()) { return false; } Rows.Clear(); _root = new GameObject("SpiritAnimismPanel", new Type[1] { typeof(RectTransform) }); _root.transform.SetParent(Hud.instance.m_rootObject.transform, false); RectTransform val = (RectTransform)_root.transform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f, 1f); val.pivot = val2; Vector2 anchorMin = (val.anchorMax = val2); val.anchorMin = anchorMin; val.sizeDelta = new Vector2(160f, 32f); _header = MakeText(_root.transform, "Header", 14f, NameColor, (FontStyles)1); ((RectTransform)_header.transform).anchoredPosition = Vector2.zero; return true; } private static bool PickFont() { TMP_FontAsset val = null; TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); foreach (TMP_FontAsset val2 in array) { if (!(((Object)val2).name != "Valheim-AveriaSansLibre")) { val = val2; break; } } if ((Object)(object)val == (Object)null) { val = TMP_Settings.defaultFontAsset; } if ((Object)(object)val == (Object)null) { TMP_Text componentInChildren = Hud.instance.m_rootObject.GetComponentInChildren<TMP_Text>(true); if ((Object)(object)componentInChildren != (Object)null) { val = componentInChildren.font; } } if ((Object)(object)val == (Object)null) { _fontMissing = true; Plugin.Log.LogWarning((object)"No font found for the summon panel; it stays off this session"); return false; } _font = val; _fontMaterial = ((TMP_Asset)val).material; Plugin.Log.LogInfo((object)("Summon panel font: " + ((Object)val).name)); return true; } private static Row BuildRow(int index) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_009c: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) Row row = new Row(); row.Root = new GameObject($"Row{index}", new Type[1] { typeof(RectTransform) }); row.Root.transform.SetParent(_root.transform, false); RectTransform val = (RectTransform)row.Root.transform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f, 1f); val.pivot = val2; Vector2 anchorMin = (val.anchorMax = val2); val.anchorMin = anchorMin; val.anchoredPosition = new Vector2(32f, -32f * ((float)index + 0.7f)); val.sizeDelta = new Vector2(160f, 32f); row.Text = MakeText(row.Root.transform, "Text", 13f, NameColor, (FontStyles)0); ((RectTransform)row.Text.transform).anchoredPosition = Vector2.zero; RectTransform val4 = MakeImage(row.Root.transform, "Bar", BarBackground, new Vector2(160f, 6f)); val4.anchoredPosition = new Vector2(0f, -20f); row.Fill = MakeImage((Transform)(object)val4, "Fill", BarFill, new Vector2(160f, 6f)); row.Fill.anchoredPosition = Vector2.zero; return row; } private static TMP_Text MakeText(Transform parent, string name, float size, Color color, FontStyles style) { //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_0026: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform val2 = (RectTransform)val.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 1f); val2.pivot = val3; Vector2 anchorMin = (val2.anchorMax = val3); val2.anchorMin = anchorMin; val2.sizeDelta = new Vector2(400f, 20f); TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).font = _font; ((TMP_Text)obj).fontSharedMaterial = _fontMaterial; ((TMP_Text)obj).fontSize = size; ((Graphic)obj).color = color; ((TMP_Text)obj).fontStyle = style; ((TMP_Text)obj).richText = true; ((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0; ((Graphic)obj).raycastTarget = false; return (TMP_Text)(object)obj; } private static RectTransform MakeImage(Transform parent, string name, Color color, Vector2 size) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform val2 = (RectTransform)val.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 1f); val2.pivot = val3; Vector2 anchorMin = (val2.anchorMax = val3); val2.anchorMin = anchorMin; val2.sizeDelta = size; Image obj = val.AddComponent<Image>(); ((Graphic)obj).color = color; ((Graphic)obj).raycastTarget = false; return val2; } } internal enum Look { Spirit, Natural } internal sealed class SummonType { public readonly string Name; public readonly string PrefabName; public readonly string WildPrefabName; public readonly bool HasEyeMask; public ConfigEntry<Look> Look; public ConfigEntry<Color> Tint; public ConfigEntry<float> Glow; public ConfigEntry<float> EyeGlow; public Material SpiritMaterial; public Color VanillaTint; public Material WildMaterial; public Texture VanillaEmissionMap; public Color VanillaEmissionColor; public Texture2D ReadableEyeMask; public bool AssetsLookedUp; public SummonType(string name, string wildPrefabName, bool hasEyeMask = false) { Name = name; WildPrefabName = wildPrefabName; PrefabName = wildPrefabName + "_spiritcaller"; HasEyeMask = hasEyeMask; } public bool OwnsMaterial(Material material) { return ((Object)material).name.StartsWith(WildPrefabName + "_", StringComparison.OrdinalIgnoreCase); } } internal readonly struct Summon { public readonly Character Character; public readonly SummonType Species; public readonly ZNetView View; public ZDO Zdo => View.GetZDO(); public Summon(Character character, SummonType species, ZNetView view) { Character = character; Species = species; View = view; } public bool CalledBy(string playerName) { return Zdo.GetString(ZDOVars.s_follow, "") == playerName; } } internal static class Summons { internal static readonly SummonType[] Types = new SummonType[4] { new SummonType("Bear", "Bjorn"), new SummonType("Boar", "Boar"), new SummonType("Moose", "Moose", hasEyeMask: true), new SummonType("Wolf", "Wolf") }; public static SummonType SpeciesOf(string objectName) { SummonType[] types = Types; foreach (SummonType summonType in types) { if (objectName.StartsWith(summonType.PrefabName, StringComparison.Ordinal)) { return summonType; } } return null; } public static SummonType Named(string name) { SummonType[] types = Types; foreach (SummonType summonType in types) { if (string.Equals(summonType.Name, name, StringComparison.OrdinalIgnoreCase)) { return summonType; } } return null; } public static IEnumerable<Summon> Standing() { foreach (Character allCharacter in Character.GetAllCharacters()) { if ((Object)(object)allCharacter == (Object)null) { continue; } SummonType summonType = SpeciesOf(((Object)((Component)allCharacter).gameObject).name); if (summonType != null) { ZNetView component = ((Component)allCharacter).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { yield return new Summon(allCharacter, summonType, component); } } } } public static IEnumerable<Summon> Mine() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { yield break; } string playerName = localPlayer.GetPlayerName(); foreach (Summon item in Standing()) { if (item.CalledBy(playerName)) { yield return item; } } } }