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 BotanicOwnerDebug v1.0.7
BotanicOwnerDebug.dll
Decompiled 15 hours agousing System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.Rendering; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("1.0.7.0")] namespace BotanicOwnerDebug; internal static class BuildingVisuals { internal static bool Eligible(ZNetView view) { if (!Object.op_Implicit((Object)(object)view) || !view.m_persistent || view.m_distant || Object.op_Implicit((Object)(object)((Component)view).GetComponentInParent<Player>()) || Object.op_Implicit((Object)(object)((Component)view).GetComponentInParent<ItemDrop>())) { return false; } if (Object.op_Implicit((Object)(object)((Component)view).GetComponent<Character>())) { return true; } if (!Object.op_Implicit((Object)(object)((Component)view).GetComponentInParent<Character>())) { if (!Object.op_Implicit((Object)(object)((Component)view).GetComponent<Piece>()) && !Object.op_Implicit((Object)(object)((Component)view).GetComponent<WearNTear>())) { return Interactive(view); } return true; } return false; } internal static bool Interactive(ZNetView view) { MonoBehaviour[] componentsInChildren = ((Component)view).GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && val is Interactable) { Container val2 = (Container)(object)((val is Container) ? val : null); ZNetView val3 = ((Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.m_rootObjectOverride)) ? val2.m_rootObjectOverride : ((Component)val).GetComponentInParent<ZNetView>()); if ((Object)(object)val3 == (Object)(object)view) { return true; } } } return false; } internal static bool Solid(Material source) { if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)source.shader) || source.renderQueue >= 2450) { return false; } string tag = source.GetTag("RenderType", false, ""); if (!string.IsNullOrEmpty(tag) && !string.Equals(tag, "Opaque", StringComparison.OrdinalIgnoreCase)) { return false; } if (source.HasProperty("_Mode") && source.GetFloat("_Mode") != 0f) { return false; } if (source.HasProperty("_SrcBlend") && source.GetInt("_SrcBlend") != 1) { return false; } if (source.HasProperty("_DstBlend") && source.GetInt("_DstBlend") != 0) { return false; } string name = ((Object)source.shader).name; return !EffectShader(name); } private static bool EffectShader(string name) { if (string.IsNullOrEmpty(name)) { return true; } if (!name.StartsWith("Hidden/", StringComparison.OrdinalIgnoreCase) && !name.StartsWith("UI/", StringComparison.OrdinalIgnoreCase) && !name.StartsWith("Skybox/", StringComparison.OrdinalIgnoreCase) && !Contains(name, "particle") && !Contains(name, "effect") && !Contains(name, "vfx") && !Contains(name, "billboard") && !Contains(name, "distort") && !Contains(name, "glow") && !Contains(name, "halo") && !Contains(name, "flare") && !Contains(name, "TextMeshPro") && !Contains(name, "smoke") && !Contains(name, "fog") && !Contains(name, "cloud") && !Contains(name, "beam") && !Contains(name, "flame") && !Contains(name, "depthonly")) { return Contains(name, "invisible"); } return true; } private static bool Contains(string value, string token) { return value.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; } internal static bool Tintable(Material source) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (!Solid(source)) { return false; } if (source.HasProperty("_ZWrite") && source.GetInt("_ZWrite") == 0) { return false; } if (!source.HasProperty("_Color")) { return true; } Color color = source.GetColor("_Color"); if (color.a > 0f && !float.IsInfinity(color.a) && !float.IsNaN(color.r) && !float.IsNaN(color.g) && !float.IsNaN(color.b) && !float.IsInfinity(color.r) && !float.IsInfinity(color.g)) { return !float.IsInfinity(color.b); } return false; } } internal sealed class DebugView : IDisposable { private struct Surface { internal int Index; internal int Cull; } private sealed class Part { internal Renderer Renderer; internal Entry Entry; internal Surface[] Surfaces; } private sealed class Entry { internal ZDO Data; internal ZNetView View; internal OwnerKey Owner; internal bool Mob; internal bool Interactive; internal bool Live; internal int CheckedFrame; internal readonly HashSet<Renderer> Parts = new HashSet<Renderer>(); } private readonly Harmony hooks = new Harmony("botanic.owner.debug"); private readonly Dictionary<ZDOID, Entry> entries = new Dictionary<ZDOID, Entry>(); private readonly Dictionary<ZNetView, ZDOID> byView = new Dictionary<ZNetView, ZDOID>(); private readonly Dictionary<Renderer, Part> parts = new Dictionary<Renderer, Part>(); private readonly Dictionary<Renderer, Part> interactiveParts = new Dictionary<Renderer, Part>(); private readonly Dictionary<Renderer, Part> mobParts = new Dictionary<Renderer, Part>(); private bool interactiveOnly; private bool mobsOnly; private readonly HashSet<ZDOID> changed = new HashSet<ZDOID>(); private readonly HashSet<ZDOID> models = new HashSet<ZDOID>(); private readonly List<ZDOID> retiredEntries = new List<ZDOID>(); private readonly List<Renderer> retiredParts = new List<Renderer>(); private readonly HashSet<Renderer> seen = new HashSet<Renderer>(); private readonly List<Material> sourceMaterials = new List<Material>(); private readonly List<Surface> surfaces = new List<Surface>(); private readonly Dictionary<long, string> names = new Dictionary<long, string>(); private readonly NativeColours colours = new NativeColours(); internal readonly List<KeyValuePair<OwnerKey, string>> Legend = new List<KeyValuePair<OwnerKey, string>>(); internal readonly string Note = "Spieler, Effekte und Cluster ausgenommen"; private readonly Func<ZNetScene, Dictionary<ZDO, ZNetView>> instances; private readonly Plane[] planes = (Plane[])(object)new Plane[6]; private ZDOMan world; private ZNetScene scene; private ZNet network; private Camera camera; private CommandBuffer commands; private float nextRefresh; private float maxDistance; private long server; private int frame; internal string ModeLabel { get { if (!mobsOnly) { if (!interactiveOnly) { return "Alle Bauteile + Mobs"; } return "Interaktive Objekte + alle Mobs"; } return "Nur Mobs"; } } internal int PaintedCount { get; private set; } internal int TrackedCount { get { if (!mobsOnly) { if (!interactiveOnly) { return parts.Count; } return interactiveParts.Count; } return mobParts.Count; } } internal DebugView() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown FieldInfo field = typeof(ZNetScene).GetField("m_instances", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null || field.FieldType != typeof(Dictionary<ZDO, ZNetView>)) { throw new NotSupportedException("Native instance registry changed."); } DynamicMethod dynamicMethod = new DynamicMethod("BotanicDebugInstances", field.FieldType, new Type[1] { typeof(ZNetScene) }, typeof(DebugView).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); instances = (Func<ZNetScene, Dictionary<ZDO, ZNetView>>)dynamicMethod.CreateDelegate(typeof(Func<ZNetScene, Dictionary<ZDO, ZNetView>>)); try { hooks.CreateClassProcessor(typeof(DebugHooks)).Patch(); } catch { hooks.UnpatchSelf(); throw; } } private bool Context() { //IL_0135: 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_0141: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsDedicated() || !Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null) { return false; } if (!object.ReferenceEquals(world, ZDOMan.instance) || !object.ReferenceEquals(scene, ZNetScene.instance) || !object.ReferenceEquals(network, ZNet.instance)) { Clear(); world = ZDOMan.instance; scene = ZNetScene.instance; network = ZNet.instance; foreach (KeyValuePair<ZDO, ZNetView> item in instances(scene)) { Add(item.Key, item.Value); } } ZNetPeer serverPeer = network.GetServerPeer(); long num = (network.IsServer() ? ZDOMan.GetSessionID() : ((serverPeer != null && serverPeer.IsReady()) ? serverPeer.m_uid : 0)); if (server != num) { server = num; foreach (ZDOID key in entries.Keys) { changed.Add(key); } nextRefresh = 0f; } return true; } internal void Add(ZDO data, ZNetView view) { //IL_005c: 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_009a: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (data == null || !BuildingVisuals.Eligible(view) || !view.IsValid() || !object.ReferenceEquals(view.GetZDO(), data) || ((ZDOID)(ref data.m_uid)).IsNone()) { return; } if (byView.TryGetValue(view, out var value) && !((ZDOID)(ref value)).Equals(data.m_uid)) { Remove(view); } if (entries.TryGetValue(data.m_uid, out var value2)) { if (object.ReferenceEquals(value2.Data, data) && object.ReferenceEquals(value2.View, view)) { return; } Remove(value2.View); } entries.Add(data.m_uid, new Entry { Data = data, View = view, Mob = Object.op_Implicit((Object)(object)((Component)view).GetComponent<Character>()) }); byView[view] = data.m_uid; changed.Add(data.m_uid); models.Add(data.m_uid); } internal void Remove(ZNetView view) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) if (!byView.TryGetValue(view, out var value)) { return; } byView.Remove(view); changed.Remove(value); models.Remove(value); if (!entries.TryGetValue(value, out var value2) || !object.ReferenceEquals(value2.View, view)) { return; } foreach (Renderer part in value2.Parts) { parts.Remove(part); interactiveParts.Remove(part); mobParts.Remove(part); } entries.Remove(value); } internal void Changed(ZDO data) { //IL_0024: 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) if (data != null && world != null && object.ReferenceEquals(world, ZDOMan.instance) && entries.ContainsKey(data.m_uid)) { changed.Add(data.m_uid); } } internal void ModelsChanged(Component source) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)source)) { ZNetView componentInParent = source.GetComponentInParent<ZNetView>(); if (Object.op_Implicit((Object)(object)componentInParent) && byView.TryGetValue(componentInParent, out var value)) { models.Add(value); } } } private bool Valid(ZDOID id, Entry entry) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)entry.View) && entry.View.IsValid() && object.ReferenceEquals(entry.View.GetZDO(), entry.Data) && entry.Data.IsValid()) { return object.ReferenceEquals(world.GetZDO(id), entry.Data); } return false; } private void Scan(Entry entry) { entry.Interactive = !entry.Mob && BuildingVisuals.Interactive(entry.View); Character component = ((Component)entry.View).GetComponent<Character>(); seen.Clear(); Renderer[] componentsInChildren = ((Component)entry.View).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val) || (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer)) || (Object)(object)((Component)val).GetComponentInParent<ZNetView>() != (Object)(object)entry.View || Object.op_Implicit((Object)(object)((Component)val).GetComponentInParent<ItemDrop>())) { continue; } Character componentInParent = ((Component)val).GetComponentInParent<Character>(); if (componentInParent is Player || (Object.op_Implicit((Object)(object)componentInParent) && !object.ReferenceEquals(componentInParent, component))) { continue; } seen.Add(val); entry.Parts.Add(val); sourceMaterials.Clear(); val.GetSharedMaterials(sourceMaterials); surfaces.Clear(); for (int j = 0; j < sourceMaterials.Count; j++) { Material val2 = sourceMaterials[j]; if (BuildingVisuals.Tintable(val2)) { int num = (val2.HasProperty("_Cull") ? val2.GetInt("_Cull") : 2); if (num < 0 || num > 2) { num = 2; } surfaces.Add(new Surface { Index = j, Cull = num }); } } sourceMaterials.Clear(); if (!parts.TryGetValue(val, out var value)) { Part part = new Part(); part.Renderer = val; part.Entry = entry; value = part; parts.Add(val, value); } bool flag = value.Surfaces != null && value.Surfaces.Length == surfaces.Count; int num2 = 0; while (flag && num2 < surfaces.Count) { flag = value.Surfaces[num2].Index == surfaces[num2].Index && value.Surfaces[num2].Cull == surfaces[num2].Cull; num2++; } if (!flag) { value.Surfaces = surfaces.ToArray(); } if (entry.Mob || entry.Interactive) { interactiveParts[val] = value; } else { interactiveParts.Remove(val); } if (entry.Mob) { mobParts[val] = value; } else { mobParts.Remove(val); } } retiredParts.Clear(); foreach (Renderer part2 in entry.Parts) { if (!seen.Contains(part2)) { retiredParts.Add(part2); } } foreach (Renderer retiredPart in retiredParts) { parts.Remove(retiredPart); interactiveParts.Remove(retiredPart); mobParts.Remove(retiredPart); entry.Parts.Remove(retiredPart); } seen.Clear(); retiredParts.Clear(); surfaces.Clear(); } private OwnerKey Resolve(ZDO data) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return OwnerKey.Resolve(data != null && data.IsValid() && object.ReferenceEquals(world.GetZDO(data.m_uid), data), (data == null) ? 0 : data.GetOwner(), server); } private void Refresh() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: 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) names.Clear(); Legend.Clear(); HashSet<OwnerKey> hashSet = new HashSet<OwnerKey>(); foreach (PlayerInfo player in network.GetPlayerList()) { string text = (string.IsNullOrEmpty(player.m_name) ? "Spieler" : player.m_name); ZDOID characterID = player.m_characterID; if (!((ZDOID)(ref characterID)).IsNone()) { ZDOID characterID2 = player.m_characterID; if (((ZDOID)(ref characterID2)).UserID != 0) { ZDOID characterID3 = player.m_characterID; long userID = ((ZDOID)(ref characterID3)).UserID; names[userID] = text; hashSet.Add(OwnerKey.Resolve(known: true, userID, server)); continue; } } Legend.Add(new KeyValuePair<OwnerKey, string>(OwnerKey.Resolve(known: false, 0L, server), text + " (Besitz-ID lädt)")); } hashSet.Add(OwnerKey.Resolve(known: true, server, server)); hashSet.Add(OwnerKey.Resolve(known: true, 0L, server)); hashSet.Add(OwnerKey.Resolve(known: false, 0L, server)); retiredEntries.Clear(); foreach (KeyValuePair<ZDOID, Entry> entry in entries) { Entry value = entry.Value; if (!Valid(entry.Key, value)) { retiredEntries.Add(entry.Key); continue; } bool num; if (!mobsOnly) { if (!interactiveOnly || value.Mob) { goto IL_01bc; } num = value.Interactive; } else { num = value.Mob; } if (num) { goto IL_01bc; } goto IL_01ca; IL_01bc: hashSet.Add(value.Owner); goto IL_01ca; IL_01ca: if (value.Mob) { Scan(value); } } foreach (ZDOID retiredEntry in retiredEntries) { Remove(entries[retiredEntry].View); } retiredEntries.Clear(); foreach (OwnerKey item in hashSet) { string value3; string value2 = ((item.Kind != OwnerKind.Server) ? ((item.Kind != OwnerKind.Unowned) ? ((item.Kind != OwnerKind.Unknown) ? ((names.TryGetValue(item.Uid, out value3) ? value3 : "Besitzer") + " [" + item.Uid + "]") : "Besitz unbekannt / ZDO fehlt") : "Kein Besitzer") : "Server"); Legend.Add(new KeyValuePair<OwnerKey, string>(item, value2)); } Legend.Sort(delegate(KeyValuePair<OwnerKey, string> a, KeyValuePair<OwnerKey, string> b) { int num2 = a.Key.Kind.CompareTo(b.Key.Kind); if (num2 != 0) { return num2; } long uid = a.Key.Uid; int num3 = uid.CompareTo(b.Key.Uid); return (num3 == 0) ? StringComparer.Ordinal.Compare(a.Value, b.Value) : num3; }); nextRefresh = Time.unscaledTime + 1f; } private void UpdateEntries() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) retiredEntries.Clear(); foreach (ZDOID item in changed) { if (entries.TryGetValue(item, out var value)) { if (!Valid(item, value)) { retiredEntries.Add(item); } else { value.Owner = Resolve(value.Data); } } } foreach (ZDOID retiredEntry in retiredEntries) { Remove(entries[retiredEntry].View); } retiredEntries.Clear(); changed.Clear(); foreach (ZDOID model in models) { if (entries.TryGetValue(model, out var value2) && Valid(model, value2)) { Scan(value2); } } models.Clear(); } private void Attach(Camera next) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if (!object.ReferenceEquals(camera, next) || commands == null) { Detach(); camera = next; CommandBuffer val = new CommandBuffer(); val.name = "BotanicOwnerDebugOnly"; commands = val; camera.AddCommandBuffer((CameraEvent)18, commands); } } private void Detach() { CommandBuffer val = commands; commands = null; try { if (Object.op_Implicit((Object)(object)camera) && val != null) { camera.RemoveCommandBuffer((CameraEvent)18, val); } } finally { camera = null; if (val != null) { val.Release(); } } } internal void Draw(int seed, float strength, float distance, bool onlyInteractive = false, bool onlyMobs = false) { //IL_00c5: 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_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Invalid comparison between Unknown and I4 //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) PaintedCount = 0; if (!Context()) { Clear(); return; } Camera main = Camera.main; if (!Object.op_Implicit((Object)(object)main)) { Detach(); return; } if (interactiveOnly != onlyInteractive || mobsOnly != onlyMobs) { interactiveOnly = onlyInteractive; mobsOnly = onlyMobs; nextRefresh = 0f; } Attach(main); commands.Clear(); maxDistance = distance * distance; colours.Configure(seed, strength); frame++; UpdateEntries(); if (Time.unscaledTime >= nextRefresh) { Refresh(); } GeometryUtility.CalculateFrustumPlanes(camera, planes); Vector3 position = ((Component)camera).transform.position; foreach (Part value in (mobsOnly ? mobParts : (interactiveOnly ? interactiveParts : parts)).Values) { Renderer renderer = value.Renderer; if (!Object.op_Implicit((Object)(object)renderer) || !renderer.enabled || value.Surfaces.Length == 0 || renderer.forceRenderingOff || !((Component)renderer).gameObject.activeInHierarchy || !renderer.isVisible || (int)renderer.shadowCastingMode == 3) { continue; } Bounds bounds = renderer.bounds; int layer = ((Component)renderer).gameObject.layer; if ((camera.cullingMask & (1 << layer)) == 0) { continue; } Vector3 val = ((Bounds)(ref bounds)).center - position; if (((Vector3)(ref val)).sqrMagnitude > maxDistance || !GeometryUtility.TestPlanesAABB(planes, bounds)) { continue; } Entry entry = value.Entry; if (entry.CheckedFrame != frame) { entry.Live = Valid(entry.Data.m_uid, entry); entry.CheckedFrame = frame; } if (entry.Live) { Surface[] array = value.Surfaces; for (int i = 0; i < array.Length; i++) { Surface surface = array[i]; commands.DrawRenderer(renderer, colours.Get(value.Entry.Owner, surface.Cull), surface.Index, 0); } PaintedCount++; } } colours.Sweep(); } internal void Clear() { Detach(); colours.Clear(); entries.Clear(); byView.Clear(); parts.Clear(); interactiveParts.Clear(); mobParts.Clear(); changed.Clear(); models.Clear(); retiredEntries.Clear(); retiredParts.Clear(); seen.Clear(); sourceMaterials.Clear(); surfaces.Clear(); names.Clear(); Legend.Clear(); world = null; scene = null; network = null; server = 0L; nextRefresh = 0f; PaintedCount = 0; } public void Dispose() { try { hooks.UnpatchSelf(); } finally { Clear(); } } } [HarmonyPatch] internal static class DebugHooks { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(ZNetScene), "AddInstance", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ZNetView), "ResetZDO", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ZNetView), "OnDestroy", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ZDO), "SetOwnerInternal", (Type[])null, (Type[])null); yield return AccessTools.PropertySetter(typeof(ZDO), "OwnerRevision"); yield return AccessTools.Method(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null); try { string[] array = new string[4] { "AttachItem", "AttachArmor", "AttachBackItem", "SetRightItemVisual" }; foreach (string name in array) { MethodInfo method = AccessTools.Method(typeof(VisEquipment), name, (Type[])null, (Type[])null); if (method != null) { yield return method; } } } finally { } } [HarmonyPrefix] private static void Before(object __instance, MethodBase __originalMethod) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown DebugView debugView = (Object.op_Implicit((Object)(object)Plugin.Instance) ? Plugin.Instance.View : null); if (debugView == null) { return; } try { if (__instance is ZNetView) { debugView.Remove((ZNetView)__instance); } else if (__originalMethod.Name == "Shutdown") { debugView.Clear(); } } catch { } } [HarmonyPostfix] private static void After(object __instance, object[] __args, MethodBase __originalMethod) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_005c: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown DebugView debugView = (Object.op_Implicit((Object)(object)Plugin.Instance) ? Plugin.Instance.View : null); if (debugView == null) { return; } try { if (__instance is ZDO) { debugView.Changed((ZDO)__instance); } else if (__originalMethod.Name == "AddInstance") { debugView.Add((ZDO)__args[0], (ZNetView)__args[1]); } else if (__instance is VisEquipment) { debugView.ModelsChanged((Component)(VisEquipment)__instance); } } catch { } } } internal enum DisplayMode { Off, All, InteractiveAndMobs, MobsOnly } internal static class DisplayModes { internal static DisplayMode Current(bool enabled, bool interactiveOnly, bool mobsOnly = false) { if (enabled) { if (!mobsOnly) { if (!interactiveOnly) { return DisplayMode.All; } return DisplayMode.InteractiveAndMobs; } return DisplayMode.MobsOnly; } return DisplayMode.Off; } internal static DisplayMode Next(DisplayMode mode) { return mode switch { DisplayMode.InteractiveAndMobs => DisplayMode.MobsOnly, DisplayMode.All => DisplayMode.InteractiveAndMobs, DisplayMode.Off => DisplayMode.All, _ => DisplayMode.Off, }; } } internal sealed class NativeColours { private struct Key : IEquatable<Key> { internal OwnerKey Owner; internal int Cull; public bool Equals(Key other) { if (Owner.Equals(other.Owner)) { return Cull == other.Cull; } return false; } public override bool Equals(object other) { if (other is Key) { return Equals((Key)other); } return false; } public override int GetHashCode() { return Owner.GetHashCode() ^ (Cull * 397); } } private sealed class Paint { internal Material Material; internal int Frame; } private readonly Dictionary<Key, Paint> cache = new Dictionary<Key, Paint>(); private readonly List<Key> retired = new List<Key>(); private Shader shader; private int seed; private int frame; private float strength; private bool configured; private static readonly int colour = Shader.PropertyToID("_Color"); internal void Configure(int nextSeed, float nextStrength) { frame++; nextStrength = Mathf.Clamp01(nextStrength); if (configured && seed == nextSeed && strength == nextStrength) { return; } seed = nextSeed; strength = nextStrength; configured = true; foreach (KeyValuePair<Key, Paint> item in cache) { SetColour(item.Key.Owner, item.Value.Material); } } private void SetColour(OwnerKey owner, Material material) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) Rgb rgb = OwnerColour.Get(owner, seed); material.SetColor(colour, new Color(rgb.R, rgb.G, rgb.B, strength)); } internal Material Get(OwnerKey owner, int cull) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown Key key = new Key { Owner = owner, Cull = cull }; if (!cache.TryGetValue(key, out var value)) { if (!Object.op_Implicit((Object)(object)shader)) { shader = Shader.Find("Hidden/Internal-Colored"); } if (!Object.op_Implicit((Object)(object)shader) || !shader.isSupported) { throw new NotSupportedException("PUP-style flat shader unavailable."); } Material val = new Material(shader); ((Object)val).name = "BotanicOwnerDebugPaint"; ((Object)val).hideFlags = (HideFlags)61; val.enableInstancing = false; Material val2 = val; Paint paint = new Paint(); paint.Material = val2; value = paint; cache.Add(key, value); val2.SetInt("_SrcBlend", 5); val2.SetInt("_DstBlend", 10); val2.SetInt("_ZWrite", 0); val2.SetInt("_ZTest", 8); val2.SetInt("_Cull", cull); SetColour(owner, val2); } value.Frame = frame; return value.Material; } internal void Sweep() { retired.Clear(); foreach (KeyValuePair<Key, Paint> item in cache) { if (item.Value.Frame < frame - 2) { retired.Add(item.Key); } } foreach (Key item2 in retired) { Object.Destroy((Object)(object)cache[item2].Material); cache.Remove(item2); } retired.Clear(); } internal void Clear() { foreach (Paint value in cache.Values) { if (Object.op_Implicit((Object)(object)value.Material)) { Object.Destroy((Object)(object)value.Material); } } cache.Clear(); retired.Clear(); shader = null; } } internal enum OwnerKind { Unknown, Unowned, Server, Player } internal struct OwnerKey : IEquatable<OwnerKey> { internal OwnerKind Kind; internal long Uid; internal static OwnerKey Resolve(bool known, long owner, long server) { if (!known) { return new OwnerKey { Kind = OwnerKind.Unknown }; } if (owner == 0) { return new OwnerKey { Kind = OwnerKind.Unowned }; } return new OwnerKey { Kind = ((owner == server && server != 0) ? OwnerKind.Server : OwnerKind.Player), Uid = owner }; } public bool Equals(OwnerKey other) { if (Kind == other.Kind) { return Uid == other.Uid; } return false; } public override bool Equals(object other) { if (other is OwnerKey) { return Equals((OwnerKey)other); } return false; } public override int GetHashCode() { return ((int)Kind * 397) ^ Uid.GetHashCode(); } } internal struct Rgb { internal float R; internal float G; internal float B; internal Rgb(float r, float g, float b) { R = r; G = g; B = b; } } internal static class OwnerColour { internal static Rgb Get(OwnerKey key, int seed) { if (key.Kind == OwnerKind.Server) { return new Rgb(1f, 1f, 1f); } if (key.Kind == OwnerKind.Unowned) { return new Rgb(0.18f, 0.18f, 0.18f); } if (key.Kind == OwnerKind.Unknown) { return new Rgb(0.22f, 0.3f, 0.4f); } ulong num = (ulong)key.Uid ^ ((ulong)(uint)seed << 32) ^ 0x9E3779B97F4A7C15uL; num = (num ^ (num >> 30)) * 13787848793156543929uL; num = (num ^ (num >> 27)) * 10723151780598845931uL; num ^= num >> 31; float num2 = (float)(num & 0xFFFFFF) / 16777216f * 6f; int num3 = (int)num2; float num4 = num2 - (float)num3; float num5 = 1f - num4; float num6 = num4; return num3 switch { 0 => new Rgb(1f, num6, 0f), 1 => new Rgb(num5, 1f, 0f), 2 => new Rgb(0f, 1f, num6), 3 => new Rgb(0f, num5, 1f), 4 => new Rgb(num6, 0f, 1f), _ => new Rgb(1f, 0f, num5), }; } } [BepInPlugin("botanic.owner.debug", "BotanicOwnerDebug", "1.0.7")] public sealed class Plugin : BaseUnityPlugin { internal const string Id = "botanic.owner.debug"; internal static Plugin Instance; internal DebugView View; private ConfigEntry<bool> show; private ConfigEntry<bool> interactiveOnly; private ConfigEntry<bool> mobsOnly; private ConfigEntry<bool> legend; private ConfigEntry<bool> logs; private ConfigEntry<KeyboardShortcut> hotkey; private ConfigEntry<int> seed; private ConfigEntry<float> opacity; private ConfigEntry<float> distance; private bool rejected; private void Awake() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Invalid comparison between Unknown and I4 Instance = this; show = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowOwnerColours", false, "Local flat owner overlay for buildings and mobs; players, effects and loose items excluded. F10 cycles Off -> All -> Interactions and mobs -> Mobs only -> Off. No server/client ownership changes."); interactiveOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "InteractiveObjectsOnly", false, "When ShowOwnerColours is enabled, hide buildings without an Interactable belonging to their network object. All NPC mobs remain visible. F10 cycles this setting. Independent of Authority server categories/config; existing player/effect/loose-item exclusions remain."); mobsOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "MobsOnly", false, "When ShowOwnerColours is enabled, show only NPC mobs (wild and tamed); players remain excluded. Takes precedence over InteractiveObjectsOnly. F10 cycles this setting."); hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Debug", "ToggleKey", new KeyboardShortcut((KeyCode)291, (KeyCode[])(object)new KeyCode[0]), "Cycle Off -> All -> Interactions and mobs -> Mobs only -> Off while playing. No toggle while typing or a game menu is open."); legend = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowLegend", true, "Show owner colours and names. White=server, dark grey=unowned, saturated colours=players, blue-grey=unknown."); seed = ((BaseUnityPlugin)this).Config.Bind<int>("Debug", "ColourSeed", 1337, "Same owner ID and seed give the same pseudo-random colour on all clients. Does not use game RNG."); opacity = ((BaseUnityPlugin)this).Config.Bind<float>("Debug", "ColourStrength", 1f, new ConfigDescription("Owner colour strength, default full colour. Original materials stay unchanged. Old Opacity setting is no longer used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.15f, 1f), new object[0])); distance = ((BaseUnityPlugin)this).Config.Bind<float>("Debug", "MaximumDistance", 200f, new ConfigDescription("Overlay range from camera; native renderer visibility checked every frame.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 1000f), new object[0])); logs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableLogs", false, "Log optional debug errors. Default false."); if ((int)SystemInfo.graphicsDeviceType == 4) { ((Behaviour)this).enabled = false; } } private void Update() { //IL_0031: 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) if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated()) { Stop(); return; } if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { KeyboardShortcut value = hotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && !InputBlocked()) { DisplayMode displayMode = DisplayModes.Next(DisplayModes.Current(show.Value, interactiveOnly.Value, mobsOnly.Value)); interactiveOnly.Value = displayMode == DisplayMode.InteractiveAndMobs; mobsOnly.Value = displayMode == DisplayMode.MobsOnly; show.Value = displayMode != DisplayMode.Off; rejected = false; } } if (!show.Value || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null) { Stop(); if (!show.Value) { rejected = false; } } else if (!rejected && View == null) { try { View = new DebugView(); } catch (Exception error) { Error(error); } } } private static bool InputBlocked() { if ((!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Console.IsVisible() && (!Object.op_Implicit((Object)(object)TextInput.instance) || !TextInput.IsVisible()) && !Menu.IsVisible()) { return InventoryGui.IsVisible(); } return true; } private void LateUpdate() { if (View == null) { return; } try { View.Draw(seed.Value, opacity.Value, distance.Value, interactiveOnly.Value, mobsOnly.Value); } catch (Exception error) { Error(error); } } private void OnGUI() { //IL_01ea: 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_0044: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) if (View == null || !legend.Value) { return; } Color color = GUI.color; try { List<KeyValuePair<OwnerKey, string>> list = View.Legend; GUI.Box(new Rect(12f, 50f, 370f, (float)(111 + list.Count * 22)), "Botanic Besitz-Debug 1.0.7 – " + hotkey.Value); GUI.Label(new Rect(22f, 78f, 350f, 22f), "Modus: " + View.ModeLabel); int num = 100; foreach (KeyValuePair<OwnerKey, string> item in list) { Rgb rgb = OwnerColour.Get(item.Key, seed.Value); GUI.color = new Color(rgb.R, rgb.G, rgb.B, 1f); GUI.Label(new Rect(23f, (float)num, 22f, 22f), "■"); GUI.color = color; GUI.Label(new Rect(49f, (float)num, 320f, 22f), item.Value); num += 22; } GUI.Label(new Rect(22f, (float)(num + 4), 350f, 24f), View.Note); GUI.Label(new Rect(22f, (float)(num + 25), 350f, 24f), "Gezeichnet: " + View.PaintedCount + " / erfasst: " + View.TrackedCount); } finally { GUI.color = color; } } private void Error(Exception error) { rejected = true; Stop(); if (logs.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Owner debug disabled: " + error.Message)); } } private void Stop() { DebugView view = View; View = null; view?.Dispose(); } private void OnDestroy() { Stop(); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void OnDisable() { Stop(); } }