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 BudylivProduction v1.2.0
plugins/BudylivProduction.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.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; 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: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BudylivProduction { internal static class ClientLinker { internal sealed class Links { public List<ZDOID>[] Lists; public float At; public int Total => Lists[0].Count + Lists[1].Count + Lists[2].Count; public int Count(LinkRole role) { return Lists[(int)role].Count; } } private const float SelectionSeconds = 30f; private const float LinksTtl = 5f; private const float LinksRequestGap = 2f; private static ZDOID _station = ZDOID.None; private static LinkRole _role; private static bool _unlink; private static float _selectedAt; private static bool _captured; private static readonly Dictionary<ZDOID, Links> StationCache = new Dictionary<ZDOID, Links>(); private static readonly Dictionary<ZDOID, float> StationRequested = new Dictionary<ZDOID, float>(); private static readonly Dictionary<ZDOID, Links> ChestCache = new Dictionary<ZDOID, Links>(); private static readonly Dictionary<ZDOID, float> ChestRequested = new Dictionary<ZDOID, float>(); private const float NearRefreshSeconds = 3f; internal static List<(ZDOID Station, List<ZDOID>[] Lists)> NearLinks = new List<(ZDOID, List<ZDOID>[])>(); private static float _nearRequested = -1000f; internal static bool AltHeld { get { if (!Input.GetKey((KeyCode)308)) { return Input.GetKey((KeyCode)307); } return true; } } private static bool ShiftHeld { get { if (!Input.GetKey((KeyCode)304)) { return Input.GetKey((KeyCode)303); } return true; } } private static bool CtrlHeld { get { if (!Input.GetKey((KeyCode)306)) { return Input.GetKey((KeyCode)305); } return true; } } private static bool SelectionActive { get { if (!((ZDOID)(ref _station)).IsNone()) { return Time.time - _selectedAt <= 30f; } return false; } } internal static bool GesturesAllowed { get { if (AltHeld && !CtrlHeld) { return !IsTyping(); } return false; } } internal static bool ShowAll { get; private set; } internal static void SetNearLinks(List<(ZDOID Station, List<ZDOID>[] Lists)> stations) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) NearLinks = stations; foreach (var station in stations) { SetLinks(chest: false, station.Station, station.Lists); } } private unsafe static void UpdateShowAll() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) if (!IsTyping()) { KeyboardShortcut value = Plugin.ShowAllLinksKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { ShowAll = !ShowAll; string text; if (!ShowAll) { text = L.T("msg.show_all_off"); } else { object[] array = new object[1]; value = Plugin.ShowAllLinksKey.Value; array[0] = ((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).ToString(); text = L.T("msg.show_all_on", array); } Show(text); _nearRequested = -1000f; if (!ShowAll) { NearLinks = new List<(ZDOID, List<ZDOID>[])>(); } } } if (ShowAll && Time.time - _nearRequested >= 3f) { _nearRequested = Time.time; Net.SendRequest(LinkOp.NearInfo, ZDOID.None, ZDOID.None, LinkRole.Input); } } internal static void Update() { //IL_0098: 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) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_0170: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) UpdateShowAll(); if (_captured && !Input.GetKey((KeyCode)323) && !Input.GetKey((KeyCode)324) && !Input.GetKey((KeyCode)325)) { _captured = false; } if (!GesturesAllowed) { return; } bool keyDown = Input.GetKeyDown((KeyCode)323); bool keyDown2 = Input.GetKeyDown((KeyCode)324); bool keyDown3 = Input.GetKeyDown((KeyCode)325); if ((keyDown ? 1 : 0) + (keyDown2 ? 1 : 0) + (keyDown3 ? 1 : 0) != 1) { return; } StationInfo info; bool fuelControl; Container container; ZNetView val = HoverTarget(out info, out fuelControl, out container); if ((Object)(object)val == (Object)null) { return; } _captured = true; bool shiftHeld = ShiftHeld; ZDOID uid = val.GetZDO().m_uid; if (keyDown3) { if (!shiftHeld) { Show(L.T((info != null) ? "msg.wheel_station" : "msg.wheel_chest", L.T("btn.wheel"))); return; } if (info != null) { Net.SendRequest(LinkOp.UnlinkAll, uid, ZDOID.None, LinkRole.Input); if (_station == uid) { _station = ZDOID.None; } } else { Net.SendRequest(LinkOp.ChestUnlinkAll, ZDOID.None, uid, LinkRole.Input); } ForgetLinks(); } else if (info != null) { LinkRole? linkRole = ((!keyDown2) ? Stations.LeftRole(info, fuelControl) : (info.HasOutput ? new LinkRole?(LinkRole.Output) : ((LinkRole?)null))); if (!linkRole.HasValue) { Show(L.T(keyDown2 ? "msg.no_output" : "msg.no_input")); return; } _station = uid; _role = linkRole.Value; _unlink = shiftHeld; _selectedAt = Time.time; Show(L.T(_unlink ? "msg.unlinking" : "msg.linking", RoleName(_role), Button(_role))); } else { if (!((Object)(object)container != (Object)null)) { return; } if (!SelectionActive) { Show(L.T("msg.pick_station", L.T("btn.left"), L.T("btn.right"))); return; } bool flag = _role == LinkRole.Output; if (keyDown2 != flag || shiftHeld != _unlink) { Show(L.T("msg.wrong_button", RoleName(_role), (_unlink ? "Shift+" : "") + "Alt+" + Button(_role))); } else { Net.SendRequest((!_unlink) ? LinkOp.Link : LinkOp.Unlink, _station, uid, _role); ForgetLinks(); _station = ZDOID.None; } } } internal static bool ShouldSuppressCombat() { if (_captured) { return true; } if (!GesturesAllowed) { return false; } StationInfo info; bool fuelControl; Container container; return (Object)(object)HoverTarget(out info, out fuelControl, out container) != (Object)null; } internal static void Show(string text) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true); } } internal static void SetLinks(bool chest, ZDOID id, List<ZDOID>[] lists) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) (chest ? ChestCache : StationCache)[id] = new Links { Lists = lists, At = Time.time }; } private static void ForgetLinks() { _nearRequested = -1000f; StationCache.Clear(); ChestCache.Clear(); StationRequested.Clear(); ChestRequested.Clear(); } internal static Links StationLinks(ZDOID id) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return Cached(StationCache, StationRequested, id, chest: false); } internal static Links ChestLinks(ZDOID id) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return Cached(ChestCache, ChestRequested, id, chest: true); } private static Links Cached(Dictionary<ZDOID, Links> cache, Dictionary<ZDOID, float> requested, ZDOID id, bool chest) { //IL_0001: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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) cache.TryGetValue(id, out var value); if ((value == null || Time.time - value.At > 5f) && (!requested.TryGetValue(id, out var value2) || Time.time - value2 > 2f)) { requested[id] = Time.time; if (chest) { Net.SendRequest(LinkOp.ChestInfo, ZDOID.None, id, LinkRole.Input); } else { Net.SendRequest(LinkOp.Info, id, ZDOID.None, LinkRole.Input); } } return value; } internal static string StationHint(GameObject hovered) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) StationInfo info; bool fuelControl; ZNetView val = Stations.FindStation(hovered, out info, out fuelControl); if ((Object)(object)val == (Object)null) { return ""; } ZDOID uid = val.GetZDO().m_uid; string text = ""; LinkRole? linkRole = Stations.LeftRole(info, fuelControl); if (linkRole.HasValue) { text = text + "\n" + Key("Alt+" + L.T("btn.left")) + " " + L.T((linkRole.Value == LinkRole.Fuel) ? "hint.link.fuel" : "hint.link.input"); } if (info.HasOutput) { text = text + "\n" + Key("Alt+" + L.T("btn.right")) + " " + L.T("hint.link.output"); } text = text + "\n" + Key("Shift+Alt+" + L.T("btn.left") + "/" + L.T("btn.right")) + " " + L.T("hint.unlink"); text = text + "\n" + Key("Shift+Alt+" + L.T("btn.wheel")) + " " + L.T("hint.unlink_all"); text = text + "\n" + Key(((object)Plugin.ShowAllLinksKey.Value/*cast due to .constrained prefix*/).ToString()) + " " + L.T(ShowAll ? "hint.hide_all" : "hint.show_all"); Links links = StationLinks(uid); if (links != null) { List<string> list = new List<string>(); if (info.HasInput) { list.Add($"{RoleName(LinkRole.Input)} {links.Count(LinkRole.Input)}"); } if (info.HasFuel) { list.Add($"{RoleName(LinkRole.Fuel)} {links.Count(LinkRole.Fuel)}"); } if (info.HasOutput) { list.Add($"{RoleName(LinkRole.Output)} {links.Count(LinkRole.Output)}"); } text = text + "\n" + L.T("hint.chests", string.Join(" · ", list)); if (links.Total > 0 && !AltHeld && !ShowAll) { text = text + " <color=#aaaaaa>" + L.T("hint.alt_show") + "</color>"; } } if (SelectionActive && _station == uid) { text = text + "\n<color=orange>" + L.T(_unlink ? "hint.selected_unlink" : "hint.selected_link", RoleName(_role)) + "</color>"; } return text; } internal static string ContainerHint(Container container) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) string text = ""; ZNetView val = ValidView((Component)(object)container); if ((Object)(object)val != (Object)null) { Links links = ChestLinks(val.GetZDO().m_uid); if (links != null && links.Total > 0) { List<string> list = new List<string>(); LinkRole[] array = new LinkRole[3] { LinkRole.Input, LinkRole.Fuel, LinkRole.Output }; foreach (LinkRole role in array) { if (links.Count(role) > 0) { list.Add($"{RoleName(role)} {links.Count(role)}"); } } text = text + "\n" + L.T("hint.chest_stations", string.Join(" · ", list)); if (!AltHeld && !ShowAll) { text = text + " <color=#aaaaaa>" + L.T("hint.alt_show") + "</color>"; } text = text + "\n" + Key("Shift+Alt+" + L.T("btn.wheel")) + " " + L.T("hint.chest_unlink_all"); } } if (SelectionActive) { text = text + "\n" + Key((_unlink ? "Shift+" : "") + "Alt+" + Button(_role)) + " " + L.T(_unlink ? "hint.chest_unlink_as" : "hint.chest_link_as", RoleName(_role)); } return text; } internal static string RoleName(LinkRole role) { return L.Role(role); } private static string Button(LinkRole role) { return L.T((role == LinkRole.Output) ? "btn.right" : "btn.left"); } private static string Key(string key) { return "[<color=yellow><b>" + key + "</b></color>]"; } internal static ZNetView HoverTarget(out StationInfo info, out bool fuelControl, out Container container) { info = null; fuelControl = false; container = null; Player localPlayer = Player.m_localPlayer; GameObject val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetHoverObject() : null); if ((Object)(object)val == (Object)null) { return null; } ZNetView val2 = Stations.FindStation(val, out info, out fuelControl); if ((Object)(object)val2 != (Object)null) { return val2; } container = val.GetComponentInParent<Container>(); if ((Object)(object)container == (Object)null) { return null; } ZNetView val3 = ValidView((Component)(object)container); if (!((Object)(object)val3 == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab(val3.GetZDO().GetPrefab()); if (!((Object)(object)((prefab != null) ? prefab.GetComponent<Container>() : null) == (Object)null)) { return val3; } } container = null; return null; } private static ZNetView ValidView(Component component) { ZNetView componentInParent = component.GetComponentInParent<ZNetView>(); if (!((Object)(object)componentInParent != (Object)null) || !componentInParent.IsValid()) { return null; } return componentInParent; } internal static bool IsTyping() { if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !TextInput.IsVisible()) { return Minimap.IsOpen(); } return true; } } [HarmonyPatch] internal static class Station_GetHoverText_Patch { private static IEnumerable<MethodBase> TargetMethods() { Type[] array = new Type[9] { typeof(Switch), typeof(Fireplace), typeof(Beehive), typeof(SapCollector), typeof(Fermenter), typeof(CookingStation), typeof(ShieldGenerator), typeof(Turret), typeof(WispSpawner) }; for (int i = 0; i < array.Length; i++) { MethodInfo methodInfo = AccessTools.Method(array[i], "GetHoverText", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { yield return methodInfo; } } } [HarmonyPriority(0)] [HarmonyAfter(new string[] { "shudnal.MyLittleUI" })] private static void Postfix(Component __instance, ref string __result) { if (Plugin.ShowControlHints.Value && !((Object)(object)ZNet.instance == (Object)null) && !((Object)(object)__instance == (Object)null) && !string.IsNullOrEmpty(__result)) { __result += ClientLinker.StationHint(__instance.gameObject); } } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class Container_GetHoverText_Patch { [HarmonyPriority(0)] [HarmonyAfter(new string[] { "shudnal.MyLittleUI" })] private static void Postfix(Container __instance, ref string __result) { if (Plugin.ShowControlHints.Value && (Object)(object)ZNet.instance != (Object)null) { __result += ClientLinker.ContainerHint(__instance); } } } [HarmonyPatch(typeof(Player), "SetControls")] internal static class Player_SetControls_Patch { private static void Prefix(Player __instance, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ClientLinker.ShouldSuppressCombat()) { attack = (attackHold = (secondaryAttack = (secondaryAttackHold = (block = (blockHold = false))))); } } } internal sealed class StationLinks { public ZDOID Station; public readonly List<ZDOID>[] Chests = new List<ZDOID>[3] { new List<ZDOID>(), new List<ZDOID>(), new List<ZDOID>() }; public bool IsEmpty => Chests.All((List<ZDOID> c) => c.Count == 0); public List<ZDOID> Of(LinkRole role) { return Chests[(int)role]; } } internal static class LinkStore { private const string HeaderV1 = "# Budyliv Production links v1"; private const string HeaderV2 = "# Budyliv Production links v2"; internal static readonly Dictionary<ZDOID, StationLinks> All = new Dictionary<ZDOID, StationLinks>(); private static readonly Dictionary<ZDOID, ObjKey> Keys = new Dictionary<ZDOID, ObjKey>(); private static readonly List<string> Unresolved = new List<string>(); private static string _path; private static bool _dirty; internal static bool Loaded => _path != null; internal static int UnresolvedCount => Unresolved.Count; internal static void Load(string worldName) { All.Clear(); Keys.Clear(); Unresolved.Clear(); _dirty = false; _path = Path.Combine(Path.Combine(Utils.GetSaveDataPath((FileSource)2), "worlds_local"), worldName + ".budylivproduction.txt"); if (!File.Exists(_path)) { Plugin.Log.LogInfo((object)("No link file yet: " + _path)); return; } string[] array = File.ReadAllLines(_path); if (array.Length != 0 && array[0].Trim() == "# Budyliv Production links v1") { string text = _path + ".v1.bak"; File.Copy(_path, text, overwrite: true); Plugin.Log.LogWarning((object)$"Link file is v1 (ZDOIDs, not stable across restarts): {array.Length - 1} lines moved to {text}; links must be made again."); _dirty = true; return; } int num = 0; string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text2 = array2[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#")) { continue; } bool? flag = TryResolve(text2); if (flag.HasValue) { if (flag == true) { num++; } else { Unresolved.Add(text2); } } else { Plugin.Log.LogWarning((object)("Skipping bad link line: " + text2)); } } _dirty = false; Plugin.Log.LogInfo((object)($"Loaded {num} links for {All.Count} stations from {_path}" + ((Unresolved.Count > 0) ? $"; {Unresolved.Count} links point to objects not found (kept, retried)" : ""))); } private static bool? TryResolve(string line) { string[] array = line.Split('\t'); if (array.Length != 3 || !ObjKey.TryParse(array[0], out var key) || !ObjKey.TryParse(array[2], out var key2) || !int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result < 0 || result > 2) { return null; } ZDO val = Zdos.Find(key); ZDO val2 = Zdos.Find(key2); if (val == null || val2 == null) { return false; } Add(val, (LinkRole)result, val2); return true; } internal static void RetryUnresolved() { if (Unresolved.Count == 0) { return; } int num = 0; foreach (string item in Unresolved.ToList()) { if (TryResolve(item) != false) { Unresolved.Remove(item); num++; _dirty = true; } } if (num > 0) { Plugin.Log.LogInfo((object)$"Resolved {num} links that were missing at load; {Unresolved.Count} still missing."); } } internal static bool Add(ZDO station, LinkRole role, ZDO chest) { //IL_0006: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) Keys[station.m_uid] = ObjKey.Of(station); Keys[chest.m_uid] = ObjKey.Of(chest); if (!All.TryGetValue(station.m_uid, out var value)) { Dictionary<ZDOID, StationLinks> all = All; ZDOID uid = station.m_uid; StationLinks obj = new StationLinks { Station = station.m_uid }; value = obj; all[uid] = obj; } List<ZDOID> list = value.Of(role); if (list.Contains(chest.m_uid)) { return false; } list.Add(chest.m_uid); _dirty = true; return true; } internal static bool Remove(ZDOID station, LinkRole role, ZDOID chest) { //IL_0005: 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_002d: Unknown result type (might be due to invalid IL or missing references) if (!All.TryGetValue(station, out var value) || !value.Of(role).Remove(chest)) { return false; } if (value.IsEmpty) { All.Remove(station); } _dirty = true; return true; } internal static void RemoveStation(ZDOID station) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (All.Remove(station)) { _dirty = true; } } internal static void RemoveChestEverywhere(ZDOID chest) { //IL_002b: 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_00bd: 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) foreach (StationLinks item in All.Values.ToList()) { List<ZDOID>[] chests = item.Chests; for (int i = 0; i < chests.Length; i++) { if (chests[i].Remove(chest)) { _dirty = true; } } } foreach (ZDOID item2 in (from kv in All where kv.Value.IsEmpty select kv.Key).ToList()) { All.Remove(item2); } } internal static void SaveIfDirty() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!_dirty || _path == null) { return; } _dirty = false; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("# Budyliv Production links v2").Append('\n'); foreach (StationLinks value3 in All.Values) { if (!Keys.TryGetValue(value3.Station, out var value)) { continue; } for (int i = 0; i < 3; i++) { foreach (ZDOID item in value3.Chests[i]) { if (Keys.TryGetValue(item, out var value2)) { stringBuilder.Append(value).Append('\t').Append(i.ToString(CultureInfo.InvariantCulture)) .Append('\t') .Append(value2) .Append('\n'); } } } } foreach (string item2 in Unresolved) { stringBuilder.Append(item2).Append('\n'); } try { string text = _path + ".tmp"; File.WriteAllText(text, stringBuilder.ToString()); if (File.Exists(_path)) { File.Replace(text, _path, null); } else { File.Move(text, _path); } } catch (Exception ex) { _dirty = true; Plugin.Log.LogError((object)("Could not save links to " + _path + ": " + ex.Message)); } } internal static void Unload() { SaveIfDirty(); All.Clear(); Keys.Clear(); Unresolved.Clear(); _path = null; } } internal static class LinkVisuals { private struct Strand { public LinkRole Role; public bool Implicit; } private static readonly Color InputColor = new Color(0.25f, 0.6f, 1f); private static readonly Color FuelColor = new Color(1f, 0.55f, 0.1f); private static readonly Color OutputColor = new Color(0.3f, 1f, 0.35f); private static readonly int EmissionId = Shader.PropertyToID("_EmissionColor"); private static GameObject _root; private static Material _material; private static Material _slowMaterial; private const int TexW = 32; private const int TexH = 16; private const int Phases = 16; private const float ChevronPitch = 0.22f; private const float LineWidth = 0.08f; private static Texture2D[] _phaseTex; private static float _phase; private static float _slowPhase; private static readonly List<LineRenderer> Lines = new List<LineRenderer>(); private static readonly HashSet<GameObject> Highlighted = new HashSet<GameObject>(); private static readonly HashSet<GameObject> WantedHighlight = new HashSet<GameObject>(); private const float StrandGap = 0.09f; private static readonly Dictionary<GameObject, List<Strand>> GlowWanted = new Dictionary<GameObject, List<Strand>>(); private static readonly Dictionary<GameObject, (Vector3 Pos, float At)> AnchorCache = new Dictionary<GameObject, (Vector3, float)>(); internal static Color RoleColor(LinkRole role) { //IL_0013: 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_0007: Unknown result type (might be due to invalid IL or missing references) return (Color)(role switch { LinkRole.Fuel => FuelColor, LinkRole.Input => InputColor, _ => OutputColor, }); } internal static void Update() { int used = 0; GlowWanted.Clear(); if (Plugin.ShowLinkLines.Value && (Object)(object)ZNetScene.instance != (Object)null && ZDOMan.instance != null) { if (ClientLinker.ShowAll) { DrawAll(ref used); } else if (ClientLinker.GesturesAllowed) { DrawHovered(ref used); } } if (used > 0) { Animate(); } for (int i = used; i < Lines.Count; i++) { if ((Object)(object)Lines[i] != (Object)null && ((Renderer)Lines[i]).enabled) { ((Renderer)Lines[i]).enabled = false; } } foreach (KeyValuePair<GameObject, List<Strand>> item in GlowWanted) { item.Value.Sort(Order); Glow(item.Key, item.Value); } foreach (GameObject item2 in new List<GameObject>(Highlighted)) { if (!((Object)(object)item2 != (Object)null) || !GlowWanted.ContainsKey(item2)) { Unglow(item2); Highlighted.Remove(item2); } } if (AnchorCache.Count > 512) { AnchorCache.Clear(); } } private static void DrawHovered(ref int used) { //IL_001c: 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_0053: 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) StationInfo info; bool fuelControl; Container container; ZNetView val = ClientLinker.HoverTarget(out info, out fuelControl, out container); if ((Object)(object)val == (Object)null) { return; } Dictionary<ZDOID, List<Strand>> dictionary = Collect(val.GetZDO().m_uid, info); if (dictionary == null) { return; } Vector3 val2 = Anchor(((Component)val).gameObject); bool fromIsStation = info != null; foreach (KeyValuePair<ZDOID, List<Strand>> item in dictionary) { if (Endpoint(item.Key, out var pos, out var go)) { DrawStrands(ref used, val2, pos, fromIsStation, item.Value); AddGlow(go, item.Value); } } } private static void DrawAll(ref int used) { //IL_0018: 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) //IL_0038: 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_0103: 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_00c2: Unknown result type (might be due to invalid IL or missing references) foreach (var (val, array) in ClientLinker.NearLinks) { if (!Endpoint(val, out var pos, out var go)) { continue; } StationInfo stationInfo = Stations.Get(ZDOMan.instance.GetZDO(val).GetPrefab()); Dictionary<ZDOID, List<Strand>> perChest = new Dictionary<ZDOID, List<Strand>>(); for (int i = 0; i < 3; i++) { foreach (ZDOID item in array[i]) { Add(item, (LinkRole)i, isImplicit: false); } } if (stationInfo != null && stationInfo.HasFuel && array[1].Count == 0) { foreach (ZDOID item2 in array[0]) { Add(item2, LinkRole.Fuel, isImplicit: true); } } foreach (KeyValuePair<ZDOID, List<Strand>> item3 in perChest) { if (Endpoint(item3.Key, out var pos2, out var go2)) { item3.Value.Sort(Order); DrawStrands(ref used, pos, pos2, fromIsStation: true, item3.Value); AddGlow(go2, item3.Value); AddGlow(go, item3.Value); } } void Add(ZDOID chest, LinkRole role, bool isImplicit) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!perChest.TryGetValue(chest, out var value)) { value = (perChest[chest] = new List<Strand>()); } if (!value.Exists((Strand x) => x.Role == role && x.Implicit == isImplicit)) { value.Add(new Strand { Role = role, Implicit = isImplicit }); } } } } private static int Order(Strand a, Strand b) { if (a.Implicit == b.Implicit) { return a.Role.CompareTo(b.Role); } if (!a.Implicit) { return -1; } return 1; } private static bool Endpoint(ZDOID id, out Vector3 pos, out GameObject go) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) pos = default(Vector3); go = null; ZDO zDO = ZDOMan.instance.GetZDO(id); if (zDO == null) { return false; } ZNetView val = ZNetScene.instance.FindInstance(zDO); if ((Object)(object)val != (Object)null) { go = ((Component)val).gameObject; pos = Anchor(go); } else { pos = zDO.GetPosition() + Vector3.up * 0.5f; } return true; } private static void DrawStrands(ref int used, Vector3 from, Vector3 to, bool fromIsStation, List<Strand> list) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0003: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0030: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (fromIsStation ? from : to); Vector3 val2 = (fromIsStation ? to : from); Vector3 val3 = Vector3.Cross(val2 - val, Vector3.up); val3 = ((((Vector3)(ref val3)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val3)).normalized : Vector3.right); for (int i = 0; i < list.Count; i++) { Vector3 val4 = val3 * (((float)i - (float)(list.Count - 1) * 0.5f) * 0.09f); Color color = RoleColor(list[i].Role); if (list[i].Implicit) { color.a = 0.35f; } bool num = list[i].Role == LinkRole.Output; Vector3 val5 = (num ? val : val2) + val4; Vector3 to2 = (num ? val2 : val) + val4; Draw(used++, val5, to2, color, list[i].Implicit ? 0.6f : 1f, list[i].Implicit); } } private static void AddGlow(GameObject go, List<Strand> strands) { if ((Object)(object)go == (Object)null) { return; } if (!GlowWanted.TryGetValue(go, out var value)) { value = (GlowWanted[go] = new List<Strand>()); } foreach (Strand s in strands) { if (!value.Exists((Strand x) => x.Role == s.Role && x.Implicit == s.Implicit)) { value.Add(s); } } } private static Dictionary<ZDOID, List<Strand>> Collect(ZDOID id, StationInfo info) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) Dictionary<ZDOID, List<Strand>> result = new Dictionary<ZDOID, List<Strand>>(); if (info != null) { ClientLinker.Links links = ClientLinker.StationLinks(id); if (links == null) { return null; } for (int i = 0; i < 3; i++) { foreach (ZDOID item in links.Lists[i]) { Add(item, (LinkRole)i, isImplicit: false); } } if (info.HasFuel && links.Count(LinkRole.Fuel) == 0) { foreach (ZDOID item2 in links.Lists[0]) { Add(item2, LinkRole.Fuel, isImplicit: true); } } } else { ClientLinker.Links links2 = ClientLinker.ChestLinks(id); if (links2 == null) { return null; } for (int j = 0; j < 3; j++) { foreach (ZDOID item3 in links2.Lists[j]) { Add(item3, (LinkRole)j, isImplicit: false); } } foreach (ZDOID item4 in links2.Lists[0]) { ZDO zDO = ZDOMan.instance.GetZDO(item4); StationInfo stationInfo = ((zDO != null) ? Stations.Get(zDO.GetPrefab()) : null); if (stationInfo != null && stationInfo.HasFuel) { ClientLinker.Links links3 = ClientLinker.StationLinks(item4); if (links3 != null && links3.Count(LinkRole.Fuel) == 0) { Add(item4, LinkRole.Fuel, isImplicit: true); } } } } foreach (List<Strand> value2 in result.Values) { value2.Sort(Order); } return result; void Add(ZDOID other, LinkRole role, bool isImplicit) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!result.TryGetValue(other, out var value)) { value = (result[other] = new List<Strand>()); } if (!value.Exists((Strand s) => s.Role == role && s.Implicit == isImplicit)) { value.Add(new Strand { Role = role, Implicit = isImplicit }); } } } internal static void Clear() { foreach (GameObject item in Highlighted) { Unglow(item); } Highlighted.Clear(); foreach (LineRenderer line in Lines) { if ((Object)(object)line != (Object)null) { ((Renderer)line).enabled = false; } } } private static Vector3 Anchor(GameObject go) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0023: Unknown result type (might be due to invalid IL or missing references) if (AnchorCache.TryGetValue(go, out (Vector3, float) value) && Time.time - value.Item2 < 1f) { return value.Item1; } Vector3 val = ComputeAnchor(go); AnchorCache[go] = (val, Time.time); return val; } private static Vector3 ComputeAnchor(GameObject go) { //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) //IL_003b: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) Bounds? val = null; MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val2 in componentsInChildren) { if (!val.HasValue) { val = ((Renderer)val2).bounds; continue; } Bounds value = val.Value; ((Bounds)(ref value)).Encapsulate(((Renderer)val2).bounds); val = value; } if (!val.HasValue) { return go.transform.position + Vector3.up * 0.5f; } Bounds valueOrDefault = val.GetValueOrDefault(); return ((Bounds)(ref valueOrDefault)).center; } private static void Draw(int index, Vector3 from, Vector3 to, Color color, float width, bool slow) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: 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_01ab: 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_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown if ((Object)(object)_root == (Object)null) { _root = new GameObject("BudylivProduction_Links"); Object.DontDestroyOnLoad((Object)(object)_root); Lines.Clear(); Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Unlit/Color"); _material = ((!((Object)(object)val != (Object)null)) ? ((Material)null) : new Material(val)); if ((Object)(object)_material != (Object)null) { _phaseTex = (Texture2D[])(object)new Texture2D[16]; for (int i = 0; i < 16; i++) { _phaseTex[i] = MakeChevrons((float)i / 16f); } _material.mainTexture = (Texture)(object)_phaseTex[0]; ((Object)_material).hideFlags = (HideFlags)32; _slowMaterial = new Material(_material) { hideFlags = (HideFlags)32 }; } } while (Lines.Count <= index) { GameObject val2 = new GameObject("link"); val2.transform.SetParent(_root.transform, false); LineRenderer val3 = val2.AddComponent<LineRenderer>(); val3.positionCount = 2; val3.useWorldSpace = true; val3.startWidth = 0.08f; val3.endWidth = 0.08f; val3.numCapVertices = 0; val3.textureMode = (LineTextureMode)1; val3.textureScale = new Vector2(4.5454545f, 1f); ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val3).receiveShadows = false; Lines.Add(val3); } LineRenderer val4 = Lines[index]; val4.SetPosition(0, from); val4.SetPosition(1, to); Color val5 = color; if (val5.a > 0.9f) { val5.a = 0.9f; } val4.startColor = val5; val4.endColor = val5; val4.startWidth = 0.08f * width; val4.endWidth = 0.08f * width; Material val6 = (slow ? _slowMaterial : _material); if ((Object)(object)val6 != (Object)null && (Object)(object)((Renderer)val4).sharedMaterial != (Object)(object)val6) { ((Renderer)val4).sharedMaterial = val6; } ((Renderer)val4).enabled = true; } private static void Animate() { if (_phaseTex != null) { float num = Mathf.Max(0f, Plugin.LinkFlowSpeed.Value) / 0.22f; _phase = Mathf.Repeat(_phase + num * Time.deltaTime, 1f); _slowPhase = Mathf.Repeat(_slowPhase + num * 0.5f * Time.deltaTime, 1f); _material.mainTexture = (Texture)(object)_phaseTex[(int)(_phase * 16f) % 16]; _slowMaterial.mainTexture = (Texture)(object)_phaseTex[(int)(_slowPhase * 16f) % 16]; } } private static Texture2D MakeChevrons(float phase) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_002d: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(32, 16, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1, hideFlags = (HideFlags)32, name = "BudylivProduction_Chevrons" }; Color32[] array = (Color32[])(object)new Color32[512]; for (int i = 0; i < 16; i++) { float num = Mathf.Abs(((float)i + 0.5f) / 16f - 0.5f) * 2f; for (int j = 0; j < 32; j++) { float num2 = Mathf.Repeat(((float)j + 0.5f) / 32f - phase + 0.45f * num, 1f); float num3 = 1f - Mathf.Clamp01((Mathf.Abs(num2 - 0.55f) - 0.13f) / (3f / 64f)); float num4 = 1f - Mathf.Clamp01((num - 0.85f) / 0.15f); float num5 = Mathf.Max(0.3f, num3) * num4; array[i * 32 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)Mathf.RoundToInt(num5 * 255f)); } } val.SetPixels32(array); val.Apply(false, true); return val; } private static void Glow(GameObject go, List<Strand> strands) { //IL_0094: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)MaterialMan.instance == (Object)null) && strands.Count != 0) { Color val; if (strands.Count == 1) { val = RoleColor(strands[0].Role) * (strands[0].Implicit ? 0.6f : 1f); } else { float num = Time.time * 1.5f; int num2 = Mathf.FloorToInt(num) % strands.Count; float num3 = Mathf.SmoothStep(0f, 1f, num - Mathf.Floor(num)); Color val2 = RoleColor(strands[num2].Role) * (strands[num2].Implicit ? 0.6f : 1f); Strand strand = strands[(num2 + 1) % strands.Count]; Color val3 = RoleColor(strand.Role) * (strand.Implicit ? 0.6f : 1f); val = Color.Lerp(val2, val3, num3); } float num4 = 0.35f + 0.15f * Mathf.Sin(Time.time * 4f); MaterialMan.instance.SetValue<Color>(go, EmissionId, val * num4, false); Highlighted.Add(go); } } private static void Unglow(GameObject go) { if ((Object)(object)go != (Object)null && (Object)(object)MaterialMan.instance != (Object)null) { MaterialMan.instance.ResetValue(go, EmissionId); } } } internal enum LinkRole { Input, Fuel, Output } internal enum LinkOp { Link = 1, Unlink, Info, UnlinkAll, ChestInfo, ChestUnlinkAll, NearInfo } internal static class Net { internal const int Protocol = 4; internal const int TextFeature = 1; internal const string RequestRpc = "BudylivProduction_Request"; internal const string MessageRpc = "BudylivProduction_Message"; internal const string TextRpc = "BudylivProduction_Text"; internal const string CountsRpc = "BudylivProduction_Links"; internal const string NearRpc = "BudylivProduction_Near"; private static ZRoutedRpc _registeredOn; private static readonly Dictionary<long, bool> TextPeers = new Dictionary<long, bool>(); internal static void Register() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && instance != _registeredOn) { _registeredOn = instance; instance.Register<ZPackage>("BudylivProduction_Request", (Action<long, ZPackage>)OnRequest); instance.Register<string>("BudylivProduction_Message", (Action<long, string>)OnMessage); instance.Register<ZPackage>("BudylivProduction_Text", (Action<long, ZPackage>)OnText); instance.Register<ZPackage>("BudylivProduction_Links", (Action<long, ZPackage>)OnCounts); instance.Register<ZPackage>("BudylivProduction_Near", (Action<long, ZPackage>)OnNear); } } internal static void SendRequest(LinkOp op, ZDOID station, ZDOID chest, LinkRole role) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //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) ZPackage val = new ZPackage(); val.Write(4); val.Write((int)op); val.Write(station); val.Write(chest); val.Write((int)role); val.Write(1); ZRoutedRpc.instance.InvokeRoutedRPC("BudylivProduction_Request", new object[1] { val }); } internal static void SendMessage(long peer, string key, params string[] args) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown bool value; if (peer == ZDOMan.GetSessionID()) { object[] args2 = args; ClientLinker.Show(L.T(key, args2)); } else if (TextPeers.TryGetValue(peer, out value) && value) { ZPackage val = new ZPackage(); val.Write(key); val.Write(args.Length); foreach (string text in args) { val.Write(text ?? ""); } ZRoutedRpc.instance.InvokeRoutedRPC(peer, "BudylivProduction_Text", new object[1] { val }); } else { ZRoutedRpc instance = ZRoutedRpc.instance; object[] array = new object[1]; object[] args2 = args; array[0] = L.Format(ukrainian: true, key, args2); instance.InvokeRoutedRPC(peer, "BudylivProduction_Message", array); } } internal static void SendLinks(long peer, bool chest, ZDOID id, List<ZDOID>[] lists) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (peer == ZDOMan.GetSessionID()) { ClientLinker.SetLinks(chest, id, lists); return; } ZPackage val = new ZPackage(); val.Write(chest); val.Write(id); foreach (List<ZDOID> list in lists) { val.Write(list.Count); foreach (ZDOID item in list) { val.Write(item); } } ZRoutedRpc.instance.InvokeRoutedRPC(peer, "BudylivProduction_Links", new object[1] { val }); } internal static void SendNearLinks(long peer, List<(ZDOID Station, List<ZDOID>[] Lists)> stations) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0034: 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_0072: Unknown result type (might be due to invalid IL or missing references) if (peer == ZDOMan.GetSessionID()) { ClientLinker.SetNearLinks(stations); return; } ZPackage val = new ZPackage(); val.Write(stations.Count); foreach (var station in stations) { val.Write(station.Station); List<ZDOID>[] item = station.Lists; foreach (List<ZDOID> list in item) { val.Write(list.Count); foreach (ZDOID item2 in list) { val.Write(item2); } } } ZRoutedRpc.instance.InvokeRoutedRPC(peer, "BudylivProduction_Near", new object[1] { val }); } private static void OnNear(long sender, ZPackage pkg) { //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_0092: 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 (!FromServer(sender)) { return; } try { int num = pkg.ReadInt(); if (num < 0 || num > 5000) { return; } List<(ZDOID, List<ZDOID>[])> list = new List<(ZDOID, List<ZDOID>[])>(num); for (int i = 0; i < num; i++) { ZDOID item = pkg.ReadZDOID(); List<ZDOID>[] array = new List<ZDOID>[3]; for (int j = 0; j < 3; j++) { int num2 = pkg.ReadInt(); if (num2 < 0 || num2 > 1000) { return; } array[j] = new List<ZDOID>(num2); for (int k = 0; k < num2; k++) { array[j].Add(pkg.ReadZDOID()); } } list.Add((item, array)); } ClientLinker.SetNearLinks(list); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Bad near-links package: " + ex.Message)); } } private static bool FromServer(long sender) { if ((Object)(object)ZNet.instance == (Object)null) { return false; } long num = (ZNet.instance.IsServer() ? ZDOMan.GetSessionID() : (ZNet.instance.GetServerPeer()?.m_uid ?? 0)); return sender == num; } private static void OnCounts(long sender, ZPackage pkg) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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) if (!FromServer(sender)) { return; } try { bool chest = pkg.ReadBool(); ZDOID id = pkg.ReadZDOID(); List<ZDOID>[] array = new List<ZDOID>[3]; for (int i = 0; i < 3; i++) { int num = pkg.ReadInt(); if (num < 0 || num > 1000) { return; } array[i] = new List<ZDOID>(num); for (int j = 0; j < num; j++) { array[i].Add(pkg.ReadZDOID()); } } ClientLinker.SetLinks(chest, id, array); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Bad counts package: " + ex.Message)); } } private static void OnRequest(long sender, ZPackage pkg) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_00c4: 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) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } try { int num = pkg.ReadInt(); if (num != 4) { TextPeers.Remove(sender); SendMessage(sender, "srv.version", num.ToString(), 4.ToString()); return; } LinkOp op = (LinkOp)pkg.ReadInt(); ZDOID stationId = pkg.ReadZDOID(); ZDOID chestId = pkg.ReadZDOID(); LinkRole role = (LinkRole)pkg.ReadInt(); int num2 = ((pkg.GetPos() < pkg.Size()) ? pkg.ReadInt() : 0); TextPeers[sender] = (num2 & 1) != 0; if (TextPeers.Count > 256) { TextPeers.Clear(); } ServerEngine.HandleRequest(sender, op, stationId, chestId, role); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Bad request from " + sender + ": " + ex.Message)); } } private static void OnText(long sender, ZPackage pkg) { if (!FromServer(sender)) { return; } try { string key = pkg.ReadString(); int num = pkg.ReadInt(); if (num >= 0 && num <= 16) { object[] array = new object[num]; for (int i = 0; i < num; i++) { array[i] = pkg.ReadString(); } ClientLinker.Show(L.T(key, array)); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Bad text package: " + ex.Message)); } } private static void OnMessage(long sender, string text) { if (FromServer(sender)) { ClientLinker.Show(text); } } } [BepInPlugin("com.budyliv.production", "Budyliv Production", "1.2.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.budyliv.production"; public const string Name = "Budyliv Production"; public const string Version = "1.2.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> TickSeconds; internal static ConfigEntry<float> ClaimWaitSeconds; internal static ConfigEntry<float> QuietSeconds; internal static ConfigEntry<float> MaxLinkRange; internal static ConfigEntry<float> RefillFraction; internal static ConfigEntry<float> DeliveryCooldownSeconds; internal static ConfigEntry<float> OutputRadius; internal static ConfigEntry<float> MinDropAgeSeconds; internal static ConfigEntry<float> OutputScanSeconds; internal static ConfigEntry<float> FullRetrySeconds; internal static ConfigEntry<int> RevisionBump; internal static ConfigEntry<bool> VerboseLogging; internal static ConfigEntry<string> Language; internal static ConfigEntry<bool> ShowControlHints; internal static ConfigEntry<bool> ShowLinkLines; internal static ConfigEntry<float> LinkFlowSpeed; internal static ConfigEntry<KeyboardShortcut> ShowAllLinksKey; private Harmony _harmony; internal static void Verbose(string text) { if (VerboseLogging != null && VerboseLogging.Value) { Log.LogInfo((object)text); } } private void Awake() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Expected O, but got Unknown //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Expected O, but got Unknown //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Expected O, but got Unknown //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Expected O, but got Unknown //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Expected O, but got Unknown //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Expected O, but got Unknown //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "Enabled", true, "Server: run automatic fuel/input/output for linked stations."); TickSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "TickSeconds", 2f, new ConfigDescription("Server: how often stations are checked.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>())); ClaimWaitSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "ClaimWaitSeconds", 0.5f, new ConfigDescription("Server: after taking a chest/drop over, wait this long for in-flight player changes before editing it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 5f), Array.Empty<object>())); QuietSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "QuietSeconds", 2f, new ConfigDescription("Server: a chest whose contents changed within this time is left alone this tick.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); MaxLinkRange = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "MaxLinkRange", 30f, new ConfigDescription("Server: maximum station-chest distance for a link (m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); RefillFraction = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "RefillFraction", 0.5f, new ConfigDescription("Server: refill fuel/input when at least this fraction of capacity is free (or it ran out). Bigger = fewer, larger transfers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); DeliveryCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "DeliveryCooldownSeconds", 5f, new ConfigDescription("Server: after a delivery, wait this long for the station owner to report the new state.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); OutputRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "OutputRadius", 2f, new ConfigDescription("Server: products lying within this distance of a station's output point go to its output chest (m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>())); MinDropAgeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "MinDropAgeSeconds", 0.2f, new ConfigDescription("Server: only collect products at least this old.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); OutputScanSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "OutputScanSeconds", 0.5f, new ConfigDescription("Server: how often products near stations are looked for (faster than TickSeconds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 10f), Array.Empty<object>())); FullRetrySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "FullRetrySeconds", 5f, new ConfigDescription("Server: a full output chest is skipped this long (or until a player changes it); the next output chest is used meanwhile.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f), Array.Empty<object>())); RevisionBump = ((BaseUnityPlugin)this).Config.Bind<int>("Server", "RevisionBump", 10, new ConfigDescription("Server: extra data revisions added to a chest the server writes, so a late player write cannot leave server and client with different contents.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>())); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "VerboseLogging", false, "Server: also log every transfer and station type (for debugging). Links, unlinks and problems are always logged."); Language = ((BaseUnityPlugin)this).Config.Bind<string>("Client", "Language", "Auto", new ConfigDescription("Client: language of hints and messages. Auto = Ukrainian when the game is in Ukrainian, English otherwise.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Auto", "English", "Ukrainian" }), Array.Empty<object>())); ShowControlHints = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "ShowControlHints", true, "Client: show link gestures (Alt+mouse) and linked chest counts on station and chest hover text."); ShowLinkLines = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "ShowLinkLines", true, "Client: while Alt is held over a station or chest, draw lines to its linked chests/stations and make them glow (blue input, orange fuel, green output)."); LinkFlowSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Client", "LinkFlowSpeed", 0.6f, new ConfigDescription("Client: how fast the arrows on link lines move toward where the items go (chest to station for input and fuel, station to chest for output), in metres per second. 0 = arrows stand still.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); ShowAllLinksKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Client", "ShowAllLinksKey", new KeyboardShortcut((KeyCode)281, Array.Empty<KeyCode>()), "Client: toggles showing every link around you at once (lines and glow, no Alt needed)."); _harmony = new Harmony("com.budyliv.production"); _harmony.PatchAll(); Log.LogInfo((object)"Budyliv Production 1.2.0 loaded."); } private void Update() { if ((Object)(object)ZNet.instance == (Object)null) { return; } try { if (ZNet.instance.IsServer()) { ServerEngine.Tick(); } if ((Object)(object)Player.m_localPlayer != (Object)null) { ClientLinker.Update(); LinkVisuals.Update(); } else { LinkVisuals.Clear(); } } catch (Exception ex) { Log.LogError((object)("Update failed: " + ex)); } } private void OnDestroy() { ServerEngine.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class ZNet_Awake_Patch { private static void Postfix() { Net.Register(); } } [HarmonyPatch(typeof(ZDOMan), "ReleaseZDOS")] internal static class ZDOMan_ReleaseZDOS_Patch { private static void Prefix() { ServerEngine.BeforeVanillaRelease(); } private static void Postfix() { ServerEngine.AfterVanillaRelease(); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal static class ZNet_Shutdown_Patch { private static void Prefix() { ServerEngine.Shutdown(); } } internal static class ServerEngine { private sealed class Claim { public ZDOID Id; public long PrevOwner; public float At; public ZDOID Station; public ZDOID Chest; } private sealed class OutChest { public ZDO Zdo; public bool Full; public bool Usable; private Inventory _inv; private bool _read; public Inventory Inv { get { if (!_read) { _read = true; _inv = ReadInventory(Zdo); } return _inv; } } } private sealed class Consumer { public StationLinks Links; public ZDO Station; public StationInfo Info; public long Owner; public float Level; public float Capacity; public int StartRoom; public List<string> Accepts; public int Given; public readonly Dictionary<string, int> Items = new Dictionary<string, int>(); public float Fill => (Level + (float)Given) / Capacity; public int Room => StartRoom - Given; } private static readonly Dictionary<ZDOID, Claim> ChestClaims = new Dictionary<ZDOID, Claim>(); private static readonly Dictionary<ZDOID, Claim> DropClaims = new Dictionary<ZDOID, Claim>(); private static readonly Dictionary<ZDOID, float> FuelReady = new Dictionary<ZDOID, float>(); private static readonly Dictionary<ZDOID, float> InputReady = new Dictionary<ZDOID, float>(); private static readonly Dictionary<ZDOID, float> PullReady = new Dictionary<ZDOID, float>(); private static readonly Dictionary<(ZDOID, LinkRole), (float MinLevel, float Until)> InFlight = new Dictionary<(ZDOID, LinkRole), (float, float)>(); private static readonly Dictionary<ZDOID, (uint Rev, float Until)> ChestFull = new Dictionary<ZDOID, (uint, float)>(); private static readonly Dictionary<ZDOID, (uint Rev, float ChangedAt)> ChestActivity = new Dictionary<ZDOID, (uint, float)>(); private static float _nextPlan; private static float _nextOutput; private static string _world; private const float NearRadius = 80f; private static readonly Dictionary<ZDOID, float> MissingSince = new Dictionary<ZDOID, float>(); private static float _nextSweep; private static readonly Dictionary<ZDOID, float> WispPicked = new Dictionary<ZDOID, float>(); private static readonly List<ZDO> HeldBeforeRelease = new List<ZDO>(); private static long Self => ZDOMan.GetSessionID(); private static void Verbose(string text) { Plugin.Verbose(text); } internal static void Tick() { if (!Plugin.Enabled.Value || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } string worldName = ZNet.instance.GetWorldName(); if (string.IsNullOrEmpty(worldName)) { return; } if (_world != worldName) { if (ZDOMan.instance.NrOfObjects() == 0) { return; } ReleaseAll(); LinkStore.Unload(); LinkStore.Load(worldName); _world = worldName; _nextPlan = (_nextOutput = Time.time + 10f); } float time = Time.time; ExecuteReadyChests(time); if (time >= _nextPlan) { _nextPlan = time + Plugin.TickSeconds.Value; _nextOutput = time + Plugin.OutputScanSeconds.Value; ExpireClaims(time); SweepDestroyed(time); Plan(time, supplies: true); } else if (time >= _nextOutput) { _nextOutput = time + Plugin.OutputScanSeconds.Value; Plan(time, supplies: false); } LinkStore.SaveIfDirty(); } internal static void Shutdown() { try { ReleaseAll(); LinkStore.Unload(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Shutdown cleanup failed: " + ex.Message)); } } _world = null; } private static void ReleaseAll() { if (ZDOMan.instance != null) { foreach (Claim item in ChestClaims.Values.ToList()) { Release(item); } foreach (Claim item2 in DropClaims.Values.ToList()) { Release(item2); } } ChestClaims.Clear(); DropClaims.Clear(); } private static string RoleArg(LinkRole role) { return L.Ref(L.RoleKey(role)); } private static string Num(float v) { return v.ToString("0", CultureInfo.InvariantCulture); } internal static void HandleRequest(long sender, LinkOp op, ZDOID stationId, ZDOID chestId, LinkRole role) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) bool flag = op == LinkOp.Info || op == LinkOp.ChestInfo || op == LinkOp.NearInfo; if (!LinkStore.Loaded) { if (!flag) { Net.SendMessage(sender, "srv.loading"); } return; } switch (op) { case LinkOp.NearInfo: SendNearLinks(sender); return; case LinkOp.ChestInfo: case LinkOp.ChestUnlinkAll: HandleChestRequest(sender, op, chestId); return; } ZDO zDO = ZDOMan.instance.GetZDO(stationId); StationInfo stationInfo = ((zDO != null) ? Stations.Get(zDO.GetPrefab()) : null); if (stationInfo == null) { if (!flag) { Net.SendMessage(sender, "srv.unsupported"); } return; } switch (op) { case LinkOp.Info: SendStationLinks(sender, stationId); return; case LinkOp.UnlinkAll: { int num = 0; if (LinkStore.All.TryGetValue(stationId, out var value)) { num = value.Chests.Sum((List<ZDOID> list) => list.Count); } LinkStore.RemoveStation(stationId); if (num > 0) { Net.SendMessage(sender, "srv.unlinked_all", num.ToString()); } else { Net.SendMessage(sender, "srv.no_links"); } if (num > 0) { Plugin.Log.LogInfo((object)$"Unlink all ({num}) station {stationInfo.Prefab} {stationId} by {sender}"); } SendStationLinks(sender, stationId); return; } } ZDO zDO2 = ZDOMan.instance.GetZDO(chestId); object obj; if (zDO2 == null) { obj = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab(zDO2.GetPrefab()); obj = ((prefab != null) ? prefab.GetComponent<Container>() : null); } if ((Object)obj == (Object)null) { Net.SendMessage(sender, "srv.not_chest"); return; } if (op == LinkOp.Unlink) { bool flag2 = LinkStore.Remove(stationId, role, chestId); Net.SendMessage(sender, flag2 ? "srv.unlinked" : "srv.was_not_linked", RoleArg(role)); if (flag2) { Plugin.Log.LogInfo((object)$"Unlink {role} station {stationInfo.Prefab} {stationId} chest {chestId} by {sender}"); } SendStationLinks(sender, stationId); return; } if (!stationInfo.Has(role)) { Net.SendMessage(sender, "srv.no_role", L.Ref(stationInfo.KindKey), RoleArg(role)); return; } float num2 = Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition()); if (num2 > Plugin.MaxLinkRange.Value) { Net.SendMessage(sender, "srv.too_far", Num(num2), Num(Plugin.MaxLinkRange.Value)); return; } bool flag3 = LinkStore.Add(zDO, role, zDO2); StationLinks value2; bool flag4 = flag3 && stationInfo.Kind == StationKind.Cooking && role == LinkRole.Input && LinkStore.All.TryGetValue(stationId, out value2) && value2.Of(LinkRole.Output).Count == 0; if (flag3) { Net.SendMessage(sender, flag4 ? "srv.linked_cooking" : "srv.linked", RoleArg(role), Num(num2)); } else { Net.SendMessage(sender, "srv.already_linked", RoleArg(role)); } if (flag3) { Plugin.Log.LogInfo((object)$"Link {role} station {stationInfo.Prefab} {stationId} chest {chestId} ({num2:0.0} m) by {sender}"); } SendStationLinks(sender, stationId); } private static void SendStationLinks(long peer, ZDOID stationId) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) LinkStore.All.TryGetValue(stationId, out var value); List<ZDOID>[] array = new List<ZDOID>[3]; for (int i = 0; i < 3; i++) { array[i] = ((value != null) ? value.Chests[i].ToList() : new List<ZDOID>()); } Net.SendLinks(peer, chest: false, stationId, array); } private static void SendNearLinks(long peer) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_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_0054: 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_00a7: Unknown result type (might be due to invalid IL or missing references) Vector3 val; if (peer == Self) { val = ZNet.instance.GetReferencePosition(); } else { ZNetPeer peer2 = ZNet.instance.GetPeer(peer); if (peer2 == null) { return; } val = peer2.m_refPos; } List<(ZDOID, List<ZDOID>[])> list = new List<(ZDOID, List<ZDOID>[])>(); foreach (StationLinks value in LinkStore.All.Values) { ZDO zDO = ZDOMan.instance.GetZDO(value.Station); if (zDO != null && !(Vector3.Distance(zDO.GetPosition(), val) > 80f)) { List<ZDOID>[] array = new List<ZDOID>[3]; for (int i = 0; i < 3; i++) { array[i] = value.Chests[i].ToList(); } list.Add((value.Station, array)); } } Net.SendNearLinks(peer, list); } private static void SendChestLinks(long peer, ZDOID chestId) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) List<ZDOID>[] array = new List<ZDOID>[3] { new List<ZDOID>(), new List<ZDOID>(), new List<ZDOID>() }; foreach (StationLinks value in LinkStore.All.Values) { for (int i = 0; i < 3; i++) { if (value.Chests[i].Contains(chestId)) { array[i].Add(value.Station); } } } Net.SendLinks(peer, chest: true, chestId, array); } private static void HandleChestRequest(long sender, LinkOp op, ZDOID chestId) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (op == LinkOp.ChestInfo) { SendChestLinks(sender, chestId); return; } int num = LinkStore.All.Values.Count((StationLinks l) => l.Chests.Any((List<ZDOID> list) => list.Contains(chestId))); if (num > 0) { LinkStore.RemoveChestEverywhere(chestId); Plugin.Log.LogInfo((object)$"Unlink chest {chestId} from all {num} stations by {sender}"); } if (num > 0) { Net.SendMessage(sender, "srv.chest_unlinked_all", num.ToString()); } else { Net.SendMessage(sender, "srv.chest_not_linked"); } SendChestLinks(sender, chestId); } private static void SweepDestroyed(float now) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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_016c: Unknown result type (might be due to invalid IL or missing references) if (now < _nextSweep) { return; } _nextSweep = now + 10f; LinkStore.RetryUnresolved(); HashSet<ZDOID> hashSet = new HashSet<ZDOID>(); foreach (StationLinks item in LinkStore.All.Values.ToList()) { foreach (ZDOID item2 in ((IEnumerable<ZDOID>)(object)new ZDOID[1] { item.Station }).Concat(item.Chests.SelectMany((List<ZDOID> l) => l)).ToList()) { if (!hashSet.Add(item2)) { continue; } float value; if (ZDOMan.instance.GetZDO(item2) != null) { MissingSince.Remove(item2); } else if (!MissingSince.TryGetValue(item2, out value)) { MissingSince[item2] = now; } else { if (now - value < 30f) { continue; } MissingSince.Remove(item2); if (item2 == item.Station && LinkStore.All.ContainsKey(item2)) { int num = LinkStore.All[item2].Chests.Sum((List<ZDOID> l) => l.Count); LinkStore.RemoveStation(item2); Plugin.Log.LogInfo((object)$"Station {item2} is gone (destroyed): removed its {num} links."); } else { LinkStore.RemoveChestEverywhere(item2); Plugin.Log.LogInfo((object)$"Chest {item2} is gone (destroyed): removed it from all stations."); } } } } } private static void Plan(float now, bool supplies) { //IL_00ac: 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) Dictionary<Vector2s, List<ZDO>> zoneCache = new Dictionary<Vector2s, List<ZDO>>(); foreach (StationLinks item in LinkStore.All.Values.ToList()) { if (!supplies && item.Of(LinkRole.Output).Count == 0) { continue; } ZDO zDO = ZDOMan.instance.GetZDO(item.Station); if (zDO == null) { continue; } long owner = zDO.GetOwner(); if (owner == 0L || !Online(owner)) { continue; } StationInfo stationInfo = Stations.Get(zDO.GetPrefab()); if (stationInfo == null) { continue; } try { if (supplies) { PlanSupply(item, zDO, stationInfo, LinkRole.Fuel, now); PlanSupply(item, zDO, stationInfo, LinkRole.Input, now); } PlanOutput(item, zDO, stationInfo, owner, now, zoneCache); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"Planning failed for station {item.Station}: {arg}"); } } } private static List<ZDOID> Sources(StationLinks links, LinkRole role) { if (role == LinkRole.Input) { return links.Of(LinkRole.Input); } if (links.Of(LinkRole.Fuel).Count <= 0) { return links.Of(LinkRole.Input); } return links.Of(LinkRole.Fuel); } private static Dictionary<ZDOID, float> ReadyMap(LinkRole role) { if (role != LinkRole.Fuel) { return InputReady; } return FuelReady; } private static bool Settled(ZDOID station, LinkRole role, float level, float now) { //IL_0005: 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) if (!InFlight.TryGetValue((station, role), out (float, float) value)) { return true; } if (level >= value.Item1 || now >= value.Item2) { InFlight.Remove((station, role)); return true; } return false; } private static bool Eager(StationInfo info, LinkRole role) { return role switch { LinkRole.Fuel => info.EagerFuel, LinkRole.Input => info.EagerInput, _ => false, }; } private static int MinRoom(StationInfo info, LinkRole role, float capacity) { if (!Eager(info, role)) { return Math.Max(1, Mathf.CeilToInt(capacity * Plugin.RefillFraction.Value * 0.5f)); } return 1; } private static void PlanSupply(StationLinks links, ZDO station, StationInfo info, LinkRole role, float now) { //IL_0010: 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) if (!info.Has(role) || !Ready(ReadyMap(role), links.Station, now)) { return; } List<ZDOID> list = Sources(links, role); if (list.Count == 0) { return; } int num; float num2; float num3; IList<string> list2; if (role == LinkRole.Fuel) { num = info.FuelRoom(station); num2 = info.FuelLevel(station); num3 = info.FuelCapacity; list2 = info.FuelNames; } else { num = info.InputRoom(station); num2 = info.InputLevel(station); num3 = info.InputCapacity; list2 = info.InputAccepts(station); } if (num > 0 && list2.Count != 0 && Settled(links.Station, role, num2, now)) { bool num4 = Eager(info, role); int num5 = Math.Max(1, Mathf.CeilToInt(num3 * Plugin.RefillFraction.Value)); if (num4 || num >= num5 || !(num2 > 0f)) { ClaimSourceWith(list, list2, now); } } } private static void ClaimSourceWith(List<ZDOID> chests, IList<string> wanted, float now) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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) foreach (ZDOID chest in chests) { if (ChestClaims.ContainsKey(chest)) { break; } ZDO zDO = ZDOMan.instance.GetZDO(chest); if (zDO != null && CanClaim(zDO, now)) { Inventory inv = ReadInventory(zDO); if (inv != null && wanted.Any((string name) => Count(inv, name) > 0)) { ClaimChest(zDO, now); break; } } } } private static bool MarkedFull(ZDO chest, float now) { //IL_0006: 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) if (!ChestFull.TryGetValue(chest.m_uid, out (uint, float) value)) { return false; } if (value.Item1 != chest.DataRevision || now >= value.Item2) { ChestFull.Remove(chest.m_uid); return false; } return true; } private static void PlanOutput(StationLinks links, ZDO station, StationInfo info, long owner, float now, Dictionary<Vector2s, List<ZDO>> zoneCache) { //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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) if (links.Of(LinkRole.Output).Count == 0 || !info.HasOutput) { return; } List<OutChest> list = new List<OutChest>(); foreach (ZDOID item in links.Of(LinkRole.Output)) { ZDO zDO = ZDOMan.instance.GetZDO(item); if (zDO != null) { bool flag = MarkedFull(zDO, now); list.Add(new OutChest { Zdo = zDO, Full = flag, Usable = (!flag && (ChestClaims.ContainsKey(item) || CanClaim(zDO, now))) }); } } if (list.Count == 0) { return; } bool flag2 = list.Any((OutChest c) => !c.Full); int num = info.PullCount(station); if (num > 0 && Ready(PullReady, links.Station, now) && (info.Kind == StationKind.Cooking || flag2)) { PullReady[links.Station] = now + info.PullCooldown; Vector3 position = (list.FirstOrDefault((OutChest c) => c.Usable) ?? list[0]).Zdo.GetPosition(); info.Pull(owner, station, num, position); Verbose($"Pull x{num} -> {info.Prefab} {links.Station}"); } if (info.Kind == StationKind.Wisp && flag2 && Ready(PullReady, links.Station, now)) { PullReady[links.Station] = now + info.PullCooldown; PickWisps(links, station, info, now, zoneCache); } ClaimAwaitedChests(links.Station, now); if (!list.Any((OutChest c) => c.Usable)) { return; } foreach (ZDO item2 in FindDrops(station, info, zoneCache)) { ItemData val = LoadDropItem(item2); if (val == null) { continue; } OutChest outChest = PickOutputChest(list, val); if (outChest == null) { continue; } if (!outChest.Usable) { Verbose($"{((Object)val.m_dropPrefab).name} from {info.Prefab} {links.Station} waits for chest {outChest.Zdo.m_uid} that already holds it (busy)."); continue; } outChest.Inv.AddItem(val); if (!ChestClaims.ContainsKey(outChest.Zdo.m_uid)) { ClaimChest(outChest.Zdo, now); } long owner2 = item2.GetOwner(); if (owner2 != Self) { item2.SetOwner(Self); } DropClaims[item2.m_uid] = new Claim { Id = item2.m_uid, PrevOwner = owner2, At = now, Station = links.Station, Chest = outChest.Zdo.m_uid }; } } private static OutChest PickOutputChest(List<OutChest> chests, ItemData item) { string name = ((Object)item.m_dropPrefab).name; foreach (OutChest chest in chests) { if (!chest.Full && chest.Inv != null && Count(chest.Inv, name) > 0 && chest.Inv.CanAddItem(item, -1)) { return chest; } } foreach (OutChest chest2 in chests) { if (chest2.Usable && chest2.Inv != null && chest2.Inv.CanAddItem(item, -1)) { return chest2; } } return null; } private static void ClaimAwaitedChests(ZDOID station, float now) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) foreach (ZDOID item in (from d in DropClaims.Values where d.Station == station && !ChestClaims.ContainsKey(d.Chest) select d.Chest).Distinct().ToList()) { ZDO zDO = ZDOMan.instance.GetZDO(item); if (zDO != null && CanClaim(zDO, now)) { ClaimChest(zDO, now); } } } private static void PickWisps(StationLinks links, ZDO station, StationInfo info, float now, Dictionary<Vector2s, List<ZDO>> zoneCache) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_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_0049: 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_0058: 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_0070: 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_00cd: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) Vector3 val = info.OutputPoint(station); float wispRadius = info.WispRadius; foreach (ZDO item in Nearby(val, wispRadius, zoneCache)) { if (item.GetPrefab() != info.WispHash) { continue; } Vector3 val2 = item.GetPosition() - val; if (!(val2.x * val2.x + val2.z * val2.z > wispRadius * wispRadius) && !(Mathf.Abs(val2.y) > wispRadius) && (!WispPicked.TryGetValue(item.m_uid, out var value) || !(now < value))) { long owner = item.GetOwner(); if (owner != 0L && owner != Self && Online(owner)) { ZRoutedRpc.instance.InvokeRoutedRPC(owner, item.m_uid, "RPC_Pick", new object[1] { 0 }); WispPicked[item.m_uid] = now + 10f; Verbose($"Pick wisp {item.m_uid} (owner {owner}) at {info.Prefab} {links.Station}"); } } } } private static IEnumerable<ZDO> Nearby(Vector3 pos, float radius, Dictionary<Vector2s, List<ZDO>> zoneCache) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (!Zdos.Available) { yield break; } HashSet<Vector2s> hashSet = new HashSet<Vector2s>(); for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { hashSet.Add(ZoneSystem.GetZone(pos + new Vector3((float)i * radius, 0f, (float)j * radius))); } } foreach (Vector2s item in hashSet) { if (!zoneCache.TryGetValue(item, out var value)) { value = new List<ZDO>(); Zdos.InZone(item, value); zoneCache[item] = value; } foreach (ZDO item2 in value) { yield return item2; } } } private static List<ZDO> FindDrops(ZDO station, StationInfo info, Dictionary<Vector2s, List<ZDO>> zoneCache) { //IL_0008: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_009c: 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_00ab: 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_00c9: Unknown result type (