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 PenPosts v1.3.1
plugins/PenPosts.dll
Decompiled an hour ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PenPosts")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PenPosts")] [assembly: AssemblyTitle("PenPosts")] [assembly: AssemblyVersion("1.0.0.0")] namespace PenPosts; internal sealed class PenFill { internal sealed class Region { public int Id; public readonly List<int> Cells = new List<int>(); public bool Open; public bool Done; public bool Reached; public bool TooBig; public int Start = -1; public int EscapeCell = -1; } internal sealed class Gap { public readonly List<int> Edges = new List<int>(); public int Width; public float X; public float Z; public int PathIndex; public bool Plugged; } public readonly int Half; public readonly int Size; public readonly float MaxStep; private readonly float _radiusCells; private readonly int _maxCells; private readonly Func<int, int, float> _groundAt; private readonly Func<int, int, float, int, int, float, bool> _wall; private readonly float[] _ground; private readonly byte[] _edge; private readonly byte[] _owner; private readonly int[] _parent; private readonly Queue<int> _queue = new Queue<int>(); private readonly List<int> _starts = new List<int>(); private readonly HashSet<int> _plugs = new HashSet<int>(); private readonly HashSet<int> _trial = new HashSet<int>(); private int _startIndex; private Region _current; public readonly List<Region> Regions = new List<Region>(); public int Queries; public IEnumerable<int> Plugs => _plugs; public PenFill(int halfCells, float radiusCells, int maxCells, float maxStep, Func<int, int, float> groundAt, Func<int, int, float, int, int, float, bool> wall) { Half = Math.Max(2, halfCells); Size = Half * 2 + 1; _radiusCells = radiusCells; _maxCells = Math.Max(4, maxCells); MaxStep = maxStep; _groundAt = groundAt; _wall = wall; _ground = new float[Size * Size]; for (int i = 0; i < _ground.Length; i++) { _ground[i] = float.PositiveInfinity; } _edge = new byte[Size * Size * 2]; _owner = new byte[Size * Size]; _parent = new int[Size * Size]; } public int Index(int x, int z) { return z * Size + x; } public void Cell(int index, out int x, out int z) { x = index % Size; z = index / Size; } public bool InGrid(int x, int z) { if (x >= 0 && z >= 0 && x < Size) { return z < Size; } return false; } public void AddStart(int x, int z) { if (InGrid(x, z)) { _starts.Add(Index(x, z)); } } public float Ground(int x, int z) { int num = Index(x, z); if (float.IsPositiveInfinity(_ground[num])) { Queries++; _ground[num] = _groundAt(x, z); } return _ground[num]; } public byte OwnerOf(int x, int z) { if (!InGrid(x, z)) { return 0; } return _owner[Index(x, z)]; } public int EdgeKey(int ax, int az, int bx, int bz) { if (bx < ax || bz < az) { int num = ax; ax = bx; bx = num; int num2 = az; az = bz; bz = num2; } return Index(ax, az) * 2 + ((bz != az) ? 1 : 0); } public void EdgeCells(int key, out int ax, out int az, out int bx, out int bz) { Cell(key / 2, out ax, out az); bx = ax + ((key % 2 == 0) ? 1 : 0); bz = az + ((key % 2 == 1) ? 1 : 0); } public bool Passable(int ax, int az, int bx, int bz) { int num = EdgeKey(ax, az, bx, bz); if (_plugs.Contains(num) || _trial.Contains(num)) { return false; } byte b = _edge[num]; if (b != 0) { return b == 1; } float num2 = Ground(ax, az); float num3 = Ground(bx, bz); bool flag; if (float.IsNaN(num2) || float.IsNaN(num3) || Math.Abs(num2 - num3) > MaxStep) { flag = false; } else { Queries++; flag = !_wall(ax, az, num2, bx, bz, num3); } _edge[num] = (byte)(flag ? 1 : 2); return flag; } private bool TooFar(int x, int z) { float num = x - Half; float num2 = z - Half; return num * num + num2 * num2 > _radiusCells * _radiusCells; } public void Plug(IEnumerable<int> edges) { foreach (int edge in edges) { _plugs.Add(edge); } } public void Try(IEnumerable<int> edges) { _trial.Clear(); if (edges == null) { return; } foreach (int edge in edges) { _trial.Add(edge); } } public void Restart() { Array.Clear(_owner, 0, _owner.Length); Regions.Clear(); _queue.Clear(); _startIndex = 0; _current = null; } public bool Step(int budget) { int num = Queries + Math.Max(1, budget); int num2 = 0; while (Queries < num && num2++ < 40000) { if (_current == null) { if (_startIndex >= _starts.Count) { return true; } int num3 = _starts[_startIndex++]; Cell(num3, out var x, out var z); if (_owner[num3] == 0 && !float.IsNaN(Ground(x, z))) { if (Regions.Count >= 250) { return true; } _current = new Region { Id = Regions.Count + 1, Start = num3 }; Regions.Add(_current); _owner[num3] = (byte)_current.Id; _parent[num3] = -1; _current.Cells.Add(num3); _queue.Clear(); _queue.Enqueue(num3); } continue; } if (_queue.Count == 0) { _current.Done = true; _current = null; continue; } int num4 = _queue.Dequeue(); Cell(num4, out var x2, out var z2); for (int i = 0; i < 4; i++) { int num5 = x2 + i switch { 1 => -1, 0 => 1, _ => 0, }; int num6 = z2 + i switch { 3 => -1, 2 => 1, _ => 0, }; if (!InGrid(num5, num6)) { Escape(num4, reached: true); break; } int num7 = Index(num5, num6); if (_owner[num7] == _current.Id || !Passable(x2, z2, num5, num6)) { continue; } if (TooFar(num5, num6)) { Escape(num4, reached: true); break; } if (_owner[num7] != 0) { if (Regions[_owner[num7] - 1].Open) { Escape(-1, reached: false); break; } continue; } _owner[num7] = (byte)_current.Id; _parent[num7] = num4; _current.Cells.Add(num7); if (_current.Cells.Count > _maxCells) { _current.TooBig = true; Escape(-1, reached: false); break; } _queue.Enqueue(num7); } } return false; } private void Escape(int cell, bool reached) { if (_current != null) { _current.Open = true; _current.Done = true; _current.Reached = reached; _current.EscapeCell = cell; _queue.Clear(); _current = null; } } public List<int> PathOut(Region r) { List<int> list = new List<int>(); if (r == null || !r.Reached || r.EscapeCell < 0) { return list; } int num = r.EscapeCell; int num2 = 0; while (num >= 0 && num2++ < _parent.Length) { list.Add(num); if (num == r.Start) { break; } num = _parent[num]; } list.Reverse(); return list; } public List<Gap> GapsOnWayOut(Region r, int maxSide) { List<Gap> list = new List<Gap>(); List<int> list2 = PathOut(r); HashSet<int> hashSet = new HashSet<int>(); int num = -1; int num2 = -1; for (int i = 0; i + 1 < list2.Count; i++) { Cell(list2[i], out var x, out var z); Cell(list2[i + 1], out var x2, out var z2); int num3 = ((x2 == x) ? 1 : 0); int num4 = ((num3 != 0) ? 1 : 0); int num5 = ((num3 == 0) ? 1 : 0); int num6 = SideBlocked(x, z, x2, z2, num4, num5, maxSide); int num7 = ((num6 < 0) ? (-1) : SideBlocked(x, z, x2, z2, -num4, -num5, maxSide)); if (num6 < 0 || num7 < 0) { num = -1; continue; } int num8 = num6 + num7 - 1; if (num8 != num || num3 != num2) { num = num8; num2 = num3; Gap gap = new Gap { Width = num8, PathIndex = i }; for (int j = -(num7 - 1); j <= num6 - 1; j++) { gap.Edges.Add(EdgeKey(x + num4 * j, z + num5 * j, x2 + num4 * j, z2 + num5 * j)); } if (hashSet.Add(gap.Edges[0])) { float num9 = (float)(num6 - num7) * 0.5f; gap.X = (float)(x + x2) * 0.5f + (float)num4 * num9; gap.Z = (float)(z + z2) * 0.5f + (float)num5 * num9; list.Add(gap); } } } list.Sort((Gap a, Gap b) => (a.Width == b.Width) ? a.PathIndex.CompareTo(b.PathIndex) : a.Width.CompareTo(b.Width)); return list; } private int SideBlocked(int cx, int cz, int nx, int nz, int px, int pz, int max) { for (int i = 1; i <= max; i++) { int num = cx + px * i; int num2 = cz + pz * i; int num3 = nx + px * i; int num4 = nz + pz * i; if (!InGrid(num, num2) || !InGrid(num3, num4)) { return -1; } if (!Passable(num, num2, num3, num4)) { return i; } } return -1; } } internal sealed class PenSolver { public readonly PenFill Fill; private readonly Func<PenFill, PenFill.Region> _choose; public int PlugWidth = 1; public int MaxPlugs = 4; public int MaxTries = 6; public int GapSide = 8; private bool _trying; private List<PenFill.Gap> _tries; private int _tryIndex; private int _rounds; public readonly List<PenFill.Gap> Plugged = new List<PenFill.Gap>(); public PenFill.Region Closed; public PenFill.Gap Opening; public bool MaybeMore; public bool TooBig; public bool Finished; public int Looks = 1; public PenSolver(PenFill fill, Func<PenFill, PenFill.Region> choose) { Fill = fill; _choose = choose; } public bool Step(int budget) { if (Finished) { return true; } if (!Fill.Step(budget)) { return false; } Next(); return Finished; } private void Again(IEnumerable<int> trial) { Fill.Try(trial); Fill.Restart(); Looks++; } private void Next() { PenFill.Region region = _choose(Fill); if (!_trying) { if (region != null) { Closed = region; Finished = true; return; } Fill.Try(null); List<PenFill.Gap> list = new List<PenFill.Gap>(); HashSet<int> hashSet = new HashSet<int>(); int num = 0; foreach (PenFill.Region region2 in Fill.Regions) { if (region2.TooBig) { TooBig = true; } if (!region2.Reached || num >= 2) { continue; } num++; foreach (PenFill.Gap item in Fill.GapsOnWayOut(region2, GapSide)) { if (hashSet.Add(item.Edges[0])) { list.Add(item); } } } list.Sort((PenFill.Gap a, PenFill.Gap b) => (a.Width == b.Width) ? a.PathIndex.CompareTo(b.PathIndex) : a.Width.CompareTo(b.Width)); if (list.Count > MaxTries) { list.RemoveRange(MaxTries, list.Count - MaxTries); } if (list.Count == 0) { Finished = true; return; } _tries = list; _tryIndex = 0; _trying = true; Again(list[0].Edges); return; } PenFill.Gap gap = _tries[_tryIndex]; if (region != null) { Fill.Try(null); if (gap.Width <= PlugWidth) { gap.Plugged = true; Fill.Plug(gap.Edges); Plugged.Add(gap); Closed = region; } else { Opening = gap; } Finished = true; return; } _tryIndex++; if (_tryIndex < _tries.Count) { Again(_tries[_tryIndex].Edges); return; } PenFill.Gap gap2 = _tries[0]; if (gap2.Width <= PlugWidth && _rounds < MaxPlugs) { _rounds++; gap2.Plugged = true; Fill.Plug(gap2.Edges); Plugged.Add(gap2); _trying = false; Again(null); } else { Fill.Try(null); Opening = gap2; MaybeMore = true; Finished = true; } } } internal static class PenGuard { private sealed class Watch { public Character Animal; public Sign Sign; public Vector3 LastGood; public bool HaveGood; public bool Flying; public float Range; } private sealed class Footing { public Character Animal; public Vector3 Pos; } private delegate bool GetPatrolFn(BaseAI ai, out Vector3 point); private const float Every = 0.5f; private const float OutBy = 1.5f; private const float SunkBy = 1f; private const float FellBy = 4f; private const float Meant = 15f; private const float BirthReach = 3f; private static readonly Dictionary<int, Watch> s_watch = new Dictionary<int, Watch>(); private static readonly Dictionary<int, Footing> s_footing = new Dictionary<int, Footing>(); private static readonly Dictionary<int, float> s_rescued = new Dictionary<int, float>(); private const float RescueAgain = 60f; private static int s_floorMask; private static readonly List<int> s_gone = new List<int>(); private static int s_index; private static int s_told; private const float FarBack = 40f; private static GetPatrolFn s_getPatrol; private static Action<BaseAI, Vector3> s_setPatrol; private static bool s_patrolTried; internal static bool On { get { if (PenPostsPlugin.KeepIn != null) { return PenPostsPlugin.KeepIn.Value; } return false; } } internal static void Tick() { if (!On) { if (s_watch.Count > 0) { ReleaseAll(); s_watch.Clear(); } } else { if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } List<Character> allCharacters = Character.GetAllCharacters(); if (allCharacters.Count == 0) { return; } int num = Mathf.Clamp(Mathf.CeilToInt((float)allCharacters.Count * Time.deltaTime / 0.5f), 1, allCharacters.Count); for (int i = 0; i < num; i++) { if (s_index >= allCharacters.Count) { s_index = 0; Sweep(); } Character c = allCharacters[s_index++]; try { Check(c); } catch (Exception ex) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogDebug((object)("Keeping an animal in failed: " + ex.Message)); } } } } } private static void Sweep() { s_gone.Clear(); foreach (KeyValuePair<int, Watch> item in s_watch) { if ((Object)(object)item.Value.Animal == (Object)null || item.Value.Animal.IsDead()) { s_gone.Add(item.Key); } } foreach (int item2 in s_gone) { s_watch.Remove(item2); } s_gone.Clear(); foreach (KeyValuePair<int, Footing> item3 in s_footing) { if ((Object)(object)item3.Value.Animal == (Object)null || item3.Value.Animal.IsDead()) { s_gone.Add(item3.Key); } } foreach (int item4 in s_gone) { s_footing.Remove(item4); } s_gone.Clear(); foreach (KeyValuePair<int, float> item5 in s_rescued) { if (Time.time - item5.Value > 60f) { s_gone.Add(item5.Key); } } foreach (int item6 in s_gone) { s_rescued.Remove(item6); } } private static bool RescuedLately(int id) { if (s_rescued.TryGetValue(id, out var value)) { return Time.time - value < 60f; } return false; } private static void Check(Character c) { //IL_005e: 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_006f: 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_00e7: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)c == (Object)null || c.IsPlayer() || !c.IsTamed() || c.IsDead()) { return; } ZNetView component = ((Component)c).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return; } int instanceID = ((Object)c).GetInstanceID(); s_watch.TryGetValue(instanceID, out var value); Vector3 position = ((Component)c).transform.position; if (c.IsFlying()) { Leash(c, instanceID, value, position); return; } Vector3 to; string how; if (c.IsOnGround()) { if (!s_footing.TryGetValue(instanceID, out var value2) || (Object)(object)value2.Animal != (Object)(object)c) { Dictionary<int, Footing> dictionary = s_footing; Footing obj = new Footing { Animal = c }; value2 = obj; dictionary[instanceID] = obj; } value2.Pos = position; } else if (!RescuedLately(instanceID) && Lost(c, instanceID, position, out to, out how)) { s_rescued[instanceID] = Time.time; Move(c, to); Tell(c, how, position); return; } if (value != null && value.Flying) { Release(instanceID, value); value = null; } if (Free(c)) { if (value != null) { s_watch.Remove(instanceID); } return; } Pen pen = ((value != null && (Object)(object)value.Sign != (Object)null) ? Guarded(PenRegistry.ParseSign(value.Sign)) : null); if (value != null && pen == null) { s_watch.Remove(instanceID); value = null; } if (pen == null) { pen = Guarded(PenRegistry.FindPen(position)); if (pen == null) { if ((Object)(object)((Component)c).GetComponent<Growup>() != (Object)null) { BornOutside(c, instanceID, position); } return; } value = (s_watch[instanceID] = new Watch { Animal = c, Sign = pen.Sign }); } PenShape shape = pen.Shape; if (shape.Contains(position)) { if (shape.FloorAt(position, out var y) && position.y < y - 1f) { Move(c, new Vector3(position.x, y + 0.2f, position.z)); Tell(c, "was lifted back onto the pen's floor", position); } else if (c.IsOnGround()) { value.LastGood = position; value.HaveGood = true; } } else { if (shape.Near(position, 1.5f)) { return; } if (value.HaveGood && Flat(position - value.LastGood) > 15f) { s_watch.Remove(instanceID); return; } Vector3 to2; if (value.HaveGood && shape.Contains(value.LastGood)) { to2 = value.LastGood; } else { if (!shape.NearestInside(position, 8f, out var spot)) { s_watch.Remove(instanceID); return; } to2 = spot + Vector3.up * 0.2f; } Move(c, to2); Tell(c, "got out and was put back in its pen", position); } } private static bool Patrol() { if (!s_patrolTried) { s_patrolTried = true; try { s_getPatrol = AccessTools.MethodDelegate<GetPatrolFn>(AccessTools.Method(typeof(BaseAI), "GetPatrolPoint", new Type[1] { typeof(Vector3).MakeByRefType() }, (Type[])null), (object)null, true); s_setPatrol = AccessTools.MethodDelegate<Action<BaseAI, Vector3>>(AccessTools.Method(typeof(BaseAI), "SetPatrolPoint", new Type[1] { typeof(Vector3) }, (Type[])null), (object)null, true); } catch (Exception ex) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogWarning((object)("The flying leash can't set where animals wander: " + ex.Message)); } s_getPatrol = null; s_setPatrol = null; } } if (s_getPatrol != null) { return s_setPatrol != null; } return false; } private static Vector3 Middle(Pen pen, out float reach) { //IL_0074: 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) if (pen.Shape != null && PenShapes.Enabled && !pen.Forced) { reach = pen.Shape.Reach; return new Vector3(pen.Shape.Centroid.x, pen.Center.y, pen.Shape.Centroid.z); } reach = (pen.Square ? (pen.Radius * 1.42f) : pen.Radius); return pen.Center; } private static Pen PenUnder(Vector3 pos) { //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_0035: 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_0038: Unknown result type (might be due to invalid IL or missing references) Pen result = null; float num = float.MaxValue; foreach (Pen item in PenRegistry.Pens()) { if (!((Object)(object)item.Sign == (Object)null)) { float reach; Vector3 val = Middle(item, out reach); float num2 = Flat(pos - val); if (num2 <= reach && num2 < num) { result = item; num = num2; } } } return result; } private static void Leash(Character c, int id, Watch w, Vector3 pos) { //IL_00cd: 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_007a: 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_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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_0123: 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_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) float num = ((PenPostsPlugin.FlyingLeash != null) ? PenPostsPlugin.FlyingLeash.Value : 0f); BaseAI baseAI = c.GetBaseAI(); if (num <= 0f || (Object)(object)baseAI == (Object)null || Free(c) || !Patrol()) { Release(id, w); return; } Pen pen = ((w != null && w.Flying && (Object)(object)w.Sign != (Object)null) ? PenRegistry.ParseSign(w.Sign) : null); if (pen == null) { Release(id, w); pen = PenUnder(pos); if (pen == null) { return; } s_watch[id] = (w = new Watch { Animal = c, Sign = pen.Sign, Flying = true, Range = baseAI.m_randomMoveRange }); Tell(c, "is on a leash over its pen", pos); } float reach; Vector3 val = Middle(pen, out reach); float num2 = Mathf.Min(w.Range, Mathf.Max(2f, (reach + num) * 0.5f)); if (Mathf.Abs(baseAI.m_randomMoveRange - num2) > 0.01f) { baseAI.m_randomMoveRange = num2; } if (!s_getPatrol(baseAI, out var point) || Flat(point - val) > 1f) { s_setPatrol(baseAI, val); } if (Flat(pos - val) > reach + num + 40f && !baseAI.HaveTarget()) { Vector3 to = default(Vector3); ((Vector3)(ref to))..ctor(val.x, Mathf.Max(pos.y, val.y + 3f), val.z); Move(c, to); Tell(c, "flew too far and was brought back over its pen", pos); } } private static void Release(int id, Watch w) { if (w == null) { return; } if (w.Flying && (Object)(object)w.Animal != (Object)null) { BaseAI baseAI = w.Animal.GetBaseAI(); if ((Object)(object)baseAI != (Object)null && w.Range > 0f) { baseAI.m_randomMoveRange = w.Range; } } s_watch.Remove(id); } private static void ReleaseAll() { foreach (KeyValuePair<int, Watch> item in new List<KeyValuePair<int, Watch>>(s_watch)) { try { Release(item.Key, item.Value); } catch { } } } private static bool Lost(Character c, int id, Vector3 pos, out Vector3 to, out string how) { //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_0025: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) to = pos; how = null; if (c.InInterior() || c.IsSwimming() || c.IsAttachedToShip()) { return false; } if (Caves.Pending(pos)) { return false; } bool solid; bool flag = Caves.Sample(pos + Vector3.up, out solid); if (flag && !solid) { return false; } if (s_floorMask == 0) { s_floorMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" }); } if (Physics.Raycast(pos + Vector3.up * 0.5f, Vector3.down, 60f, s_floorMask, (QueryTriggerInteraction)1)) { return false; } Footing value; bool flag2 = s_footing.TryGetValue(id, out value) && (Object)(object)value.Animal == (Object)(object)c; if (flag2 && Flat(pos - value.Pos) > 15f) { s_footing.Remove(id); flag2 = false; } if (flag2 && pos.y < value.Pos.y - 4f) { to = value.Pos + Vector3.up * 0.2f; how = "fell through the floor or the ground and was put back where it last stood"; return true; } if (flag) { return false; } float num = 0f; if (!((Object)(object)ZoneSystem.instance != (Object)null) || !ZoneSystem.instance.GetGroundHeight(pos, ref num) || !(pos.y < num - 1f)) { return false; } if (flag2) { to = value.Pos + Vector3.up * 0.2f; how = "fell through the ground and was put back where it last stood"; return true; } to = new Vector3(pos.x, num + 0.5f, pos.z); how = "came up out of the ground"; return true; } private static void BornOutside(Character c, int id, Vector3 pos) { //IL_003b: 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_005e: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) foreach (Pen item in PenRegistry.Pens()) { Sign sign = item.Sign; Pen pen = Guarded(((Object)(object)sign != (Object)null) ? item : null); if (pen != null && pen.Shape.Near(pos, 3f) && pen.Shape.NearestInside(pos, 4f, out var spot)) { Move(c, spot + Vector3.up * 0.2f); s_watch[id] = new Watch { Animal = c, Sign = sign }; Tell(c, "was born outside the fence and was put in the pen", pos); break; } } } private static bool Free(Character c) { BaseAI baseAI = c.GetBaseAI(); MonsterAI val = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null); if (val != null && (Object)(object)val.GetFollowTarget() != (Object)null) { return true; } Tameable component = ((Component)c).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_saddle != (Object)null) { return component.m_saddle.HaveValidUser(); } return false; } private static Pen Guarded(Pen pen) { if (pen == null || pen.Shape == null || pen.Shape.Floor == null || !PenShapes.Enabled || pen.Forced) { return null; } return pen; } private static float Flat(Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) Vector2 val = new Vector2(v.x, v.z); return ((Vector2)(ref val)).magnitude; } private static void Move(Character c, Vector3 to) { //IL_0006: 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_0024: Unknown result type (might be due to invalid IL or missing references) ((Component)c).transform.position = to; Rigidbody component = ((Component)c).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.position = to; component.linearVelocity = Vector3.zero; } BaseAI baseAI = c.GetBaseAI(); if ((Object)(object)baseAI != (Object)null) { baseAI.StopMoving(); baseAI.ResetRandomMovement(); } } private static void Tell(Character c, string what, Vector3 from) { //IL_0054: 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_0070: Unknown result type (might be due to invalid IL or missing references) if (s_told >= 40) { return; } s_told++; string text = c.m_name; try { if (Localization.instance != null) { text = Localization.instance.Localize(text); } } catch { } ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogInfo((object)$"{text} {what} (it was at {from.x:0.0}, {from.y:0.0}, {from.z:0.0})."); } } } internal static class Caves { private delegate bool SampleFn(Vector3 pos, out bool solid); private delegate bool PendingFn(Vector3 pos); private static bool s_tried; private static SampleFn s_sample; private static PendingFn s_pending; private static void Resolve() { if (s_tried) { return; } s_tried = true; try { Type type = AccessTools.TypeByName("HearthBelow.VoxelMagic.VoxelWorld"); if (type == null) { return; } MethodInfo methodInfo = AccessTools.Method(type, "TrySampleSolid", new Type[2] { typeof(Vector3), typeof(bool).MakeByRefType() }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(type, "IsGroundPendingAt", new Type[1] { typeof(Vector3) }, (Type[])null); if (methodInfo != null) { s_sample = (SampleFn)Delegate.CreateDelegate(typeof(SampleFn), methodInfo); } if (methodInfo2 != null) { s_pending = (PendingFn)Delegate.CreateDelegate(typeof(PendingFn), methodInfo2); } if (s_sample != null) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogInfo((object)"Hearth Below found: tame animals in dug caves are left where they are."); } } } catch (Exception ex) { ManualLogSource log2 = PenPostsPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Hearth Below was found but its caves couldn't be read: " + ex.Message)); } s_sample = null; s_pending = null; } } internal static bool Sample(Vector3 pos, out bool solid) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) solid = false; Resolve(); if (s_sample == null) { return false; } try { return s_sample(pos, out solid); } catch { solid = false; return false; } } internal static bool Pending(Vector3 pos) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) Resolve(); if (s_pending == null) { return false; } try { return s_pending(pos); } catch { return false; } } } [BepInPlugin("anwo.PenPosts", "PenPosts", "1.3.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class PenPostsPlugin : BaseUnityPlugin { public const string Guid = "anwo.PenPosts"; public const string Name = "PenPosts"; public const string Version = "1.3.1"; internal static ConfigEntry<float> DefaultRadius; internal static ConfigEntry<float> MaxRadius; internal static ConfigEntry<int> DefaultCap; internal static ConfigEntry<bool> ShowPenHover; internal static ConfigEntry<bool> ShowAreaOnLook; internal static ConfigEntry<float> ShowAreaSeconds; internal static ConfigEntry<bool> NoFoodWhenFull; internal static ConfigEntry<bool> SmartArea; internal static ConfigEntry<float> MaxArea; internal static ConfigEntry<FallbackForm> FallbackShape; internal static ConfigEntry<bool> KeepIn; internal static ConfigEntry<float> FlyingLeash; internal static ConfigEntry<float> ButcherDamage; internal static ManualLogSource Log; private Harmony _harmony; private const float LookDelay = 0.4f; private Sign _lookSign; private float _lookSince; private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Expected O, but got Unknown //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Expected O, but got Unknown //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; DefaultRadius = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Pens", "Default radius", 10f, new ConfigDescription("Radius in metres for a pen sign that doesn't give one (\"Pen\" or \"Pen Boars\"); for a square pen it's half the side. Only used when there's no closed fence around the sign, or the sign says round or square.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>())); MaxRadius = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Pens", "Max radius", 40f, new ConfigDescription("Largest radius a pen sign may set (\"Pen 25\"). Also how far from the sign a fence is looked for.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>())); DefaultCap = ((BaseUnityPlugin)this).Config.Bind<int>("1 - Pens", "Pen cap", 0, new ConfigDescription("Breeding cap for pens whose sign doesn't set one. 0 = each animal's own cap (from LetMeTameYou or the game). Usually you set the cap on the sign instead: \"Pen 10 Boar 8\" makes boars in that pen stop breeding at 8 (10 is the pen's size in metres, only used when there's no closed fence, and can be left out). Other forms: \"Pen 10 Boar 8 Lox 4\" caps several kinds, \"Pen 10 cap 8\" caps every kind in the pen at 8. A kind the sign doesn't name uses the sign's cap for every kind if it has one, else this setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); SmartArea = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Pens", "Smart area", true, "A pen is the area inside the fence or walls around its sign, worked out from what's built there. Doors and gates count as shut, even when they're open, and gaps narrower than about 0.75 m are ignored. If there's no closed fence (a wider gap) or it encloses more than Max area, the pen uses the Fallback shape instead; the sign's hover text says why, the pen's marks are grey-blue instead of green, and an orange ring marks the gap. Write \"round\" or \"square\" on a sign to always use that shape."); MaxArea = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Pens", "Max area", 1600f, new ConfigDescription("Largest fenced area (square metres) taken as one pen. Anything bigger falls back to the Fallback shape.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(25f, 10000f), Array.Empty<object>())); FallbackShape = ((BaseUnityPlugin)this).Config.Bind<FallbackForm>("1 - Pens", "Fallback shape", FallbackForm.Round, "Shape of a pen with no closed fence around its sign (unless the sign says round or square). Round: a circle with the sign's radius. Square: a square around the sign, twice the radius wide, turned the way the sign faces."); KeepIn = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Pens", "Keep animals in", true, "Tame animals in a pen with a closed fence stay in it. One that gets out anyway (through a gap small enough to count as closed, a gate left open, or by slipping through a wall, a rock or the side of a cave) is put back where it last stood inside, and one that sinks into the pen's floor is lifted back onto it. A young one born or hatched on the wrong side of the fence is put inside. Animals that follow someone or carry a rider are free to go: to take one out, tell it to follow you. Flying animals (drakes) can't be held by a fence: they're on a leash instead (see Flying leash). A round or square pen without a closed fence has nothing to hold its animals in, so they're not held. Also, any tame animal (in or out of a pen) that falls through the ground or a floor into nothing is put back where it last stood, as the game already does for players. Animals in caves dug with Hearth Below, or standing on any floor under the ground, are left where they are. Each animal is looked after by the game that runs it, so it works in multiplayer when everyone has the mod. The first times it happens in a game are written to the log."); FlyingLeash = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Pens", "Flying leash", 10f, new ConfigDescription("A tame flying animal (a drake) over a pen is on a leash: it can fly over the pen and up to this many metres past its edge, and then turns back. It wanders around the middle of the pen instead of around wherever it happens to be, and it's never snatched back mid-flight; only one that ends up far away (40 m past the leash) when it isn't fighting is brought back over the pen. Works with any pen (fenced, round or square). Telling it to follow you, or riding it, takes it off the leash; when it stops following you over a pen it's leashed to that pen. 0 = flying animals aren't leashed. Needs Keep animals in.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); ShowPenHover = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "Show pen info on sign", true, "When you look at a pen sign, show its area, cap and how many tamed animals of each kind are inside."); NoFoodWhenFull = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Pens", "No food when full", true, "Tamed animals only eat when the food does them some good, so none is wasted: when they can still breed (their pen isn't at its cap, or outside pens, the game doesn't find them crowded), when a herd bell can still collect from them (the Herd Bell mod; not when their yield store is full), or when they wear a saddle or riding handle (food refills a mount's stamina). The rest leave food alone: animals in a full pen or crowded together, young ones still growing, and kinds that can't breed. They eat again as soon as that changes (a pen gets room, a bell is emptied). Wild animals you're taming eat as usual."); ShowAreaOnLook = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "Show pen area when looking at the sign", true, "Look at a pen sign for a moment to see the pen's area: marks on the ground along its fence or square (or a ring and a see-through ball for a round pen). Green marks: the pen is fine, a closed fence or the round or square shape the sign asks for. Grey-blue marks: the fence couldn't be used (an opening, too big, none found, or still being measured), so the pen is the Fallback shape for now. An orange ring marks the opening that keeps the fence from closing, and a small yellow ring a gap narrow enough to ignore. The marks change as soon as the pen does, so closing a gap turns them green while you watch. No key needed, so E, Shift+E and Q keep working on the sign as usual."); ShowAreaSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "Show pen area for", 20f, new ConfigDescription("Seconds the pen area stays visible after you look away from the sign.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 300f), Array.Empty<object>())); ButcherDamage = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Butcher knife", "Butcher knife damage", 100000f, new ConfigDescription("Damage of one hit with the Butcher knife. The knife only ever hurts tamed animals, so this changes nothing else. The game's own is 1000, enough for a plain boar or wolf but not for big or starred animals: a lox has 1000 health, a 1-star lox 2000 and a 2-star lox 3000, and tamed trolls and modded mounts have more. The default 100000 kills any tamed animal in one hit. 0 = leave the knife as the game made it. Changes right away (the damage on the knife's tooltip too). Each player's own setting is used for their own hits.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000000f), Array.Empty<object>())); ButcherDamage.SettingChanged += delegate { ButcherKnife.Apply(); }; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Config.SettingChanged += delegate(object s, SettingChangedEventArgs e) { if ((object)e.ChangedSetting == SmartArea || (object)e.ChangedSetting == MaxArea || (object)e.ChangedSetting == MaxRadius) { PenRegistry.ResetShapes(); } if ((object)e.ChangedSetting == FallbackShape) { PenArea.HideAll(); } }; _harmony = new Harmony("anwo.PenPosts"); try { _harmony.PatchAll(typeof(VanillaPatches)); LmtyPatch.TryPatch(_harmony); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("PenPosts failed to patch: " + ex)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"PenPosts 1.3.1 loaded."); } private void OnDestroy() { PenArea.HideAll(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { try { PenArea.Tick(); PenShapes.Tick(); PenGuard.Tick(); if (!ShowAreaOnLook.Value) { return; } Player localPlayer = Player.m_localPlayer; GameObject val = (((Object)(object)localPlayer != (Object)null && !IsTyping()) ? ((Humanoid)localPlayer).GetHoverObject() : null); Sign val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent<Sign>() : null); Pen pen = (((Object)(object)val2 != (Object)null) ? PenRegistry.ParseSign(val2) : null); if (pen == null) { _lookSign = null; return; } if ((Object)(object)_lookSign != (Object)(object)val2) { _lookSign = val2; _lookSince = Time.time; PenShapes.Request(pen); } if (Time.time - _lookSince >= 0.4f) { PenArea.Keep(pen, ShowAreaSeconds.Value); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Pen area failed: " + ex.Message)); } } private static bool IsTyping() { try { if (Console.IsVisible() || TextInput.IsVisible() || Menu.IsVisible() || Minimap.InTextInput() || InventoryGui.IsVisible()) { return true; } Chat instance = Chat.instance; return (Object)(object)instance != (Object)null && instance.HasFocus(); } catch { return false; } } } internal static class PenArea { private sealed class View { public Sign Sign; public GameObject Ring; public GameObject Ball; public GameObject Outline; public GameObject Gaps; public Material BallMaterial; public Color BallColor; public string Key; public float Shown; public float Until; } private static readonly Color Green = new Color(0.45f, 0.85f, 0.35f, 1f); private static readonly Color GreyBlue = new Color(0.56f, 0.66f, 0.79f, 1f); private static readonly Color Yellow = new Color(0.95f, 0.8f, 0.25f, 1f); private const float BallAlpha = 0.09f; private static readonly Dictionary<string, GameObject> s_segmentTemplates = new Dictionary<string, GameObject>(); private static GameObject s_templateParent; private static readonly List<View> Views = new List<View>(); private static Mesh s_ball; private static Shader s_shader; private static bool s_seeThrough; private static bool s_warned; public static void Keep(Pen pen, float seconds) { float num = Time.time + seconds; View view = Views.Find((View v) => (Object)(object)v.Sign == (Object)(object)pen.Sign); if (view != null) { if (view.Until < num) { view.Until = num; } } else { View view2 = Show(pen); view2.Until = num; Views.Add(view2); } } internal static bool Ok(Pen pen) { if (pen != null) { if (!pen.Forced && PenShapes.Enabled) { return pen.Shape != null; } return true; } return false; } internal static string KeyOf(Pen pen) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); if (pen.Shape != null && PenShapes.Enabled && !pen.Forced) { stringBuilder.Append('F').Append(pen.Shape.Area.ToString("0.0", CultureInfo.InvariantCulture)).Append('/') .Append(pen.Shape.Outline.Count); } else { stringBuilder.Append(pen.Square ? 'S' : 'R').Append(pen.Radius.ToString("0.0", CultureInfo.InvariantCulture)); } stringBuilder.Append(Ok(pen) ? "|ok" : "|fallback"); Vector3 center = pen.Center; stringBuilder.Append('|').Append(Mathf.RoundToInt(center.x * 2f)).Append(',') .Append(Mathf.RoundToInt(center.z * 2f)) .Append(',') .Append(Mathf.RoundToInt(((Quaternion)(ref pen.Facing)).eulerAngles.y)); if (PenShapes.Enabled && !pen.Forced) { foreach (GapMark gap in pen.Gaps) { stringBuilder.Append('|').Append(gap.Plugged ? 'p' : 'o').Append(Mathf.RoundToInt(gap.Pos.x)) .Append(',') .Append(Mathf.RoundToInt(gap.Pos.z)); } } return stringBuilder.ToString(); } public static void Tick() { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) for (int num = Views.Count - 1; num >= 0; num--) { View view = Views[num]; if ((Object)(object)view.Sign == (Object)null || Time.time >= view.Until) { Hide(view); Views.RemoveAt(num); } else { Pen pen = null; try { pen = PenRegistry.ParseSign(view.Sign); } catch { } if (pen == null) { Hide(view); Views.RemoveAt(num); } else { if (KeyOf(pen) != view.Key) { float until = view.Until; float shown = view.Shown; Hide(view); View view2 = Show(pen); view2.Until = until; view2.Shown = shown; Views[num] = view2; view = view2; } if ((Object)(object)view.BallMaterial != (Object)null) { float num2 = Mathf.Clamp01((Time.time - view.Shown) / 0.4f); float num3 = Mathf.Clamp01((view.Until - Time.time) / 1.5f); Color ballColor = view.BallColor; ballColor.a *= Mathf.Min(num2, num3); view.BallMaterial.color = ballColor; } } } } } public static void HideAll() { foreach (View view in Views) { Hide(view); } Views.Clear(); } private static View Show(Pen pen) { //IL_000f: 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_0014: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0181: 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_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_0172: 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_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Expected O, but got Unknown //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Expected O, but got Unknown //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) Color val = (Ok(pen) ? Green : GreyBlue); View view = new View { Sign = pen.Sign, Shown = Time.time, Until = Time.time + PenPostsPlugin.ShowAreaSeconds.Value, Key = KeyOf(pen), BallColor = new Color(val.r, val.g, val.b, 0.09f) }; if (pen.Gaps.Count > 0 && PenShapes.Enabled && !pen.Forced) { try { view.Gaps = ShowGaps(pen.Gaps); } catch (Exception e) { Warn("gap marks", e); } } if (pen.Shape != null && PenShapes.Enabled && !pen.Forced) { try { view.Outline = ShowOutline(pen.Shape.Outline, val); } catch (Exception e2) { Warn("outline", e2); } if ((Object)(object)view.Outline != (Object)null) { return view; } } if (pen.Square) { try { view.Outline = ShowOutline(SquareRuns(pen), val); } catch (Exception e3) { Warn("square", e3); } if ((Object)(object)view.Outline != (Object)null) { return view; } } Vector3 position = ((Component)pen.Sign).transform.position; float num = position.y - 1.5f; float num2 = default(float); RaycastHit val2 = default(RaycastHit); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(position, ref num2)) { num = num2; } else if (Physics.Raycast(position + Vector3.up * 0.5f, Vector3.down, ref val2, 30f, LayerMask.GetMask(new string[1] { "terrain" }))) { num = ((RaycastHit)(ref val2)).point.y; } Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(position.x, num, position.z); try { object obj; if (!((Object)(object)ZNetScene.instance != (Object)null)) { obj = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab("guard_stone"); obj = ((prefab != null) ? prefab.GetComponent<PrivateArea>() : null); } PrivateArea val4 = (PrivateArea)obj; if ((Object)(object)val4 != (Object)null && (Object)(object)val4.m_areaMarker != (Object)null) { view.Ring = Object.Instantiate<GameObject>(((Component)val4.m_areaMarker).gameObject, val3 + Vector3.up * 0.5f, Quaternion.identity); ((Object)view.Ring).name = "anwo_pen_ring"; CircleProjector component = view.Ring.GetComponent<CircleProjector>(); GameObject val5 = TintedSegment(component.m_prefab, val); if ((Object)(object)val5 != (Object)null) { component.m_prefab = val5; } component.m_radius = pen.Radius; component.m_nrOfSegments = Mathf.Clamp(Mathf.RoundToInt(MathF.PI * 2f * pen.Radius / 1.1f), 16, 220); view.Ring.SetActive(true); } } catch (Exception e4) { Warn("ring", e4); } try { if ((Object)(object)s_shader == (Object)null) { s_shader = Shader.Find("UI/Default"); s_seeThrough = (Object)(object)s_shader != (Object)null; if ((Object)(object)s_shader == (Object)null) { s_shader = Shader.Find("Sprites/Default") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Unlit/Transparent"); } } if ((Object)(object)s_shader != (Object)null) { view.Ball = new GameObject("anwo_pen_ball"); view.Ball.transform.SetPositionAndRotation(val3, Quaternion.identity); view.Ball.transform.localScale = Vector3.one * pen.Radius; view.Ball.AddComponent<MeshFilter>().sharedMesh = BallMesh(); MeshRenderer obj2 = view.Ball.AddComponent<MeshRenderer>(); view.BallMaterial = new Material(s_shader) { color = new Color(view.BallColor.r, view.BallColor.g, view.BallColor.b, 0f) }; if (s_seeThrough) { view.BallMaterial.SetInt("unity_GUIZTestMode", 4); } view.BallMaterial.renderQueue = 3100; ((Renderer)obj2).sharedMaterial = view.BallMaterial; ((Renderer)obj2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj2).receiveShadows = false; } } catch (Exception e5) { Warn("ball", e5); } return view; } private static float Glow(Color color) { //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_000d: 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) if (!(color == Yellow)) { if (!(color == Green)) { return 0.55f; } return 0.6f; } return 0.75f; } private static string ColourName(Color color) { //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_000d: 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) if (!(color == Yellow)) { if (!(color == Green)) { return "grey-blue"; } return "green"; } return "yellow"; } private static GameObject TintedSegment(GameObject original, Color color) { //IL_000b: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)original == (Object)null) { return null; } string text = ColourName(color); if (s_segmentTemplates.TryGetValue(text, out var value) && (Object)(object)value != (Object)null) { return value; } try { if ((Object)(object)s_templateParent == (Object)null) { s_templateParent = new GameObject("anwo_pen_ring_template"); s_templateParent.SetActive(false); Object.DontDestroyOnLoad((Object)(object)s_templateParent); } GameObject val = Object.Instantiate<GameObject>(original, s_templateParent.transform); ((Object)val).name = "anwo_pen_ring_segment_" + text.Replace("-", ""); val.SetActive(true); float num = Glow(color); List<string> list = new List<string>(); Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { Material[] sharedMaterials = val2.sharedMaterials; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null)) { Material val3 = new Material(sharedMaterials[j]); Tint(val3, "_Color", color, num, 0.45f); Tint(val3, "_TintColor", color, num * 0.64f, 0.45f); Tint(val3, "_MainColor", color, num, 0.45f); Tint(val3, "_BaseColor", color, num, 0.45f); if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", color * (num * 0.64f)); } sharedMaterials[j] = val3; list.Add(((Object)(object)val3.shader != (Object)null) ? ((Object)val3.shader).name : "?"); } } val2.sharedMaterials = sharedMaterials; } Light[] componentsInChildren2 = val.GetComponentsInChildren<Light>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Behaviour)componentsInChildren2[i]).enabled = false; } ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogInfo((object)("Pen ring look: " + text + " copy of the ward marker (" + ((list.Count == 0) ? "no materials" : string.Join(", ", list.Distinct())) + ").")); } s_segmentTemplates[text] = val; return val; } catch (Exception e) { Warn("ring colour", e); return null; } } private static void Tint(Material m, string property, Color color, float brightness, float alphaScale) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0035: Unknown result type (might be due to invalid IL or missing references) if (m.HasProperty(property)) { Color color2 = m.GetColor(property); m.SetColor(property, new Color(color.r * brightness, color.g * brightness, color.b * brightness, color2.a * alphaScale)); } } private static List<KeyValuePair<Vector3, Vector3>> SquareRuns(Pen pen) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_002b: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_0064: 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_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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_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) Vector3 position = ((Component)pen.Sign).transform.position; Vector3 val = pen.Facing * Vector3.right * pen.Radius; Vector3 val2 = pen.Facing * Vector3.forward * pen.Radius; Vector3 val3 = position - val - val2; Vector3 val4 = position + val - val2; Vector3 val5 = position + val + val2; Vector3 val6 = position - val + val2; return new List<KeyValuePair<Vector3, Vector3>> { new KeyValuePair<Vector3, Vector3>(val3, val4), new KeyValuePair<Vector3, Vector3>(val4, val5), new KeyValuePair<Vector3, Vector3>(val5, val6), new KeyValuePair<Vector3, Vector3>(val6, val3) }; } private static GameObject ShowOutline(List<KeyValuePair<Vector3, Vector3>> runs, Color tint) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) object obj; if (!((Object)(object)ZNetScene.instance != (Object)null)) { obj = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab("guard_stone"); obj = ((prefab != null) ? prefab.GetComponent<PrivateArea>() : null); } PrivateArea val = (PrivateArea)obj; if ((Object)(object)val == (Object)null || (Object)(object)val.m_areaMarker == (Object)null) { return null; } CircleProjector areaMarker = val.m_areaMarker; GameObject val2 = TintedSegment(areaMarker.m_prefab, tint) ?? areaMarker.m_prefab; if ((Object)(object)val2 == (Object)null) { return null; } int num = ((((LayerMask)(ref areaMarker.m_mask)).value != 0) ? ((LayerMask)(ref areaMarker.m_mask)).value : LayerMask.GetMask(new string[4] { "Default", "static_solid", "terrain", "piece" })); GameObject val3 = new GameObject("anwo_pen_outline"); int num2 = 0; RaycastHit val6 = default(RaycastHit); foreach (KeyValuePair<Vector3, Vector3> run in runs) { Vector3 key = run.Key; Vector3 val4 = run.Value - key; val4.y = 0f; float magnitude = ((Vector3)(ref val4)).magnitude; if (magnitude < 0.01f) { continue; } val4 /= magnitude; int num3 = Mathf.Max(1, Mathf.RoundToInt(magnitude / 1f)); for (int i = 0; i < num3; i++) { if (num2 >= 600) { break; } Vector3 val5 = key + val4 * (((float)i + 0.5f) * magnitude / (float)num3); val5.y = key.y; if (Physics.Raycast(val5 + Vector3.up * 1.5f, Vector3.down, ref val6, 4f, num, (QueryTriggerInteraction)1)) { val5.y = ((RaycastHit)(ref val6)).point.y; } Object.Instantiate<GameObject>(val2, val5, Quaternion.LookRotation(val4, Vector3.up), val3.transform).SetActive(true); num2++; } } return val3; } private static GameObject ShowGaps(List<GapMark> gaps) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0070: 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_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_0089: 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) object obj; if (!((Object)(object)ZNetScene.instance != (Object)null)) { obj = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab("guard_stone"); obj = ((prefab != null) ? prefab.GetComponent<PrivateArea>() : null); } PrivateArea val = (PrivateArea)obj; if ((Object)(object)val == (Object)null || (Object)(object)val.m_areaMarker == (Object)null) { return null; } GameObject val2 = new GameObject("anwo_pen_gaps"); foreach (GapMark gap in gaps) { GameObject obj2 = Object.Instantiate<GameObject>(((Component)val.m_areaMarker).gameObject, gap.Pos + Vector3.up * 0.5f, Quaternion.identity, val2.transform); ((Object)obj2).name = (gap.Plugged ? "anwo_pen_gap_ignored" : "anwo_pen_gap"); CircleProjector component = obj2.GetComponent<CircleProjector>(); if (gap.Plugged) { GameObject val3 = TintedSegment(component.m_prefab, Yellow); if ((Object)(object)val3 != (Object)null) { component.m_prefab = val3; } } component.m_nrOfSegments = Mathf.Clamp(Mathf.RoundToInt(MathF.PI * 2f * (component.m_radius = Mathf.Max(0.6f, gap.Width * 0.5f + 0.35f)) / 0.5f), 8, 40); obj2.SetActive(true); } return val2; } private static void Hide(View v) { if ((Object)(object)v.Gaps != (Object)null) { Object.Destroy((Object)(object)v.Gaps); } if ((Object)(object)v.Outline != (Object)null) { Object.Destroy((Object)(object)v.Outline); } if ((Object)(object)v.Ring != (Object)null) { Object.Destroy((Object)(object)v.Ring); } if ((Object)(object)v.Ball != (Object)null) { Object.Destroy((Object)(object)v.Ball); } if ((Object)(object)v.BallMaterial != (Object)null) { Object.Destroy((Object)(object)v.BallMaterial); } } private static void Warn(string what, Exception e) { if (!s_warned) { s_warned = true; ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogWarning((object)("Showing the pen " + what + " failed: " + e.Message)); } } } private static Mesh BallMesh() { //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected O, but got Unknown //IL_009f: 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) if ((Object)(object)s_ball != (Object)null) { return s_ball; } List<Vector3> list = new List<Vector3>(); List<Color> list2 = new List<Color>(); List<int> list3 = new List<int>(); for (int i = 0; i <= 32; i++) { float num = MathF.PI * ((float)i / 32f - 0.5f); float num2 = Mathf.Sin(num); float num3 = Mathf.Cos(num); float num4 = ((i % 4 == 0) ? 1.6f : 1f); if (i == 16) { num4 = 2.2f; } for (int j = 0; j <= 64; j++) { float num5 = MathF.PI * 2f * (float)j / 64f; list.Add(new Vector3(Mathf.Cos(num5) * num3, num2, Mathf.Sin(num5) * num3)); list2.Add(new Color(1f, 1f, 1f, Mathf.Clamp01(num4 * 0.5f))); } } int num6 = 65; for (int k = 0; k < 32; k++) { for (int l = 0; l < 64; l++) { int num7 = k * num6 + l; int num8 = num7 + num6; int item = num7 + 1; int item2 = num8 + 1; list3.Add(num7); list3.Add(num8); list3.Add(item); list3.Add(item); list3.Add(num8); list3.Add(item2); } } s_ball = new Mesh { name = "anwo_pen_ball" }; s_ball.SetVertices(list); s_ball.SetColors(list2); s_ball.SetTriangles(list3, 0); s_ball.RecalculateNormals(); s_ball.RecalculateBounds(); return s_ball; } } internal sealed class Pen { public Sign Sign; public Vector3 Center; public float Radius; public int Cap; public PenText.Caps Caps; public string Title; public PenForm Form; public Quaternion Facing = Quaternion.identity; public PenShape Shape; public string ShapeNote = ""; public float ShapeCheckedAt = -999f; public float ChangedAt = -999f; public List<GapMark> Gaps = new List<GapMark>(); public bool Forced => Form != PenForm.Fence; public bool Square { get { if (Form != PenForm.Square) { if (Form == PenForm.Fence && PenPostsPlugin.FallbackShape != null) { return PenPostsPlugin.FallbackShape.Value == FallbackForm.Square; } return false; } return true; } } } internal static class PenRegistry { private static readonly List<Sign> Signs = new List<Sign>(); private static readonly Dictionary<int, KeyValuePair<string, Pen>> Parsed = new Dictionary<int, KeyValuePair<string, Pen>>(); private static readonly Regex Tags = new Regex("<[^>]*>", RegexOptions.Compiled); private static readonly Regex PenRx = new Regex("^\\s*pen(?![a-z])\\s*[:\\-]?\\s*(?:(\\d+(?:[.,]\\d+)?)\\s*m?\\b)?(.*)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline); private static readonly Regex RoundRx = new Regex("\\b(?:round|circle)\\b", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SquareRx = new Regex("\\b(?:square|box)\\b", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly List<Pen> s_pens = new List<Pen>(); private static float s_pensAt = -999f; private static int s_pensSigns = -1; internal static List<Sign> AllSigns() { Signs.RemoveAll((Sign s) => (Object)(object)s == (Object)null); return Signs; } internal static List<Pen> Pens() { if (Time.time - s_pensAt < 1f && s_pensSigns == Signs.Count && Time.time >= s_pensAt) { return s_pens; } s_pensAt = Time.time; s_pens.Clear(); for (int num = Signs.Count - 1; num >= 0; num--) { Sign val = Signs[num]; if ((Object)(object)val == (Object)null) { Signs.RemoveAt(num); } else { Pen pen = null; try { pen = ParseSign(val); } catch { } if (pen != null) { s_pens.Add(pen); } } } s_pensSigns = Signs.Count; return s_pens; } internal static void ResetShapes() { PenShapes.Clear(); foreach (KeyValuePair<string, Pen> value in Parsed.Values) { if (value.Value != null) { value.Value.Shape = null; value.Value.ShapeNote = ""; value.Value.ShapeCheckedAt = -999f; value.Value.Gaps.Clear(); } } } public static void Add(Sign s) { if ((Object)(object)s != (Object)null && !Signs.Contains(s)) { Signs.Add(s); } } public static Pen ParseSign(Sign s) { //IL_0063: 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: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s == (Object)null) { return null; } string text; try { text = s.GetText(); } catch { return null; } if (string.IsNullOrEmpty(text)) { return null; } int instanceID = ((Object)s).GetInstanceID(); if (Parsed.TryGetValue(instanceID, out var value) && value.Key == text) { if (value.Value != null) { value.Value.Center = ((Component)s).transform.position; value.Value.Facing = FacingOf(s); } return value.Value; } Pen pen = null; string input = Tags.Replace(text, "").Trim(); Match match = PenRx.Match(input); if (match.Success) { float num = PenPostsPlugin.DefaultRadius.Value; if (match.Groups[1].Success && float.TryParse(match.Groups[1].Value.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { num = result; } num = Mathf.Clamp(num, 1f, PenPostsPlugin.MaxRadius.Value); string value2 = match.Groups[2].Value; PenText.Caps caps = PenText.Parse(value2); PenForm form = (SquareRx.IsMatch(value2) ? PenForm.Square : (RoundRx.IsMatch(value2) ? PenForm.Round : PenForm.Fence)); pen = new Pen { Sign = s, Center = ((Component)s).transform.position, Facing = FacingOf(s), Radius = num, Cap = caps.Cap, Caps = caps, Title = caps.Title, Form = form }; } Parsed[instanceID] = new KeyValuePair<string, Pen>(text, pen); return pen; } public static Pen FindPen(Vector3 pos) { //IL_002c: 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) Pen result = null; float num = float.MaxValue; foreach (Pen item in Pens()) { if (!((Object)(object)item.Sign == (Object)null) && Inside(item, pos)) { float num2 = pos.x - item.Center.x; float num3 = pos.z - item.Center.z; float num4 = num2 * num2 + num3 * num3; if (num4 < num) { result = item; num = num4; } } } return result; } public static bool Inside(Pen pen, Vector3 pos) { //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_002d: 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) if (pen.Shape != null && PenShapes.Enabled && !pen.Forced) { return pen.Shape.Contains(pos); } if (pen.Square) { return InSquare(pen, pos); } float num = pos.x - pen.Center.x; float num2 = pos.z - pen.Center.z; return num * num + num2 * num2 <= pen.Radius * pen.Radius; } public static bool InSquare(Pen pen, Vector3 pos) { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_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_0039: 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) Quaternion facing = pen.Facing; Vector3 val = new Quaternion(0f - facing.x, 0f - facing.y, 0f - facing.z, facing.w) * (pos - pen.Center); if (Mathf.Abs(val.x) <= pen.Radius) { return Mathf.Abs(val.z) <= pen.Radius; } return false; } internal static Quaternion FacingOf(Sign s) { //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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_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) Vector3 forward = ((Component)s).transform.forward; forward.y = 0f; if (!(((Vector3)(ref forward)).sqrMagnitude < 0.0001f)) { return Quaternion.LookRotation(((Vector3)(ref forward)).normalized, Vector3.up); } return Quaternion.identity; } } internal static class Context { internal struct State { public bool Set; public Procreation Proc; public int OldCap; public bool CapChanged; } internal static Procreation Current; internal static Pen CurrentPen; internal static int CapFor(Pen pen, Procreation proc) { if (pen == null) { return 0; } if (pen.Caps != null && pen.Caps.Kinds.Count > 0 && (Object)(object)proc != (Object)null) { Character component = ((Component)proc).GetComponent<Character>(); string text = ((!((Object)(object)component != (Object)null)) ? null : ((Localization.instance != null) ? Localization.instance.Localize(component.m_name) : component.m_name)); int num = PenText.KindCap(pen.Caps, text, Utils.GetPrefabName(((Component)proc).gameObject)); if (num > 0) { return num; } } if (pen.Cap <= 0) { return PenPostsPlugin.DefaultCap.Value; } return pen.Cap; } internal static State Enter(Procreation proc) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) State result = default(State); try { if ((Object)(object)proc == (Object)null || (Object)(object)Current != (Object)null) { return result; } Pen pen = PenRegistry.FindPen(((Component)proc).transform.position); if (pen == null) { return result; } result.Set = true; result.Proc = proc; Current = proc; CurrentPen = pen; int num = CapFor(pen, proc); if (num > 0) { result.OldCap = proc.m_maxCreatures; result.CapChanged = true; proc.m_maxCreatures = num; } } catch (Exception ex) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogDebug((object)("Enter failed: " + ex.Message)); } } return result; } internal static void Exit(State st) { if (!st.Set) { return; } try { if (st.CapChanged && (Object)(object)st.Proc != (Object)null) { st.Proc.m_maxCreatures = st.OldCap; } } catch { } Current = null; CurrentPen = null; } } internal static class VanillaPatches { private static float _hoverCacheTime; private static Sign _hoverCacheSign; private static string _hoverCacheText; [HarmonyPostfix] [HarmonyPatch(typeof(Sign), "Awake")] private static void SignAwake(Sign __instance) { PenRegistry.Add(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "Awake")] private static void ItemsLoaded() { ButcherKnife.Apply(); } [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static void ItemsCopied() { ButcherKnife.Apply(); } [HarmonyPostfix] [HarmonyPatch(typeof(WearNTear), "Awake")] private static void PieceAwake(WearNTear __instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) try { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { PenShapes.Changed(((Component)__instance).transform.position); } } catch { } } [HarmonyPostfix] [HarmonyPatch(typeof(WearNTear), "OnDestroy")] private static void PieceGone(WearNTear __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) try { PenShapes.Changed(((Component)__instance).transform.position); } catch { } } [HarmonyPrefix] [HarmonyPatch(typeof(Procreation), "Procreate")] private static void ProcreatePrefix(Procreation __instance, out Context.State __state) { __state = Context.Enter(__instance); } [HarmonyFinalizer] [HarmonyPatch(typeof(Procreation), "Procreate")] private static Exception ProcreateFinalizer(Exception __exception, Context.State __state) { Context.Exit(__state); return __exception; } [HarmonyPrefix] [HarmonyPatch(typeof(SpawnSystem), "GetNrOfInstances", new Type[] { typeof(GameObject), typeof(Vector3), typeof(float), typeof(bool), typeof(bool) })] private static bool CountPrefix(GameObject prefab, ref Vector3 center, ref float maxRange, bool eventCreaturesOnly, bool procreationOnly, ref int __result) { //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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) try { Procreation current = Context.Current; Pen pen = Context.CurrentPen; if ((Object)(object)current == (Object)null || pen == null || eventCreaturesOnly || procreationOnly) { return true; } if (Mathf.Abs(maxRange - current.m_totalCheckRange) > 0.01f) { return true; } if (pen.Shape != null && PenShapes.Enabled && !pen.Forced) { if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<BaseAI>() != (Object)null) { __result = PenShapes.Count(prefab, pen.Shape); return false; } center = new Vector3(pen.Shape.Centroid.x, ((Component)current).transform.position.y, pen.Shape.Centroid.z); maxRange = pen.Shape.Reach; return true; } if (pen.Square) { if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<BaseAI>() != (Object)null) { __result = PenShapes.Count(prefab, (Vector3 p) => PenRegistry.InSquare(pen, p)); return false; } center = new Vector3(pen.Center.x, ((Component)current).transform.position.y, pen.Center.z); maxRange = pen.Radius * 1.42f; return true; } center = new Vector3(pen.Center.x, ((Component)current).transform.position.y, pen.Center.z); maxRange = pen.Radius; } catch (Exception ex) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogDebug((object)("Count redirect failed: " + ex.Message)); } } return true; } [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch(typeof(MonsterAI), "UpdateConsumeItem")] private static void ConsumePrefix(MonsterAI __instance, out Tameable __state) { __state = null; try { __state = FullPens.Begin(__instance); } catch (Exception ex) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogDebug((object)("Full pen feeding check failed: " + ex.Message)); } } } [HarmonyFinalizer] [HarmonyPatch(typeof(MonsterAI), "UpdateConsumeItem")] private static Exception ConsumeFinalizer(Exception __exception, Tameable __state) { FullPens.End(__state); return __exception; } [HarmonyPostfix] [HarmonyPatch(typeof(Tameable), "IsHungry")] private static void IsHungryPostfix(Tameable __instance, ref bool __result) { if (__result && (Object)(object)FullPens.Suppressed != (Object)null && (Object)(object)FullPens.Suppressed == (Object)(object)__instance) { __result = false; } } [HarmonyPostfix] [HarmonyPatch(typeof(Sign), "GetHoverText")] private static void SignHover(Sign __instance, ref string __result) { try { if (!PenPostsPlugin.ShowPenHover.Value) { return; } Pen pen = PenRegistry.ParseSign(__instance); if (pen != null) { if ((Object)(object)_hoverCacheSign != (Object)(object)__instance || Time.time - _hoverCacheTime > 1f) { _hoverCacheSign = __instance; _hoverCacheTime = Time.time; _hoverCacheText = Describe(pen); } __result += _hoverCacheText; } } catch (Exception ex) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogDebug((object)("Hover failed: " + ex.Message)); } } } private static string AreaText(Pen pen) { if (pen.Shape != null && PenShapes.Enabled && !pen.Forced) { string text = $"fenced area, {pen.Shape.Area:0} m²"; List<GapMark> list = pen.Gaps.FindAll((GapMark g) => g.Plugged); if (list.Count == 1) { text = text + " (small gap " + list[0].Where + " ignored)"; } else if (list.Count > 1) { text += $" ({list.Count} small gaps ignored)"; } return text; } string text2 = (pen.Square ? $"{pen.Radius * 2f:0.#} m square" : $"{pen.Radius:0.#} m radius"); if (pen.Forced || !PenShapes.Enabled) { return text2; } if (!string.IsNullOrEmpty(pen.ShapeNote)) { return text2 + " (" + pen.ShapeNote + ")"; } return text2 + ((pen.ShapeCheckedAt < 0f) ? " (measuring the fence...)" : ""); } private static string Upper(string s) { if (!string.IsNullOrEmpty(s)) { return char.ToUpperInvariant(s[0]) + s.Substring(1); } return s; } private static string Describe(Pen pen) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsPlayer() && allCharacter.IsTamed() && PenRegistry.Inside(pen, ((Component)allCharacter).transform.position)) { string key = ((Localization.instance != null) ? Localization.instance.Localize(allCharacter.m_name) : allCharacter.m_name); dictionary.TryGetValue(key, out var value); dictionary[key] = value + 1; } } int num = ((pen.Cap > 0) ? pen.Cap : PenPostsPlugin.DefaultCap.Value); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("\n<color=#9fd36b>Pen</color>"); if (!string.IsNullOrEmpty(pen.Title)) { stringBuilder.Append(" \"").Append(pen.Title).Append('"'); } string text = ((pen.Caps == null || pen.Caps.Kinds.Count <= 0) ? ((num > 0) ? $"breeding cap {num}" : "each animal's own breeding cap") : ("breeding cap " + string.Join(", ", pen.Caps.Kinds.Select((KeyValuePair<string, int> k) => Upper(k.Key) + " " + k.Value)) + ((num > 0) ? (", others " + num) : ", others their own"))); stringBuilder.Append(": ").Append(AreaText(pen)).Append(", " + text); if (dictionary.Count == 0) { stringBuilder.Append("\nNo tamed animals inside"); } else { stringBuilder.Append("\nInside: ").Append(string.Join(", ", from kv in dictionary orderby kv.Value descending select $"{kv.Key} {kv.Value}")); } if (PenPostsPlugin.ShowAreaOnLook.Value) { stringBuilder.Append("\n<color=#c0c0c0>The pen's area shows while you look at this sign</color>"); } return stringBuilder.ToString(); } } internal static class FullPens { private struct Entry { public float Until; public bool Fasting; } internal static Tameable Suppressed; private static readonly Dictionary<int, Entry> Cache = new Dictionary<int, Entry>(); private static readonly FieldRef<BaseAI, Tameable> AiTameable = AccessTools.FieldRefAccess<BaseAI, Tameable>("m_tamable"); private static readonly FieldRef<MonsterAI, ItemDrop> ConsumeTarget = AccessTools.FieldRefAccess<MonsterAI, ItemDrop>("m_consumeTarget"); private static readonly FieldRef<Procreation, GameObject> MyPrefab = AccessTools.FieldRefAccess<Procreation, GameObject>("m_myPrefab"); private static readonly FieldRef<Procreation, GameObject> OffspringPrefab = AccessTools.FieldRefAccess<Procreation, GameObject>("m_offspringPrefab"); private static readonly Func<Tameable, bool> HaveSaddle = MakeHaveSaddle(); internal static Tameable Begin(MonsterAI ai) { if (!PenPostsPlugin.NoFoodWhenFull.Value || (Object)(object)ai == (Object)null) { return null; } Tameable val = AiTameable.Invoke((BaseAI)(object)ai); if ((Object)(object)val == (Object)null) { return null; } Character component = ((Component)ai).GetComponent<Character>(); if ((Object)(object)component == (Object)null || !component.IsTamed() || !val.IsHungry()) { return null; } if (!Fasting(ai)) { return null; } Suppressed = val; ConsumeTarget.Invoke(ai) = null; return val; } internal static void End(Tameable tame) { if ((Object)(object)tame != (Object)null && (Object)(object)Suppressed == (Object)(object)tame) { Suppressed = null; } } private static bool Fasting(MonsterAI ai) { int instanceID = ((Object)ai).GetInstanceID(); float time = Time.time; if (Cache.TryGetValue(instanceID, out var value) && time < value.Until) { return value.Fasting; } bool flag = false; try { flag = Decide(ai); } catch (Exception ex) { ManualLogSource log = PenPostsPlugin.Log; if (log != null) { log.LogDebug((object)("Full pen check failed: " + ex.Message)); } } if (Cache.Count > 2000) { Cache.Clear(); } Cache[instanceID] = new Entry { Until = time + 3f, Fasting = flag }; return flag; } private static Func<Tameable, bool> MakeHaveSaddle() { try { return AccessTools.MethodDelegate<Func<Tameable, bool>>(AccessTools.Method(typeof(Tameable), "HaveSaddle", (Type[])null, (Type[])null), (object)null, true); } catch { return null; } } private static bool Decide(MonsterAI ai) { Tameable val = AiTameable.Invoke((BaseAI)(object)ai); if ((Object)(object)val != (Object)null && HaveSaddle != null && HaveSaddle(val)) { return false; } Procreation component = ((Component)ai).GetComponent<Procreation>(); if ((Object)(object)component != (Object)null && !Crowded(component)) { return false; } return !HerdBellLink.StillProducing((Component)(object)ai); } internal static bool Crowded(Procreation proc) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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) if (PenRegistry.FindPen(((Component)proc).transform.position) != null) { return IsFull(proc); } GameObject val = MyPrefab.Invoke(proc); if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { val = ZNetScene.instance.GetPrefab(Utils.GetPrefabName(((Component)proc).gameObject)); } GameObject val2 = OffspringPrefab.Invoke(proc); if ((Object)(object)val2 == (Object)null && (Object)(object)proc.m_offspring != (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { val2 = ZNetScene.instance.GetPrefab(Utils.GetPrefabName(proc.m_offspring)); } if ((Object)(object)val == (Object)null) { return false; } Vector3 position = ((Component)proc).transform.position; int num = SpawnSystem.GetNrOfInstances(val, position, proc.m_totalCheckRange, false, false); if ((Object)(object)val2 != (Object)null) { num += SpawnSystem.GetNrOfInstances(val2, position, proc.m_totalCheckRange, false, false); } return num >= proc.m_maxCreatures; } internal static bool IsFull(Procreation proc) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) Context.State st = Context.Enter(proc); if (!st.Set) { return false; } try { GameObject val = MyPrefab.Invoke(proc); if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { val = ZNetScene.instance.GetPrefab(Utils.GetPrefabName(((Component)proc).gameObject)); } GameObject val2 = OffspringPrefab.Invoke(proc); if ((Object)(object)val2 == (Object)null && (Object)(object)proc.m_offspring != (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { val2 = ZNetScene.instance.GetPrefab(Utils.GetPrefabName(proc.m_offspring)); } if ((Object)(object)val == (Object)null) { return false;