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 QuestHeim v0.0.1
QuestHeim/QuestHeim.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HeaveHo.Shared; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using QuestHeim.Shared; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [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 HeaveHo.Shared { internal sealed class ServerSettings : IDisposable { public enum ServerMod { NotConnected, Checking, Installed, Missing } private sealed class ConfigurationManagerAttributes { public bool? ReadOnly; } private sealed class SyncedText { public string Key; public Func<string> Own; public Action<string> Use; public string Given; public bool FromServer; public bool Pending; public byte[] Packed; public bool TooBig; public MemoryStream Incoming; public int NextPart; } private sealed class Sending { public ZRpc Rpc; public string Key; public byte[] Data; public int Next; public int Parts; } private const int Protocol = 2; private const float ChangeSendGap = 0.5f; private const float AnswerWait = 20f; private const float FileWait = 1f; private const int PartSize = 65536; private const int CompressFrom = 1024; private const int WarnBytes = 262144; private const int MaxBytes = 8388608; private const int PaceBelow = 10240; private readonly string _send; private readonly string _ask; private readonly string _dAsk; private readonly string _dHello; private readonly string _dSend; private readonly string _edit; private readonly string _dTextAsk; private readonly string _dText; private readonly string _dAgain; private readonly ConfigFile _config; private readonly ManualLogSource _log; private readonly string _name; private readonly List<ConfigEntryBase> _entries = new List<ConfigEntryBase>(); private readonly Dictionary<ConfigEntryBase, object> _own = new Dictionary<ConfigEntryBase, object>(); private readonly Dictionary<ConfigEntryBase, object> _server = new Dictionary<ConfigEntryBase, object>(); private readonly List<GameObject> _guardedPieces = new List<GameObject>(); private readonly List<Recipe> _guardedRecipes = new List<Recipe>(); private ZRoutedRpc _registeredOn; private bool _applying; private bool _reloading; private bool _changePending; private float _nextChangeSend; private float _askedAt = -1f; private int _serverProtocol; private bool _directSeen; private readonly HashSet<ZRpc> _directPeers = new HashSet<ZRpc>(); private readonly List<SyncedText> _texts = new List<SyncedText>(); private readonly Dictionary<ZRpc, HashSet<string>> _textPeers = new Dictionary<ZRpc, HashSet<string>>(); private bool _textPending; private float _nextTextSend; private bool _readOnlyShown; private float _nextAdminCheck; private FileSystemWatcher _watcher; private volatile bool _fileTouched; private float _reloadAt = -1f; private string _fileText; private ZRpc _adminConnection; private readonly List<Sending> _outbox = new List<Sending>(); private static readonly MethodInfo UpdateAvailablePieces = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null); private static readonly List<ServerSettings> Live = new List<ServerSettings>(); private static Harmony _saveHarmony; public string Version { get; } public bool FromServer => _server.Count > 0; public ServerMod Server { get; private set; } = ServerMod.NotConnected; public string ServerVersion { get; private set; } public bool CanEditServer => IsServer || (_adminConnection != null && Server == ServerMod.Installed && _serverProtocol >= 1 && IsServerConnection(_adminConnection)); private static bool IsServer => (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer(); public event Action ServerChanged; public ServerSettings(string guid, ConfigFile config, ManualLogSource log) { _send = guid + ".settings"; _ask = guid + ".settings.ask"; _dAsk = guid + ".settings.d.ask"; _dHello = guid + ".settings.d.hello"; _dSend = guid + ".settings.d.values"; _edit = guid + ".settings.d.edit"; _dTextAsk = guid + ".settings.d.textask"; _dAgain = guid + ".settings.d.again"; _dText = guid + ".settings.d.text"; _config = config; _log = log; BepInPlugin val = PluginOf(guid); _name = ((val != null) ? val.Name : null) ?? guid; Version = ((val == null) ? null : val.Version?.ToString()) ?? ""; Live.Add(this); if (Live.Count == 1) { PatchSave(); } WatchFile(); } public ConfigEntry<T> Add<T>(ConfigEntry<T> entry) { if (entry == null || _entries.Contains((ConfigEntryBase)(object)entry)) { return entry; } _entries.Add((ConfigEntryBase)(object)entry); entry.SettingChanged += OnChanged; GiveManagerAttributes((ConfigEntryBase)(object)entry); return entry; } private static void GiveManagerAttributes(ConfigEntryBase entry) { ConfigDescription description = entry.Description; if (description == null || description == ConfigDescription.Empty || (description.Tags ?? new object[0]).Any(IsManagerAttributes)) { return; } try { object[] value = new object[1] { new ConfigurationManagerAttributes() }.Concat(description.Tags ?? new object[0]).ToArray(); AccessTools.Field(typeof(ConfigDescription), "<Tags>k__BackingField")?.SetValue(description, value); } catch (Exception) { } } public ConfigEntry<T> Bind<T>(string section, string key, T value, string description, AcceptableValueBase range = null, params object[] tags) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if (!description.Contains("[Synced with Server]")) { description += " [Synced with Server]"; } return Add<T>(_config.Bind<T>(section, key, value, new ConfigDescription(description, range, tags ?? new object[0]))); } public void NeedsServer(GameObject piecePrefab) { if (!((Object)(object)piecePrefab == (Object)null)) { _guardedPieces.RemoveAll((GameObject p) => (Object)(object)p == (Object)null || ((Object)p).name == ((Object)piecePrefab).name); _guardedPieces.Add(piecePrefab); Guard(); } } public void NeedsServer(Recipe recipe) { if (!((Object)(object)recipe == (Object)null)) { _guardedRecipes.RemoveAll((Recipe r) => (Object)(object)r == (Object)null || (Object)(object)r == (Object)(object)recipe || (!string.IsNullOrEmpty(((Object)recipe).name) && ((Object)r).name == ((Object)recipe).name)); _guardedRecipes.Add(recipe); Guard(); } } public void AddText(string key, Func<string> own, Action<string> use) { if (string.IsNullOrEmpty(key) || own == null || use == null) { ManualLogSource log = _log; if (log != null) { log.LogError((object)"AddText needs a key, own and use"); } return; } _texts.RemoveAll((SyncedText x) => x.Key == key); SyncedText syncedText = new SyncedText { Key = key, Own = own, Use = use }; _texts.Add(syncedText); Give(syncedText, OwnText(syncedText)); ZRpc val = ((!((Object)(object)ZNet.instance != (Object)null) || IsServer) ? null : ZNet.instance.GetServerPeer()?.m_rpc); if (_registeredOn != null && val != null) { val.Register<ZPackage>(_dText, (Action<ZRpc, ZPackage>)OnText); AskTexts(val); } } public void TextChanged(string key) { SyncedText syncedText = _texts.FirstOrDefault((SyncedText x) => x.Key == key); if (syncedText != null) { syncedText.Packed = null; if (!syncedText.FromServer) { Give(syncedText, OwnText(syncedText)); } if (IsServer) { syncedText.Pending = true; _textPending = true; } } } public bool TextFromServer(string key) { return _texts.Any((SyncedText x) => x.Key == key && x.FromServer); } public void Update() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != _registeredOn) { Unregister(); Restore(); RestoreTexts(give: true); _changePending = false; _textPending = false; SetServer(ServerMod.NotConnected, null, 0); if (instance != null) { Register(instance); } } float unscaledTime = Time.unscaledTime; if (_changePending && unscaledTime >= _nextChangeSend) { SendChange(); } if (_textPending && unscaledTime >= _nextTextSend) { SendTexts(); } if (_outbox.Count > 0) { Pump(); } if (Server == ServerMod.Checking && _askedAt >= 0f && unscaledTime - _askedAt > 20f) { if (_guardedPieces.Count + _guardedRecipes.Count > 0) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("The server didn't answer: " + _name + " isn't installed there (or its copy is older than 2026-10-11), so its pieces and items can't be made on this server.")); } } else { ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)("The server didn't answer: " + _name + " isn't installed there, or its copy is older" + (FromServer ? " (its settings apply)." : " (your own settings apply)."))); } } SetServer(ServerMod.Missing, null, 0); } if (_fileTouched) { _fileTouched = false; _reloadAt = unscaledTime + 1f; } if (_reloadAt >= 0f && unscaledTime >= _reloadAt) { _reloadAt = -1f; ReloadFile(); } if (FromServer && unscaledTime >= _nextAdminCheck) { _nextAdminCheck = unscaledTime + 1f; ShowReadOnly(); } } public void Dispose() { Unregister(); Restore(); RestoreTexts(give: false); SetServer(ServerMod.NotConnected, null, 0); foreach (ConfigEntryBase entry in _entries) { Unsubscribe(entry); } _entries.Clear(); _texts.Clear(); try { _watcher?.Dispose(); } catch (Exception) { } _watcher = null; Live.Remove(this); if (Live.Count == 0) { UnpatchSave(); } } private void Register(ZRoutedRpc rpc) { Forget(rpc, _send); Forget(rpc, _ask); rpc.Register<ZPackage>(_send, (Action<long, ZPackage>)OnRoutedValues); rpc.Register(_ask, (Action<long>)OnRoutedAsk); rpc.m_onNewPeer = (Action<long>)Delegate.Combine(rpc.m_onNewPeer, new Action<long>(OnNewPeer)); _registeredOn = rpc; if (IsServer) { foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { ListenTo(peer); if (peer != null) { ZRpc rpc2 = peer.m_rpc; if (rpc2 != null) { rpc2.Invoke(_dAgain, Array.Empty<object>()); } } } return; } if ((Object)(object)ZNet.instance != (Object)null) { SetServer(ServerMod.Checking, null, 0); if (ZNet.instance.GetServerPeer() != null) { AskServer(); } } } private void Unregister() { if (_registeredOn == null) { return; } ZRoutedRpc registeredOn = _registeredOn; registeredOn.m_onNewPeer = (Action<long>)Delegate.Remove(registeredOn.m_onNewPeer, new Action<long>(OnNewPeer)); Forget(_registeredOn, _send); Forget(_registeredOn, _ask); if ((Object)(object)ZNet.instance != (Object)null) { foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer?.m_rpc != null) { string[] array = new string[7] { _dAsk, _dHello, _dSend, _edit, _dTextAsk, _dText, _dAgain }; foreach (string name in array) { ForgetDirect(peer.m_rpc, name); } } } } _directPeers.Clear(); _textPeers.Clear(); _outbox.Clear(); _directSeen = false; _registeredOn = null; } private static void Forget(ZRoutedRpc rpc, string name) { if (AccessTools.Field(typeof(ZRoutedRpc), "m_functions")?.GetValue(rpc) is IDictionary dictionary) { dictionary.Remove(StringExtensionMethods.GetStableHashCode(name)); } } private static void ForgetDirect(ZRpc rpc, string name) { if (AccessTools.Field(typeof(ZRpc), "m_functions")?.GetValue(rpc) is IDictionary dictionary) { dictionary.Remove(StringExtensionMethods.GetStableHashCode(name)); } } private void OnNewPeer(long uid) { if (IsServer) { ZNetPeer peer = ZNet.instance.GetPeer(uid); ListenTo(peer); if (peer?.m_rpc != null) { SendDirect(peer.m_rpc); } SendRouted(uid); } else if ((Object)(object)ZNet.instance != (Object)null) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null && serverPeer.m_uid == uid) { AskServer(); } } } private void ListenTo(ZNetPeer peer) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown if (peer?.m_rpc != null) { peer.m_rpc.Register(_dAsk, new Method(OnDirectAsk)); peer.m_rpc.Register<ZPackage>(_edit, (Action<ZRpc, ZPackage>)OnEdit); peer.m_rpc.Register<ZPackage>(_dTextAsk, (Action<ZRpc, ZPackage>)OnTextAsk); } } private void OnDirectAsk(ZRpc rpc) { if (IsServer) { _directPeers.Add(rpc); SendDirect(rpc); } } private void OnRoutedAsk(long sender) { if (IsServer) { SendRouted(sender); } } private void SendDirect(ZRpc rpc) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(2); val.Write(Version); ISocket socket = rpc.GetSocket(); string text = ((socket != null) ? socket.GetHostName() : null); val.Write(!string.IsNullOrEmpty(text) && ZNet.instance.IsAdmin(text)); rpc.Invoke(_dHello, new object[1] { val }); if (_entries.Count > 0) { rpc.Invoke(_dSend, new object[1] { Values() }); } } private void SendRouted(long target) { if (ZRoutedRpc.instance != null && _entries.Count > 0) { ZRoutedRpc.instance.InvokeRoutedRPC(target, _send, new object[1] { Values() }); } } private ZPackage Values() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(_entries.Count); foreach (ConfigEntryBase entry in _entries) { val.Write(entry.Definition.Section); val.Write(entry.Definition.Key); val.Write(TomlTypeConverter.ConvertToString(entry.BoxedValue, entry.SettingType)); } return val; } private void AskServer() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null); if (val?.m_rpc == null) { return; } _askedAt = Time.unscaledTime; val.m_rpc.Register<ZPackage>(_dHello, (Action<ZRpc, ZPackage>)OnDirectHello); val.m_rpc.Register<ZPackage>(_dSend, (Action<ZRpc, ZPackage>)OnDirectValues); val.m_rpc.Register<ZPackage>(_dText, (Action<ZRpc, ZPackage>)OnText); val.m_rpc.Register(_dAgain, new Method(OnAskAgain)); val.m_rpc.Invoke(_dAsk, Array.Empty<object>()); AskTexts(val.m_rpc); try { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(val.m_uid, _ask, Array.Empty<object>()); } } catch (Exception) { } } private static bool IsServerConnection(ZRpc rpc) { int result; if (!IsServer) { ZNet instance = ZNet.instance; result = ((((instance == null) ? null : instance.GetServerPeer()?.m_rpc) == rpc) ? 1 : 0); } else { result = 0; } return (byte)result != 0; } private void OnAskAgain(ZRpc rpc) { if (IsServerConnection(rpc)) { rpc.Invoke(_dAsk, Array.Empty<object>()); AskTexts(rpc); } } private void OnDirectHello(ZRpc rpc, ZPackage pkg) { if (!IsServerConnection(rpc)) { return; } try { int protocol = pkg.ReadInt(); string text = pkg.ReadString(); _adminConnection = ((pkg.GetPos() < pkg.Size() && pkg.ReadBool()) ? rpc : null); if (text != Version && text != ServerVersion) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("The server has " + _name + " " + text + ", you have " + Version + ": some things may not match. Use the same version as the server.")); } } _directSeen = true; SetServer(ServerMod.Installed, text, protocol); } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("Could not read the server's hello: " + ex.Message)); } } } private void OnDirectValues(ZRpc rpc, ZPackage pkg) { if (IsServerConnection(rpc)) { TakeValues(pkg); } } private void OnRoutedValues(long sender, ZPackage pkg) { if (!_directSeen && !IsServer) { ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null); if (val != null && val.m_uid == sender) { TakeValues(pkg); } } } private void TakeValues(ZPackage pkg) { try { int num = pkg.ReadInt(); List<string> list = new List<string>(); for (int i = 0; i < num; i++) { string section = pkg.ReadString(); string key = pkg.ReadString(); string text = pkg.ReadString(); ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)_entries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase x) => x.Definition.Section == section && x.Definition.Key == key)); if (val != null) { object obj; try { obj = TomlTypeConverter.ConvertToValue(text, val.SettingType); } catch (Exception) { continue; } if (!_own.ContainsKey(val)) { _own[val] = val.BoxedValue; } _server[val] = obj; if (!object.Equals(val.BoxedValue, obj)) { Apply(val, obj); list.Add(section + "/" + key + " = " + text); } } } ManualLogSource log = _log; if (log != null) { log.LogInfo((object)($"Settings from the server apply while you play here ({_server.Count})" + ((list.Count > 0) ? (": " + string.Join(", ", list.ToArray())) : ""))); } ShowReadOnly(); } catch (Exception ex2) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("Could not read the server's settings: " + ex2.Message)); } } } private void Apply(ConfigEntryBase e, object value) { bool saveOnConfigSet = _config.SaveOnConfigSet; _applying = true; try { _config.SaveOnConfigSet = false; e.BoxedValue = value; } finally { _config.SaveOnConfigSet = saveOnConfigSet; _applying = false; } } private void Restore() { if (_server.Count == 0) { return; } foreach (KeyValuePair<ConfigEntryBase, object> item in _own) { Apply(item.Key, item.Value); } _own.Clear(); _server.Clear(); ShowReadOnly(); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"Your own settings apply again"); } } private void OnChanged(object sender, EventArgs args) { if (_applying) { return; } ConfigEntryBase val = (ConfigEntryBase)((sender is ConfigEntryBase) ? sender : null); if (val == null) { return; } if (_server.TryGetValue(val, out var value)) { if (!_reloading && CanEditServer) { SendEdit(val); } else { _own[val] = val.BoxedValue; } Apply(val, value); } else if (IsServer) { _changePending = true; if (Time.unscaledTime >= _nextChangeSend) { SendChange(); } } } private void SendChange() { _changePending = false; _nextChangeSend = Time.unscaledTime + 0.5f; if (!IsServer) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer?.m_rpc == null) { continue; } if (_directPeers.Contains(peer.m_rpc)) { if (_entries.Count > 0) { peer.m_rpc.Invoke(_dSend, new object[1] { Values() }); } } else { SendRouted(peer.m_uid); } } } private void SendEdit(ConfigEntryBase e) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetServerPeer() : null); if (val?.m_rpc != null) { ZPackage val2 = new ZPackage(); val2.Write(e.Definition.Section); val2.Write(e.Definition.Key); val2.Write(TomlTypeConverter.ConvertToString(e.BoxedValue, e.SettingType)); val.m_rpc.Invoke(_edit, new object[1] { val2 }); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("Asked the server to set " + e.Definition.Section + "/" + e.Definition.Key)); } } } private void OnEdit(ZRpc rpc, ZPackage pkg) { try { if (!IsServer) { return; } ISocket socket = rpc.GetSocket(); string text = ((socket != null) ? socket.GetHostName() : null) ?? ""; ZNetPeer val = ((IEnumerable<ZNetPeer>)ZNet.instance.GetPeers()).FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.m_rpc == rpc)); string section = pkg.ReadString(); string key = pkg.ReadString(); string text2 = pkg.ReadString(); if (!ZNet.instance.IsAdmin(text)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)((val?.m_playerName ?? text) + " tried to change " + section + "/" + key + " but isn't on the admin list")); } if (_entries.Count > 0) { rpc.Invoke(_dSend, new object[1] { Values() }); } return; } ConfigEntryBase val2 = ((IEnumerable<ConfigEntryBase>)_entries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase x) => x.Definition.Section == section && x.Definition.Key == key)); if (val2 != null) { val2.BoxedValue = TomlTypeConverter.ConvertToValue(text2, val2.SettingType); ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)("Admin " + (val?.m_playerName ?? text) + " set " + section + "/" + key + " = " + text2)); } } } catch (Exception ex) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogWarning((object)("Could not take an admin's change: " + ex.Message)); } } } private void ShowReadOnly() { bool flag = FromServer && !CanEditServer; if (flag == _readOnlyShown) { return; } _readOnlyShown = flag; foreach (ConfigEntryBase entry in _entries) { ConfigDescription description = entry.Description; object[] array = ((description != null) ? description.Tags : null) ?? new object[0]; foreach (object obj in array) { if (IsManagerAttributes(obj)) { try { AccessTools.Field(obj.GetType(), "ReadOnly")?.SetValue(obj, flag ? ((object)true) : null); } catch (Exception) { } } } } } private static bool IsManagerAttributes(object tag) { return tag != null && tag.GetType().Name == "ConfigurationManagerAttributes"; } private string OwnText(SyncedText t) { try { return t.Own() ?? ""; } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Could not read " + t.Key + ": " + ex.Message)); } return t.Given ?? ""; } } private void Give(SyncedText t, string text) { if (t.Given != null && t.Given == text) { return; } t.Given = text; try { t.Use(text); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Could not use " + t.Key + ": " + ex)); } } } private void RestoreTexts(bool give) { foreach (SyncedText text in _texts) { text.Incoming = null; if (!text.FromServer) { continue; } text.FromServer = false; if (give) { Give(text, OwnText(text)); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("Your own " + text.Key + " applies again")); } } } } private void AskTexts(ZRpc server) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (_texts.Count == 0 || server == null) { return; } ZPackage val = new ZPackage(); val.Write(_texts.Count); foreach (SyncedText text in _texts) { val.Write(text.Key); } server.Invoke(_dTextAsk, new object[1] { val }); } private void OnTextAsk(ZRpc rpc, ZPackage pkg) { try { if (!IsServer) { return; } int num = pkg.ReadInt(); HashSet<string> hashSet = new HashSet<string>(); for (int i = 0; i < num && i < 1000; i++) { string key = pkg.ReadString(); if (_texts.Any((SyncedText x) => x.Key == key)) { hashSet.Add(key); } } if (_textPeers.TryGetValue(rpc, out var value)) { hashSet.UnionWith(value); } foreach (ZRpc item in _textPeers.Keys.Where((ZRpc r) => !r.IsConnected()).ToList()) { _textPeers.Remove(item); } _textPeers[rpc] = hashSet; foreach (SyncedText text in _texts) { if (hashSet.Contains(text.Key)) { SendText(rpc, text); } } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Could not answer a player's ask for server data: " + ex.Message)); } } } private void SendTexts() { _textPending = false; _nextTextSend = Time.unscaledTime + 0.5f; if (!IsServer) { return; } foreach (SyncedText text in _texts) { if (!text.Pending) { continue; } text.Pending = false; foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer?.m_rpc != null && _textPeers.TryGetValue(peer.m_rpc, out var value) && value.Contains(text.Key)) { SendText(peer.m_rpc, text); } } } } private void SendText(ZRpc rpc, SyncedText t) { byte[] array = Packed(t); if (array != null) { _outbox.RemoveAll((Sending s) => s.Rpc == rpc && s.Key == t.Key); _outbox.Add(new Sending { Rpc = rpc, Key = t.Key, Data = array, Parts = Math.Max(1, (array.Length + 65536 - 1) / 65536) }); Pump(); } } private void Pump() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown for (int num = _outbox.Count - 1; num >= 0; num--) { Sending sending = _outbox[num]; try { while (sending.Next < sending.Parts && sending.Rpc.IsConnected() && sending.Rpc.GetSocket().GetSendQueueSize() < 10240) { int num2 = sending.Next * 65536; int num3 = Math.Min(65536, sending.Data.Length - num2); byte[] array = new byte[num3]; Buffer.BlockCopy(sending.Data, num2, array, 0, num3); ZPackage val = new ZPackage(); val.Write(sending.Key); val.Write(sending.Next); val.Write(sending.Parts); val.Write(array); sending.Rpc.Invoke(_dText, new object[1] { val }); sending.Next++; } if (sending.Next >= sending.Parts || !sending.Rpc.IsConnected()) { _outbox.RemoveAt(num); } } catch (Exception ex) { _outbox.RemoveAt(num); ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Could not send " + sending.Key + " to a player: " + ex.Message)); } } } } private byte[] Packed(SyncedText t) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown if (t.Packed == null) { string text = OwnText(t); ZPackage val = new ZPackage(); val.Write(text); ZPackage val2 = new ZPackage(); bool flag = text.Length > 1024; val2.Write(flag); if (flag) { val2.WriteCompressed(val); } else { val2.Write(val); } t.Packed = val2.GetArray(); t.TooBig = t.Packed.Length > 8388608; string arg = $"{t.Packed.Length / 1024} KB" + (flag ? $" gzipped ({text.Length / 1024} KB of text)" : ""); if (t.TooBig) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"{t.Key} is too big to send to players ({arg}, at most {8} MB): they keep their own."); } } else if (t.Packed.Length > 262144) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)$"{t.Key} is big to send to every player who joins ({arg}): it takes about {(float)t.Packed.Length / 153600f:0} s of their connection, and their world loads slower meanwhile."); } } } return t.TooBig ? null : t.Packed; } private void OnText(ZRpc rpc, ZPackage pkg) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown if (!IsServerConnection(rpc)) { return; } SyncedText syncedText = null; try { string key = pkg.ReadString(); int num = pkg.ReadInt(); int num2 = pkg.ReadInt(); byte[] array = pkg.ReadByteArray(); syncedText = _texts.FirstOrDefault((SyncedText x) => x.Key == key); if (syncedText == null) { return; } if (num2 < 1 || num2 > 129 || num < 0 || num >= num2) { throw new InvalidDataException($"part {num} of {num2}"); } if (num == 0) { syncedText.Incoming = new MemoryStream(); syncedText.NextPart = 0; } if (syncedText.Incoming == null || num != syncedText.NextPart) { throw new InvalidDataException($"part {num} came out of order"); } syncedText.Incoming.Write(array, 0, array.Length); syncedText.NextPart = num + 1; if (num >= num2 - 1) { ZPackage val = new ZPackage(syncedText.Incoming.ToArray()); syncedText.Incoming = null; ZPackage val2 = (val.ReadBool() ? val.ReadCompressedPackage() : val.ReadPackage()); string text = val2.ReadString(); syncedText.FromServer = true; Give(syncedText, text); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"The server's {key} applies while you play here ({text.Length / 1024} KB)"); } } } catch (Exception ex) { if (syncedText != null) { syncedText.Incoming = null; } ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("Could not read the server's data" + ((syncedText != null) ? (" for " + syncedText.Key) : "") + ": " + ex.Message)); } } } private void SetServer(ServerMod state, string version, int protocol) { if (state != ServerMod.Checking) { _askedAt = -1f; } if (state != ServerMod.Installed) { _adminConnection = null; } bool flag = state != Server || version != ServerVersion; Server = state; ServerVersion = version; _serverProtocol = protocol; if (!flag) { return; } Guard(); try { this.ServerChanged?.Invoke(); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("ServerChanged: " + ex)); } } } private void Guard() { bool flag = Server == ServerMod.NotConnected || Server == ServerMod.Installed; bool flag2 = false; foreach (GameObject guardedPiece in _guardedPieces) { Piece val = (((Object)(object)guardedPiece != (Object)null) ? guardedPiece.GetComponent<Piece>() : null); if ((Object)(object)val != (Object)null && val.m_enabled != flag) { val.m_enabled = flag; flag2 = true; } } foreach (Recipe guardedRecipe in _guardedRecipes) { if ((Object)(object)guardedRecipe != (Object)null && guardedRecipe.m_enabled != flag) { guardedRecipe.m_enabled = flag; flag2 = true; } } if (flag2 && (Object)(object)Player.m_localPlayer != (Object)null) { try { UpdateAvailablePieces?.Invoke(Player.m_localPlayer, null); } catch (Exception) { } } } private void WatchFile() { try { string configFilePath = _config.ConfigFilePath; _watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)) { NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite) }; FileSystemEventHandler value = delegate { _fileTouched = true; }; _watcher.Changed += value; _watcher.Created += value; _watcher.Renamed += delegate { _fileTouched = true; }; _watcher.EnableRaisingEvents = true; } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Edits to the config file apply after a restart (can't watch it: " + ex.Message + ")")); } } } private void ReloadFile() { string text = ReadFile(_config.ConfigFilePath); if (text == null) { if (File.Exists(_config.ConfigFilePath)) { _reloadAt = Time.unscaledTime + 1f; } } else { if (text == _fileText) { return; } _fileText = text; bool saveOnConfigSet = _config.SaveOnConfigSet; _reloading = true; try { _config.SaveOnConfigSet = false; _config.Reload(); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Could not read the edited config file (check the line you changed): " + ex.Message)); } } finally { _config.SaveOnConfigSet = saveOnConfigSet; _reloading = false; } } } private void PatchSave() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0069: Expected O, but got Unknown try { _saveHarmony = new Harmony(_send + ".save"); _saveHarmony.Patch((MethodBase)AccessTools.Method(typeof(ConfigFile), "Save", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ServerSettings), "BeforeSave", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ServerSettings), "AfterSave", (Type[])null), (HarmonyMethod)null); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Could not keep the server's values out of your config file: " + ex.Message)); } } } private static void UnpatchSave() { try { Harmony saveHarmony = _saveHarmony; if (saveHarmony != null) { saveHarmony.UnpatchSelf(); } } catch (Exception) { } _saveHarmony = null; } private static void BeforeSave(ConfigFile __instance) { foreach (ServerSettings item in Live) { if (item._config != __instance) { continue; } foreach (KeyValuePair<ConfigEntryBase, object> item2 in item._own) { SetQuietly(item2.Key, item2.Value); } } } private static Exception AfterSave(ConfigFile __instance, Exception __exception) { foreach (ServerSettings item in Live) { if (item._config != __instance) { continue; } foreach (KeyValuePair<ConfigEntryBase, object> item2 in item._server) { SetQuietly(item2.Key, item2.Value); } item._fileText = ReadFile(__instance.ConfigFilePath); } return __exception; } private static string ReadFile(string path) { try { return File.Exists(path) ? File.ReadAllText(path) : null; } catch (Exception) { return null; } } private static void SetQuietly(ConfigEntryBase e, object value) { AccessTools.Field(((object)e).GetType(), "_typedValue")?.SetValue(e, value); } private static BepInPlugin PluginOf(string guid) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown Type[] array; try { array = typeof(ServerSettings).Assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } Type[] array2 = array; foreach (Type type in array2) { object[] customAttributes = type.GetCustomAttributes(typeof(BepInPlugin), inherit: false); for (int num2 = 0; num2 < customAttributes.Length; num2++) { BepInPlugin val = (BepInPlugin)customAttributes[num2]; if (val.GUID == guid || guid.StartsWith(val.GUID + ".")) { return val; } } } return null; } private void Unsubscribe(ConfigEntryBase e) { ((object)e).GetType().GetEvent("SettingChanged")?.RemoveEventHandler(e, new EventHandler(OnChanged)); } } } namespace QuestHeim { internal static class Board { [HarmonyPatch(typeof(Piece), "DropResources")] private static class Piece_DropResources { private static bool Prefix(Piece __instance) { return !IsBoard(((Component)__instance).gameObject); } } [HarmonyPatch(typeof(Player), "CheckCanRemovePiece", new Type[] { typeof(Piece) })] private static class Player_CheckCanRemovePiece { private static bool Prefix(Piece __0, ref bool __result) { if ((Object)(object)__0 == (Object)null || !IsBoard(((Component)__0).gameObject) || CanBuildOrRemove) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetScene_Awake { private static void Postfix(ZNetScene __instance) { try { Register(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("Registering the QuestHeim board failed: " + ex)); } } } public const string PrefabName = "marlthon_questheim_board"; public const int Slots = 10; private static GameObject _prefab; private static GameObject[] _effects = Array.Empty<GameObject>(); private static PieceTable _table; private static bool _prepared; private static readonly FieldRef<ZNetScene, Dictionary<int, GameObject>> NamedPrefabs = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs"); internal static bool CanBuildOrRemove => Plugin.Synced?.CanEditServer ?? false; internal static bool IsBoard(GameObject go) { return (Object)(object)go != (Object)null && Utils.GetPrefabName(go) == "marlthon_questheim_board"; } internal static void Load() { //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Expected O, but got Unknown //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) using Stream stream = typeof(Board).Assembly.GetManifestResourceStream("QuestHeim.assets.mar_questheim"); if (stream == null) { throw new InvalidOperationException("The QuestHeim bundle is missing."); } using BinaryReader binaryReader = new BinaryReader(stream); AssetBundle val = AssetBundle.LoadFromMemory(binaryReader.ReadBytes((int)stream.Length)); GameObject boardAsset = ((val != null) ? val.LoadAsset<GameObject>("QH_NoticeBoard") : null); GameObject val2 = ((val != null) ? val.LoadAsset<GameObject>("QH_Chest") : null); if ((Object)(object)val != (Object)null) { string[] array = new string[4] { "sfx_build_hammer_wood_questheim", "sfx_wood_destroyed_questheim", "vfx_Place_wood_wall_questheim", "vfx_SawDust_questheim" }; List<GameObject> list = new List<GameObject>(); string[] array2 = array; foreach (string text in array2) { GameObject val3 = val.LoadAsset<GameObject>(text); if ((Object)(object)val3 != (Object)null) { list.Add(val3); } else { Plugin.Log.LogWarning((object)("Effect prefab '" + text + "' is missing from mar_questheim.")); } } _effects = list.ToArray(); } if (val != null) { val.Unload(false); } if ((Object)(object)boardAsset == (Object)null || (Object)(object)val2 == (Object)null || !Object.op_Implicit((Object)(object)boardAsset.GetComponent<Piece>()) || !Object.op_Implicit((Object)(object)boardAsset.GetComponent<ZNetView>()) || !Object.op_Implicit((Object)(object)val2.GetComponent<Container>()) || !Object.op_Implicit((Object)(object)boardAsset.transform.Find("chest_anchor")) || Enumerable.Range(0, 10).Any((int num) => !Object.op_Implicit((Object)(object)boardAsset.transform.Find("notice_" + num)))) { throw new InvalidOperationException("The QuestHeim bundle is missing a prefab, component or anchor."); } GameObject val4 = new GameObject("QuestHeim_prefabs"); val4.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val4); _prefab = Object.Instantiate<GameObject>(boardAsset, val4.transform); ((Object)_prefab).name = "marlthon_questheim_board"; _prefab.GetComponent<Piece>().m_name = "$questheim_board"; _prefab.GetComponent<Piece>().m_description = "$questheim_board_desc"; _prefab.AddComponent<BoardFace>(); GameObject val5 = Object.Instantiate<GameObject>(val2, _prefab.transform.Find("chest_anchor"), false); val5.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); Object.DestroyImmediate((Object)(object)val5.GetComponent<Piece>()); Object.DestroyImmediate((Object)(object)val5.GetComponent<WearNTear>()); Object.DestroyImmediate((Object)(object)val5.GetComponent<ZNetView>()); Container component = val5.GetComponent<Container>(); component.m_rootObjectOverride = _prefab.GetComponent<ZNetView>(); component.m_name = "$questheim_box"; Piece component2 = _prefab.GetComponent<Piece>(); component2.m_category = (PieceCategory)4; component2.m_usage = (UsageTagFlags)128; Plugin.Synced.NeedsServer(_prefab); } internal static void Register(ZNetScene scene) { if ((Object)(object)scene == (Object)null || (Object)(object)_prefab == (Object)null) { return; } GameObject[] effects = _effects; foreach (GameObject prefab in effects) { RegisterPrefab(scene, prefab); } PrepareNotices(scene); ApplyConstructionSettings(); RegisterPrefab(scene, _prefab); GameObject prefab2 = scene.GetPrefab("Hammer"); PieceTable val = ((!((Object)(object)prefab2 != (Object)null)) ? null : prefab2.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces); if (!((Object)(object)val == (Object)null)) { _table = val; val.m_pieces.RemoveAll((GameObject val2) => (Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)_prefab && ((Object)val2).name == "marlthon_questheim_board"); if (!val.m_pieces.Contains(_prefab)) { val.m_pieces.Add(_prefab); } } } private static void RegisterPrefab(ZNetScene scene, GameObject prefab) { List<GameObject> list = (((Object)(object)prefab.GetComponent<ZNetView>() != (Object)null) ? scene.m_prefabs : scene.m_nonNetViewPrefabs); list.RemoveAll((GameObject existing) => (Object)(object)existing != (Object)null && (Object)(object)existing != (Object)(object)prefab && ((Object)existing).name == ((Object)prefab).name); if (!list.Contains(prefab)) { list.Add(prefab); } NamedPrefabs.Invoke(scene)[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; } internal static void ApplyConstructionSettings() { if (!((Object)(object)_prefab == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { Piece component = _prefab.GetComponent<Piece>(); if (!Costs.Apply(component, Plugin.BoardCost.Value, Plugin.Log) && (component.m_resources == null || component.m_resources.Length == 0)) { Costs.Apply(component, ((ConfigEntryBase)Plugin.BoardCost).DefaultValue as string, Plugin.Log); } if (!Costs.ApplyStation(component, Plugin.BoardStation.Value, Plugin.Log) && (Object)(object)component.m_craftingStation == (Object)null) { Costs.ApplyStation(component, ((ConfigEntryBase)Plugin.BoardStation).DefaultValue as string, Plugin.Log); } } } internal static void Unload() { if ((Object)(object)_table != (Object)null) { _table.m_pieces.Remove(_prefab); } } private static void PrepareNotices(ZNetScene scene) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_prefab == (Object)null) && !_prepared) { Material iron = MaterialOf(scene, "Iron") ?? MaterialOf(scene, "Bronze"); AddNotices(_prefab.transform, scene, iron); Transform val = _prefab.transform.Find("chest_anchor"); GameObject val2 = new GameObject("questheim_pouch"); val2.transform.SetParent(val, false); val2.transform.localPosition = new Vector3(0f, 0.25f, -0.2f); PouchModel.Make(val2.transform, scene); val2.SetActive(false); _prefab.AddComponent<NoticeBoard>(); _prepared = true; } } private static void AddNotices(Transform board, ZNetScene scene, Material iron) { //IL_00bd: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) Mesh sharedMesh = QuadMesh(); BoxCollider component = ((Component)board).GetComponent<BoxCollider>(); Vector3 localPosition2 = default(Vector3); for (int i = 0; i < 10; i++) { Transform val = board.Find("notice_" + i); BoxCollider val2 = ((Component)val).gameObject.AddComponent<BoxCollider>(); float num = -0.015f; if ((Object)(object)component != (Object)null) { Vector3 localPosition = val.localPosition; localPosition.z = component.center.z - component.size.z * 0.5f; float z = val.InverseTransformPoint(board.TransformPoint(localPosition)).z; num = Mathf.Min(num, z - 0.01f); } val2.center = new Vector3(0f, 0f, (num + 0.005f) * 0.5f); val2.size = new Vector3(0.33f, 0.42f, 0.005f - num); ((Component)val).gameObject.AddComponent<NoticePaper>(); GameObject val3 = new GameObject("paper"); val3.transform.SetParent(val, false); val3.transform.localScale = new Vector3(0.33f, 0.42f, 1f); val3.AddComponent<MeshFilter>().sharedMesh = sharedMesh; ((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterial = Paper.For(i switch { 0 => Kind.Trophy, 2 => Kind.Kill, _ => (Kind)(i % 4), }, scene); ((Vector3)(ref localPosition2))..ctor(0f, 0.16499999f, 0f); GameObject val4 = new GameObject("pin_nail"); val4.transform.SetParent(val, false); if ((Object)(object)iron != (Object)null) { GameObject val5 = GameObject.CreatePrimitive((PrimitiveType)2); Object.DestroyImmediate((Object)(object)val5.GetComponent<Collider>()); ((Object)val5).name = "nail"; val5.transform.SetParent(val4.transform, false); val5.transform.localPosition = localPosition2; val5.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); val5.transform.localScale = new Vector3(0.022f, 0.012f, 0.022f); ((Renderer)val5.GetComponent<MeshRenderer>()).sharedMaterial = iron; } ((Component)val).gameObject.SetActive(false); } } private static Mesh QuadMesh() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_002b: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) Mesh val = new Mesh { name = "questheim_quad" }; val.vertices = (Vector3[])(object)new Vector3[4] { new Vector3(-0.5f, -0.5f, 0f), new Vector3(0.5f, -0.5f, 0f), new Vector3(-0.5f, 0.5f, 0f), new Vector3(0.5f, 0.5f, 0f) }; val.uv = (Vector2[])(object)new Vector2[4] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0f, 1f), new Vector2(1f, 1f) }; val.triangles = new int[6] { 0, 2, 1, 2, 3, 1 }; val.RecalculateNormals(); val.RecalculateTangents(); val.RecalculateBounds(); return val; } private static Material MaterialOf(ZNetScene scene, string itemPrefab) { GameObject prefab = scene.GetPrefab(itemPrefab); MeshRenderer val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<MeshRenderer>(true) : null); return ((Object)(object)val != (Object)null) ? ((Renderer)val).sharedMaterial : null; } } internal static class Costs { public const string Help = "Item prefab names and amounts, separated by commas, like FineWood:12, BronzeNails:30."; public const string StationHelp = "The crafting station's prefab name (piece_workbench, forge, piece_stonecutter, piece_artisanstation, blackforge, piece_magetable), or none."; public static Requirement[] Parse(string text, List<string> problems) { //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown problems = problems ?? new List<string>(); int count = problems.Count; List<Requirement> list = new List<Requirement>(); string[] array = (text ?? "").Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.Length == 0) { continue; } string[] array2 = (from b in text3.Split(new char[1] { ':' }) select b.Trim()).ToArray(); if (array2.Length < 2 || array2.Length > 3 || !Whole(array2[1], out var value) || value < 1) { problems.Add("\"" + text3 + "\" isn't Name:amount"); continue; } bool result = true; if (array2.Length == 3 && !bool.TryParse(array2[2], out result)) { problems.Add("\"" + text3 + "\": the last part isn't true or false"); continue; } ItemDrop item = FindItem(array2[0]); if ((Object)(object)item == (Object)null) { problems.Add("no item called \"" + array2[0] + "\""); continue; } if (list.Any((Requirement r) => (Object)(object)r.m_resItem == (Object)(object)item)) { problems.Add(array2[0] + " is listed twice"); continue; } list.Add(new Requirement { m_resItem = item, m_amount = value, m_recover = result }); } if (list.Count == 0 && problems.Count == count) { problems.Add("it's empty (nothing would be free: write at least one item)"); } return (problems.Count == count) ? list.ToArray() : null; } private static bool Whole(string text, out int value) { return int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out value); } public static ItemDrop FindItem(string name) { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null); if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab(name); } return ((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null; } public static CraftingStation FindStation(string name, out bool found) { name = (name ?? "").Trim(); found = true; if (name.Length == 0 || name.Equals("none", StringComparison.OrdinalIgnoreCase)) { return null; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null); CraftingStation val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<CraftingStation>() : null); found = (Object)(object)val2 != (Object)null; return val2; } public static bool Apply(Piece piece, string text, ManualLogSource log) { if ((Object)(object)piece == (Object)null) { return false; } List<string> problems = new List<string>(); Requirement[] array = Parse(text, problems); Report(log, ((Object)piece).name, problems); if (array == null) { return false; } piece.m_resources = array; return true; } public static bool ApplyStation(Piece piece, string text, ManualLogSource log) { if ((Object)(object)piece == (Object)null) { return false; } bool found; CraftingStation craftingStation = FindStation((text ?? "").Split(new char[1] { ':' })[0], out found); if (!found) { if (log != null) { log.LogWarning((object)(((Object)piece).name + ": no crafting station called \"" + text + "\", it keeps its station")); } return false; } piece.m_craftingStation = craftingStation; return true; } private static void Report(ManualLogSource log, string what, List<string> problems) { if (problems.Count > 0 && log != null) { log.LogWarning((object)(what + "'s cost setting has a mistake, so it keeps its last cost: " + string.Join("; ", problems.ToArray()))); } } } internal enum NoticeRemoval { PerPlayer, Everyone } internal sealed class NoticeBoard : MonoBehaviour { private sealed class SharedClaim { public NoticeBoard Board; public Player Player; public Contract Offer; public string Token; public long Owner; public float Expires; } public const int Slots = 10; private const string KeyNotices = "QuestHeim.notices"; private const string KeyDay = "QuestHeim.day"; private const string KeyFirst = "QuestHeim.first"; private const string KeyCustomRevision = "QuestHeim.customRevision"; private const string ClaimRpc = "QuestHeim_ClaimSharedNotice"; private const string ClaimResultRpc = "QuestHeim_SharedNoticeResult"; private static SharedClaim _pendingClaim; private ZNetView _view; private GameObject[] _slots; private MeshRenderer[] _papers; private GameObject _pouch; private Container _box; private string _shown; private readonly Contract[] _sharedOffers = new Contract[10]; private readonly Contract[] _personalOffers = new Contract[10]; private int _personalTier = -1; private Player _shownPlayer; private int _shownDay = -1; private int _claimedSlots; private bool _shownPersonal; private float _nextShow; private float _nextPost; internal static readonly List<NoticeBoard> Loaded = new List<NoticeBoard>(); private unsafe string ClaimKey { get { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) string text = ZNet.instance.GetWorldUID().ToString(); ZDOID uid = _view.GetZDO().m_uid; return "QuestHeim.claims." + text + "." + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString(); } } private void Awake() { _view = ((Component)this).GetComponent<ZNetView>(); _slots = (GameObject[])(object)new GameObject[10]; _papers = (MeshRenderer[])(object)new MeshRenderer[10]; for (int i = 0; i < 10; i++) { Transform val = ((Component)this).transform.Find("notice_" + i); _slots[i] = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null); MeshRenderer[] papers = _papers; int num = i; object obj; if (!((Object)(object)val != (Object)null)) { obj = null; } else { Transform obj2 = val.Find("paper"); obj = ((obj2 != null) ? ((Component)obj2).GetComponent<MeshRenderer>() : null); } papers[num] = (MeshRenderer)obj; } Transform obj3 = ((Component)this).transform.Find("chest_anchor/questheim_pouch"); _pouch = ((obj3 != null) ? ((Component)obj3).gameObject : null); _box = ((Component)this).GetComponentInChildren<Container>(true); if (!((Object)(object)_view == (Object)null) && _view.IsValid()) { Loaded.Add(this); _view.Register<int, string, string>("QuestHeim_ClaimSharedNotice", (Action<long, int, string, string>)ClaimSharedNotice); _view.Register<string, bool>("QuestHeim_SharedNoticeResult", (Action<long, string, bool>)ReceiveSharedNotice); Show(force: true); } } private void OnDestroy() { Loaded.Remove(this); if ((Object)(object)_pendingClaim?.Board == (Object)(object)this) { _pendingClaim = null; } } private void Update() { if ((Object)(object)_view == (Object)null || !_view.IsValid()) { return; } float time = Time.time; if (time >= _nextPost && _view.IsOwner()) { _nextPost = time + 2f; try { Post(); ClearPouch(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Posting notices: " + ex.Message)); } } if (time >= _nextShow) { _nextShow = time + 0.5f; Show(force: false); } } private string[] Read() { string[] array = new string[10]; string[] array2 = (_view.GetZDO().GetString("QuestHeim.notices", "") ?? "").Split(new char[1] { ';' }); for (int i = 0; i < 10; i++) { array[i] = ((i < array2.Length) ? array2[i] : ""); } return array; } private void Write(string[] slots) { _view.GetZDO().Set("QuestHeim.notices", string.Join(";", slots)); } public int Count() { return _sharedOffers.Where((Contract c, int slot) => c != null && (_claimedSlots & (1 << slot)) == 0).Count(); } public Contract ContractAt(int slot) { if ((Object)(object)_view == (Object)null || !_view.IsValid() || slot < 0 || slot >= 10 || (_claimedSlots & (1 << slot)) != 0) { return null; } Contract contract = _sharedOffers[slot]; Player localPlayer = Player.m_localPlayer; if (contract == null || (Object)(object)localPlayer == (Object)null || Plugin.Progression.Value == BossProgression.Global) { return contract; } int num = Contracts.PlayerTier(localPlayer); if (num != _personalTier) { Array.Clear(_personalOffers, 0, 10); _personalTier = num; } return _personalOffers[slot] ?? (_personalOffers[slot] = Contracts.Make(new Random(StringExtensionMethods.GetStableHashCode(contract.Id)), -1, num)); } public static void RedrawAll() { foreach (NoticeBoard item in Loaded) { if ((Object)(object)item != (Object)null && (Object)(object)item._view != (Object)null && item._view.IsValid()) { item.Show(force: true); } } } internal static void CustomQuestsChanged() { foreach (NoticeBoard item in Loaded) { if ((Object)(object)item != (Object)null) { Array.Clear(item._personalOffers, 0, 10); } } } private void Show(bool force) { if ((Object)(object)_pouch != (Object)null) { _pouch.SetActive(!string.IsNullOrEmpty(_view.GetZDO().GetString("QuestHeim.pouch", ""))); } string text = _view.GetZDO().GetString("QuestHeim.notices", ""); int num = _view.GetZDO().GetInt("QuestHeim.day", -1); Player localPlayer = Player.m_localPlayer; bool flag = Plugin.Progression.Value == BossProgression.PerPlayer; bool flag2 = text != _shown; bool flag3 = (Object)(object)_shownPlayer != (Object)(object)localPlayer || _shownDay != num; if (!force && !flag2 && !flag3 && flag == _shownPersonal) { return; } if (flag2) { string[] array = Read(); for (int i = 0; i < 10; i++) { _sharedOffers[i] = Contract.Read(array[i]); } Array.Clear(_personalOffers, 0, 10); _shown = text; } if (flag3) { _claimedSlots = 0; string text2 = default(string); if ((Object)(object)localPlayer != (Object)null && localPlayer.TryGetUniqueKeyValue(ClaimKey, ref text2)) { string[] array2 = text2.Split(new char[1] { ':' }); if (array2.Length == 2 && int.TryParse(array2[0], out var result) && result == num) { int.TryParse(array2[1], out _claimedSlots); } } _shownPlayer = localPlayer; _shownDay = num; } _shownPersonal = flag; for (int j = 0; j < 10; j++) { Contract contract = _sharedOffers[j]; bool flag4 = contract != null && (_claimedSlots & (1 << j)) == 0; if ((Object)(object)_slots[j] != (Object)null) { _slots[j].SetActive(flag4); } if (flag4 && !((Object)(object)_papers[j] == (Object)null)) { Material val = ((!flag && Plugin.Illustrated.Value) ? Sketch.For(contract, ZNetScene.instance, Plugin.NoticeHeading.Value) : null); val = val ?? Paper.For(flag ? Kind.Gather : contract.Kind, ZNetScene.instance); if ((Object)(object)val != (Object)null) { ((Renderer)_papers[j]).sharedMaterial = val; } } } } private void ClearPouch() { string text = _view.GetZDO().GetString("QuestHeim.pouch", ""); if (!string.IsNullOrEmpty(text) && !((Object)(object)_box == (Object)null)) { string[] names = text.Split(new char[1] { ',' }); if (!_box.GetInventory().GetAllItems().Any((ItemData i) => (Object)(object)i.m_dropPrefab != (Object)null && names.Contains(((Object)i.m_dropPrefab).name))) { _view.GetZDO().Set("QuestHeim.pouch", ""); } } } private void Post() { if ((Object)(object)EnvMan.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || !HasCurrentQuestConfig()) { return; } double timeSeconds = ZNet.instance.GetTimeSeconds(); int num = EnvMan.instance.GetDay(timeSeconds); if (timeSeconds < EnvMan.instance.GetMorningStartSec(num)) { num--; } TakeDownOrphans(); int num2 = _view.GetZDO().GetInt("QuestHeim.day", -1); if (num2 == num) { RefreshCustomOffers(); return; } if (num2 < 0 || num < num2) { _view.GetZDO().Set("QuestHeim.day", num); if (num2 < 0) { _view.GetZDO().Set("QuestHeim.first", 1); } return; } Random random = new Random(); int num4; if (_view.GetZDO().GetInt("QuestHeim.first", 0) == 1) { int value = Plugin.FirstDawnLeast.Value; int num3 = Math.Max(value, Plugin.FirstDawnMost.Value); num4 = random.Next(value, num3 + 1); _view.GetZDO().Set("QuestHeim.first", 0); } else { num4 = Read().Count((string s) => !string.IsNullOrEmpty(s)); for (int num5 = 0; num5 < Math.Min(num - num2, 5); num5++) { num4 += DawnCount(random); } } string[] slots = new string[10]; Fill(slots, num4, random); Write(slots); _view.GetZDO().Set("QuestHeim.day", num); _view.GetZDO().Set("QuestHeim.customRevision", CustomQuests.Revision); } private static bool HasCurrentQuestConfig() { return ZNet.instance.IsServer() || Plugin.Synced.TextFromServer("custom-quests"); } private void RefreshCustomOffers() { ZDO zDO = _view.GetZDO(); int revision = CustomQuests.Revision; int num = zDO.GetInt("QuestHeim.customRevision", int.MinValue); if (num == revision) { return; } if (num != int.MinValue) { string[] array = Read(); Random rnd = new Random(); for (int i = 0; i < 10; i++) { if (!string.IsNullOrEmpty(array[i])) { array[i] = Contracts.Make(rnd)?.Write() ?? array[i]; } } Write(array); } zDO.Set("QuestHeim.customRevision", revision); } public int PostNow(int count, IList<Kind> kinds, bool clear) { if ((Object)(object)_view == (Object)null || !_view.IsValid() || !_view.IsOwner()) { return 0; } string[] slots = (clear ? new string[10] : Read()); HashSet<int> hashSet = new HashSet<int>(from i in Enumerable.Range(0, 10) where !string.IsNullOrEmpty(slots[i]) select i); Random rnd = new Random(); int num = Fill(slots, count, rnd); int num2 = 0; for (int num3 = 0; num3 < 10; num3++) { if (hashSet.Contains(num3)) { continue; } Contract contract = Contract.Read(slots[num3]); if (contract == null) { continue; } if (num2 < kinds.Count) { Kind kind = kinds[num2++]; for (int num4 = 0; num4 < 200; num4++) { if (contract.Kind == kind) { break; } Contract contract2 = Contracts.Make(rnd); if (contract2 != null) { contract = contract2; } } } slots[num3] = contract.Write(); } if (clear) { Write(slots); return num; } if (num > 0) { Write(slots); } return num; } private void TakeDownOrphans() { string[] array = Read(); bool flag = false; for (int i = 0; i < array.Length; i++) { Contract contract = Contract.Read(array[i]); if (contract != null && !Contracts.Known(contract.Target)) { array[i] = ""; flag = true; } } if (flag) { Write(array); } } private static int DawnCount(Random rnd) { int num = 1; string[] array = (Plugin.MoreChances.Value ?? "").Split(new char[1] { ',' }); foreach (string text in array) { if (!float.TryParse(text.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || rnd.NextDouble() * 100.0 >= (double)result) { break; } num++; } return num; } private static int Fill(string[] slots, int count, Random rnd) { int num = 0; for (int i = 0; i < count; i++) { if (slots.Count((string x) => !string.IsNullOrEmpty(x)) >= Plugin.MaxNotices.Value) { break; } int[] array = (from num2 in Enumerable.Range(0, 10) where string.IsNullOrEmpty(slots[num2]) select num2).ToArray(); if (array.Length == 0) { break; } Contract contract = Contracts.Make(rnd); if (contract == null) { break; } slots[array[rnd.Next(array.Length)]] = contract.Write(); num++; } return num; } public void RequestTake(int slot) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)_view == (Object)null || !_view.IsValid() || (_pendingClaim != null && Time.unscaledTime < _pendingClaim.Expires)) { return; } _pendingClaim = null; Show(force: false); Contract contract = ContractAt(slot); if (contract == null) { return; } if (!QuestProgress.CanTake(localPlayer)) { ((Character)localPlayer).Message((MessageType)2, Translations.T("questheim_too_many", Plugin.MaxActiveQuests.Value), 0, (Sprite)null, false); } else if ((Object)(object)NoticeItem.Prefab == (Object)null || !((Humanoid)localPlayer).GetInventory().HaveEmptySlot()) { ((Character)localPlayer).Message((MessageType)2, Translations.T("questheim_bag_full"), 0, (Sprite)null, false); } else if (Plugin.RemoveNotice.Value == NoticeRemoval.Everyone) { long owner = _view.GetZDO().GetOwner(); if (owner != 0) { SharedClaim sharedClaim = (_pendingClaim = new SharedClaim { Board = this, Player = localPlayer, Offer = contract, Owner = owner, Token = Guid.NewGuid().ToString("N"), Expires = Time.unscaledTime + 8f }); _view.InvokeRPC(owner, "QuestHeim_ClaimSharedNotice", new object[3] { slot, _sharedOffers[slot].Id, sharedClaim.Token }); } } else if (!QuestProgress.Accept(localPlayer, contract)) { ((Character)localPlayer).Message((MessageType)2, Translations.T("questheim_bag_full"), 0, (Sprite)null, false); } else { _claimedSlots |= 1 << slot; localPlayer.AddUniqueKeyValue(ClaimKey, _shownDay.ToString(CultureInfo.InvariantCulture) + ":" + _claimedSlots.ToString(CultureInfo.InvariantCulture)); Show(force: true); ((Character)localPlayer).Message((MessageType)1, Translations.T("questheim_took", contract.Line()), 0, (Sprite)null, false); } } private void ClaimSharedNotice(long sender, int slot, string offerId, string token) { if (!_view.IsValid() || !_view.IsOwner()) { return; } bool flag = false; if (Plugin.RemoveNotice.Value == NoticeRemoval.Everyone && slot >= 0 && slot < 10) { string[] array = Read(); Contract contract = Contract.Read(array[slot]); if (contract != null && contract.Id == offerId) { array[slot] = ""; Write(array); flag = true; } } _view.InvokeRPC(sender, "QuestHeim_SharedNoticeResult", new object[2] { token, flag }); } private void ReceiveSharedNotice(long sender, string token, bool granted) { SharedClaim pendingClaim = _pendingClaim; if (pendingClaim == null || (Object)(object)pendingClaim.Board != (Object)(object)this || pendingClaim.Owner != sender || pendingClaim.Token != token) { return; } _pendingClaim = null; if (!((Object)(object)pendingClaim.Player == (Object)null) && !((Object)(object)pendingClaim.Player != (Object)(object)Player.m_localPlayer)) { if (!granted) { ((Character)pendingClaim.Player).Message((MessageType)2, Translations.T("questheim_gone"), 0, (Sprite)null, false); } else if (QuestProgress.Accept(pendingClaim.Player, pendingClaim.Offer, dropIfFull: true)) { ((Character)pendingClaim.Player).Message((MessageType)1, Translations.T("questheim_took", pendingClaim.Offer.Line()), 0, (Sprite)null, false); } else { ((Character)pendingClaim.Player).Message((MessageType)2, Translations.T("questheim_bag_full"), 0, (Sprite)null, false); } } } } internal sealed class NoticePaper : MonoBehaviour, Hoverable, Interactable { private int _slot = -1; private NoticeBoard _board; private void Awake() { int.TryParse(((Object)this).name.Substring(((Object)this).name.LastIndexOf('_') + 1), out _slot); _board = ((Component)this).GetComponentInParent<NoticeBoard>(); } public string GetHoverText() { Contract contract = (((Object)(object)_board != (Object)null) ? _board.ContractAt(_slot) : null); if (contract == null) { return ""; } return Localization.instance.Localize(Contracts.Describe(contract) + "\n[<color=yellow><b>$KEY_Use</b></color>] " + Translations.T("questheim_take")); } public string GetHoverName() { return Translations.T("questheim_notice_name"); } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || (Object)(object)_board == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer) { return false; } _board.RequestTake(_slot); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal sealed class BoardFace : MonoBehaviour, Hoverable, Interactable { public string GetHoverText() { NoticeBoard componentInParent = ((Component)this).GetComponentInParent<NoticeBoard>(); string text = (((Object)(object)componentInParent != (Object)null && componentInParent.Count() == 0) ? Translations.T("questheim_board_empty") : Translations.T("questheim_board_hint")); string text2 = ((!ZInput.IsNonClassicFunctionality() || !ZInput.IsGamepadActive()) ? "$KEY_AltPlace" : "$KEY_AltKeys"); return Localization.instance.Localize("$questheim_board\n<size=80%><color=#bdb7a9>" + text + "</color></size>\n[<color=yellow><b>" + text2 + " + $KEY_Use</b></color>] " + Translations.T("questheim_abandon")); } public string GetHoverName() { return Localization.instance.Localize("$questheim_board"); } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { int result; if (!hold && alt) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer) { result = (QuestProgress.AbandonOldest(val) ? 1 : 0); goto IL_0028; } } result = 0; goto IL_0028; IL_0028: return (byte)result != 0; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class NoticeItem { [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] private static class ItemData_GetTooltip { private static void Postfix(ItemData item, ref string __result) { try { Contract contract = ContractOf(item); if (contract != null) { __result = Contracts.Describe(contract) + "\n" + Status(item, contract) + "\n\n" + __result; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Notice tooltip: " + ex.Message)); } } } [HarmonyPatch(typeof(ItemData), "GetIcon")] private static class ItemData_GetIcon { private static void Postfix(ItemData __instance, ref Sprite __result) { if (Is(__instance)) { Sprite[] icons = __instance.m_shared.m_icons; Contract contract = ContractOf(__instance); if (contract != null && icons != null && icons.Length >= 8) { bool flag = IsDone(__instance); Sprite val = (Plugin.Illustrated.Value ? Sketch.IconFor(contract, ZNetScene.instance, Plugin.NoticeHeading.Value, flag) : null); __result = val ?? icons[(int)(contract.Kind + (flag ? 4 : 0))] ?? __result; } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetScene_Awake { private static void Postfix(ZNetScene __instance) { Guarded(delegate { Register(__instance, ObjectDB.instance); }); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake { private static void Postfix(ObjectDB __instance) { Guarded(delegate { Register(ZNetScene.instance, __instance); }); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDB_CopyOtherDB { private static void Postfix(ObjectDB __instance) { Guarded(delegate { Register(ZNetScene.instance, __instance); }); } } public const string PrefabName = "marlthon_questheim_notice"; public const string ItemName = "$questheim_notice"; private const string KeyContract = "QuestHeim.contract"; internal static GameObject Prefab; private static GameObject _holder; private const int Kinds = 4; private const string KeyDone = "QuestHeim.done"; private static readonly FieldRef<InventoryGui, Container> OpenChest = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); public static void Register(ZNetScene scene, ObjectDB db) { if (!((Object)(object)scene == (Object)null) || !((Object)(object)db == (Object)null)) { scene = (((Object)(object)scene != (Object)null) ? scene : ZNetScene.instance); if ((Object)(object)Prefab == (Object)null && (Object)(object)scene != (Object)null) { Prefab = Build(scene); } if (!((Object)(object)Prefab == (Object)null)) { Prefab.GetComponent<ItemDrop>().m_itemData.m_dropPrefab = Prefab; ItemReload.Replace(scene, db, (IEnumerable<GameObject>)(object)new GameObject[1] { Prefab }); } } } public static void Forget() { Prefab = null; _holder = null; } public static void MarkDone(ItemData item, Contract c) { item.m_customData["QuestHeim.done"] = "1"; } private static bool IsDone(ItemData item) { string value; return item.m_customData.TryGetValue("QuestHeim.done", out value) && value == "1"; } public static bool Is(ItemData item) { return item != null && item.m_shared.m_name == "$questheim_notice"; } public static Contract ContractOf(ItemData item) { string value; return (Is(item) && item.m_customData.TryGetValue("QuestHeim.contract", out value)) ? Contract.Read(value) : null; } public static bool Give(Player player, Contract contract, bool dropIfFull) { //IL_008f: 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_009f: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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) if ((Object)(object)Prefab == (Object)null || (Object)(object)player == (Object)null) { return false; } ItemData val = Prefab.GetComponent<ItemDrop>().m_itemData.Clone(); val.m_dropPrefab = Prefab; val.m_stack = 1; val.m_customData["QuestHeim.contract"] = contract.Write(); if (((Humanoid)player).GetInventory().AddItem(val)) { return true; } if (!dropIfFull) { return false; } Transform transform = ((Component)player).transform; if ((Object)(object)ItemDrop.DropItem(val, 1, transform.position + transform.forward * 0.6f + Vector3.up, transform.rotation) == (Object)null) { return false; } ((Character)player).Message((MessageType)2, Translations.T("questheim_dropped"), 0, (Sprite)null, false); return true; } private static GameObject Build(ZNetScene scene) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = scene.GetPrefab("LeatherScraps"); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)"The game has no leather scraps to copy: no notices this session"); return null; } _holder = new GameObject("QuestHeim_items"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); GameObject val = Object.Instantiate<GameObject>(prefab, _holder.transform); ((Object)val).name = "marlthon_questheim_notice"; ItemDrop component = val.GetComponent<ItemDrop>(); SharedData shared = component.m_itemData.m_shared; shared.m_name = "$questheim_notice"; shared.m_description = "$questheim_notice_desc"; shared.m_itemType = (ItemType)16; shared.m_maxStackSize = 1; shared.m_autoStack = false; shared.m_value = 0; shared.m_weight = 0.1f; shared.m_teleportable = true; try { Dress(val, scene); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Notice look: " + ex.Message)); } Sprite[] array = (Sprite[])(object)new Sprite[8]; for (int i = 0; i < array.Length; i++) { array[i] = Paper.IconFor((Kind)(i % 4), scene, i >= 4); } if (array.All((Sprite val2) => (Object)(object)val2 != (Object)null)) { shared.m_icons = array; } component.m_itemData.m_dropPrefab = val; return val; } private static void Dress(GameObject go, ZNetScene scene) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { val.enabled = false; } Material val2 = Paper.For(Kind.Kill, scene); if (!((Object)(object)val2 == (Object)null)) { GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)3); Object.DestroyImmediate((Object)(object)val3.GetComponent<Collider>()); ((Object)val3).name = "questheim_sheet"; val3.transform.SetParent(go.transform, false); val3.transform.localScale = new Vector3(0.33f, 0.004f, 0.42f); ((Renderer)val3.GetComponent<MeshRenderer>()).sharedMaterial = val2; } } private static string Status(ItemData item, Contract c) { if (c.Kind == Kind.Kill) { int num = Kills.Progress(item); return (num >= c.Count) ? ("<color=#99e68c>" + Translations.T("questheim_status_done") + "</color>") : Translations.T("questheim_status_kills", num, c.Count); } Player localPlayer = Player.m_localPlayer; Inventory val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory() : null); object obj; if (!((Object)(object)InventoryGui.instance != (Object)null)) { obj = null; } else { Container obj2 = OpenChest.Invoke(InventoryGui.instance); obj = ((obj2 != null) ? obj2.GetInventory() : null); } Inventory val2 = (Inventory)obj; string text; if (val != null && val.ContainsItem(item)) { text = Translations.T("questheim_status_have", HandIn.CountOf(val, c.Target), c.Count); } else { if (val2 == null || !val2.ContainsItem(item)) { return Translations.T("questheim_status_needs", c.Count); } text = Translations.T("questheim_status_box", HandIn.CountOf(val2, c.Target), c.Count); } int num2 = HandIn.CountOf((val != null && val.ContainsItem(item)) ? val : val2, c.Target); return (num2 >= c.Count) ? ("<color=#99e68c>" + text + "</color>") : text; } private static void Guarded(Action register) { try { register(); } catch (Exception ex) { Plugin.Log.LogError((object)("Registering the notice failed: " + ex)); } } } internal static class Commands { private const string Owner = "QuestHeim"; private static readonly string[] ToolGuids = new string[2] { "com.quad.claudetools", "com.dhack.claudetools" }; private const string Usage = "questheim boards [radius]: the QuestHeim boards near the player, which way they face, their notices and materials | questheim names: prefab names the contract lists use that this game doesn't have, and the world's stage | questheim found: what discovery adds beyond the built-in lists (other mods' creatures, things, food, metals) | questheim spawns <creature>: its entries in the world's spawn lists | questheim sample [count] [stage]: notices as a board would write them, nothing posted | questheim sketch <kind> <prefab> <count> [runes|bounty|none]: a notice's illustrated paper and bag icon as PNGs in claude/shots | questheim post [count] [clear] [kill|gather|trophy|provisions ...]: put notices up (clear: take the others down first; kinds in place order) on the nearest board now (single player, host or devcommands)"; private static BaseUnityPlugin _registeredWith; private static float _nextLook; internal static void Update() { if (Time.unscaledTime < _nextLook) { return; } _nextLook = Time.unscaledTime + 2f; BaseUnityPlugin val = null; string[] toolGuids = ToolGuids; foreach (string key in toolGuids) { if (Chainloader.PluginInfos.TryGetValue(key, out var value) && (Object)(object)value.Instance != (Object)null) { val = value.Instance; break; } } if ((Object)(object)val == (Object)null || val == _registeredWith) { return; } _registeredWith = val; try { MethodInfo method = ((object)val).GetType().GetMethod("RegisterCommand", BindingFlags.Static | BindingFlags.Public); if (!(method == null)) { Type type = method.GetParameters()[3].ParameterType.GetGenericArguments()[1].GetGenericArguments()[0]; MethodInfo method2 = type.GetMethod("Parse", new Type[1] { typeof(string) }); object obj = typeof(Commands).GetMethod("Wrap", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(type).Invoke(null, new object[1] { method2 }); method.Invoke(null, new object[4] { "QuestHeim", "questheim", "questheim boards [radius]: the QuestHeim boards near the player, which way they face, their notices and materials | questheim names: prefab names the contract lists use that this game doesn't have, and the world's stage | questheim found: what discovery adds beyond the built-in lists (other mods' creatures, things, food, metals) | questheim spawns <creature>: its entries in the world's spawn lists | questheim sample [count] [stage]: notices as a board would write them, nothing posted | questheim sketch <kind> <prefab> <count> [runes|bounty|none]: a notice's illustrated paper and bag icon as PNGs in claude/shots | questheim post [count] [clear] [kill|gather|trophy|provisions ...]: put notices up (clear: take the others down first; kinds in place order) on the nearest board now (single player, host or devcommands)", obj }); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't add the 'questheim' command to Claude Tools (" + ex.Message + ").")); } } private static Func<string[], Action<T>, Action<string>, IEnumerator> Wrap<T>(MethodInfo parse) { Func<string, T> toJson = (Func<string, T>)Delegate.CreateDelegate(typeof(Func<string, T>), parse); return (string[] args, Action<T> output, Action<string> error) => Run(args, delegate(object o) { output(toJson(JsonConvert.SerializeObject(o))); }, error); } internal static void Unregister() { try { ((object)_registeredWith)?.GetType().GetMethod("UnregisterAll", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, new object[1] { "QuestHeim" }); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't remove the 'questheim' command (" + ex.Message + ").")); } _registeredWith = null; } private static IEnumerator Run(string[] args, Action<object> output, Action<string> error) { //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_0540: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected I4, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0dd7: Unknown result type (might be due to invalid IL or missing references) try { string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : ""); if (text == "spawns" && args.Length > 2) { List<string> list = new List<string>(); List<SpawnSystemList> list2 = new List<SpawnSystemList>(); GameObject prefab = ZNetScene.instance.GetPrefab("_ZoneCtrl"); SpawnSystem val = ((prefab != null) ? prefab.GetComponent<SpawnSystem>() : null); if ((Object)(object)val != (Object)null) { list2.AddRange(val.m_spawnLists); } foreach (SpawnSystemList item in list2) { foreach (SpawnData spawner in item.m_spawners) { if ((Object)(object)spawner.m_prefab != (Object)null && ((Object)spawner.m_prefab).name == args[2]) { list.Add($"{((Object)item).name}: biome={spawner.m_biome} ({(int)spawner.m_biome}) area={spawner.m_biomeArea} enabled={spawner.m_enabled} key='{spawner.m_requiredGlobalKey}' event='{spawner.m_requiredPersistentEvent}' night={spawner.m_spawnAtNight}/{spawner.m_spawnAtDay}"); } } } output(new Dictionary<string, object> { { "spawns", list } }); return null; } if (text == "post") { if ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()) && (!((Object)(object)Console.instance != (Object)null) || !((Terminal)Console.instance).IsCheatsEnabled())) { error("questheim post changes the world: single player, the host, or with devcommands."); return null; } Player me = Player.m_localPlayer; if ((Object)(object)me == (Object)null) { error("Not in a world."); return null; } NoticeBoard noticeBoard = (from b in NoticeBoard.Loaded where (Object)(object)b != (Object)null orderby Vector3.Distance(((Component)b).transform.position, ((Component)me).transform.position) select b).FirstOrDefault(); if ((Object)(object)noticeBoard == (Object)null || Vector3.Distance(((Component)noticeBoard).transform.position, ((Component)me).transform.position) > 20f) { error("No QuestHeim board within 20 m."); return null; } int result; int count = ((args.Length <= 2 || !int.TryParse(args[2], out result)) ? 1 : result); List<Kind> list3 = new List<Kind>(); bool clear = false; for (int num = 3; num < args.Length; num++) { Kind result2; if (args[num].Equals("clear", StringComparison.OrdinalIgnoreCase)) { clear = true; } else if (Enum.TryParse<Kind>(args[num], ignoreCase: true, out result2)) { list3.Add(result2); } } output(new Dictionary<string, object> { { "posted", noticeBoard.PostNow(count, list3, clear) } }); return null; } if (text == "sketch" && args.Length > 4) { if (!Enum.TryParse<Kind>(args[2], ignoreCase: true, out var result3)) { error("Kind: Kill, Gather, Trophy or Provisions."); return null; } int result4; Contract contract = new Contract { Kind = result3, Target = args[3], Count = ((!int.TryParse(args[4], out result4)) ? 1 : result4), Id = "sketch" }; Heading result5; Heading heading = ((args.Length > 5 && Enum.TryParse<Heading>(args[5], ignoreCase: true, out result5)) ? result5 : Plugin.NoticeHeading.Value); Material val2 = Sketch.For(contract, ZNetScene.instance, heading); Sprite val3 = Sketch.IconFor(contract, ZNetScene.instance, heading, done: false); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { error("No picture of " + args[3] + "."); return null; } string path = Path.Combine(Paths.BepInExRootPath, "claude", "shots"); string text2 = Path.Combine(path, $"questheim_sketch_{result3}_{args[3]}_{contract.Count}_{heading}.png"); string text3 = Path.Combine(path, $"questheim_icon_{result3}_{args[3]}_{heading}.png"); File.WriteAllBytes(text2, ImageConversion.EncodeToPNG((Texture2D)val2.mainTexture)); File.WriteAllBytes(text3, ImageConversion.EncodeToPNG(val3.texture)); output(new Dictionary<string, object> { { "paper", text2 }, { "icon", text3 }, { "picture", Sketch.PictureInfo(contract, ZNetScene.instance) } }); return null; } switch (text) { case "trophies": { List<string> list5 = new List<string>(); List<Entry> list6 = ContractData.AllEntries().ToList(); foreach (Entry item2 in list6.Where((Entry e) => e.Kind == Kind.Trophy)) { float chance; Entry entry = Contracts.TrophySource(item2.Prefab, list6, out chance); if (entry == null) { list5.Add($"t{item2.Tier} {item2.Prefab}: no creature found, priced @{item2.Value} x{item2.Count}"); continue; } float num4 = entry.Value / Mathf.Max(0.01f, chance); int num5 = Math.Max(1, Mathf.RoundToInt((float)entry.Count * chance)); list5.Add($"t{item2.Tier} {item2.Prefab} | {entry.Prefab} @{entry.Value} x{entry.Count} drops it {chance:P0} | " + $"usual x{num5}, each worth {num4:0}, notice for x{num5} pays {(float)num5 * num4 * Contracts.Premium(Kind.Trophy):0}"); } output(new Dictionary<string, object> { { "trophies", list5 } }); return null; } case "gathers": { List<string> list8 = new List<string>(); List<Entry> list9 = ContractData.AllEntries().ToList(); Dictionary<string, List<Gathering.Source>> dictionary = Gathering.Sources(); foreach (Entry g in from e in list9 where e.Kind == Kind.Gather orderby e.Tier select e) { List<Gathering.Source> value; string text4 = (dictionary.TryGetValue(g.Prefab, out value) ? string.Join(", ", from x in value.OrderByDescending((Gathering.Source x) => x.Each).Take(3) select $"{x.Prefab}[{x.Way}] {x.Each:0.##}") : "no source found"); bool flag = ContractData.Entries.Any((Entry e) => e.Kind == Kind.Gather && e.Prefab == g.Prefab); Gathering.Price(g, list9, out var usual, out var each); float cost; int most; string text5 = (Gathering.Easiest(g, list9, out cost, out most) ? $"one takes {cost:0.#}, most x{most}" : "no way found"); list8.Add(string.Format("t{0} {1}{2} | was x{3} @{4} = {5:0} | {6} | ", g.Tier, g.Prefab, flag ? "" : " (found)", g.Count, g.Value, (float)g.Count * g.Value, text5) + $"now x{usual} @{each:0.#} = {(float)usual * each:0} | {text4}"); } output(new Dictionary<string, object> { { "gathers", list8 } }); return null; } case "sample": { int result7; int num2 = ((args.Length > 2 && int.TryParse(args[2], out result7)) ? result7 : 10); int result8; int forTier = ((args.Length > 3 && int.TryParse(args[3], out result8)) ? result8 : (-1)); Random rnd = new Random(); List<string> list4 = new List<string>(); for (int num3 = 0; num3 < num2; num3++) { Contract contract2 = Contracts.Make(rnd, forTier); if (contract2 != null) { list4.Add($"t{contract2.Tier} {contract2.Kind} {contract2.Target} x{contract2.Count} -> {contract2.Reward}"); } } output(new Dictionary<string, object> { { "sample", list4 } }); return null; } case "found": { Discovery.Forget(); List<Entry> list7 = ContractData.AllEntries().ToList(); output(new Dictionary<string, object> { { "found", (from e in Discovery.Found orderby e.Tier, e.Kind select $"{e.Kind} t{e.Tier} {e.Prefab} x{e.Count} @{e.Value} ({Contracts.DisplayName(e.Prefab)})").ToList() }, { "foundRewards", Discovery.FoundPay.Select((PayEntry p) => $"t{p.Tier} {p.Prefab} @{p.Value} ({Contracts.DisplayName(p.Prefab)})").ToList() }, { "arrows", (from a in Discovery.Ammo orderby a.Tier select $"t{a.Tier} {a.Prefab} @{a.Value} ({Contracts.DisplayName(a.Prefab)})").ToList() }, { "valuables", Discovery.Valuables.Select((PayEntry v) => $"{v.Prefab} @{v.Value} ({Contracts.DisplayName(v.Prefab)})").ToList() }, { "creaturesSkipped", Discovery.Skipped() }, { "builtIn", ContractData.Entries.Count }, { "total", list7.Count } }); return null; } case "names": output(new Dictionary<string, object> { { "unknown", Contracts.Unknown() }, { "worldTier", Contracts.WorldTier() } }); return null; default: { if (text != "boards") { output(new Dictionary<string, object> { { "usage", "questheim boards [radius]: the QuestHeim boards near the player, which way they face, their notices and materials | questheim names: prefab names the contract lists use that this game doesn't have, and the world's stage | questheim found: what discovery adds beyond the built-in lists (other mods' creatures, things, food, metals) | questheim spawns <creature>: its entries in the world's spawn lists | questheim sample [count] [stage]: notices as a board would write them, nothing posted | questheim sketch <kind> <prefab> <count> [runes|bounty|none]: a notice's illustrated paper and bag icon as PNGs in claude/shots | questheim post [count] [clear] [kill|gather|trophy|provisions ...]: put notices up (clear: take the others down first; kinds in place order) on the nearest board now (single player, host or devcommands)" } }); return null; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { error("Not in a world."); return null; } float result6; float radius = ((args.Length > 2 && float.TryParse(args[2], out result6)) ? result6 : 30f); output(new Dictionary<string, object> { { "boards", Boards(((Component)localPlayer).transform.position, radius) } }); break; } } } catch (Exception ex) { error(ex.Message); } return null; } private static List<object> Boards(Vector3 from, float radius) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) List<object> list = new List<object>(); int stableHashCode = StringExtensionMethods.GetStableHashCode("marlthon_questheim_board"); ZNetView[] array = Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0); foreach (ZNetView val in array) { if ((Object)(object)val == (Object)null || val.GetZDO() == null || val.GetZDO().GetPrefab() != stableHashCode) { continue; } Transform transform = ((Component)val).transform; if (!(Vector3.Distance(transform.position, from) > radius)) { Transform val2 = transform.Find("questheim_look"); object obj; if (!((Object)(object)val2 != (Object)null)) { obj = null; } else { Transform obj2 = val2.Find("plank"); obj = ((obj2 != null) ? ((Component)obj2).GetComponent<MeshRenderer>() : null); } MeshRenderer r = (MeshRenderer)obj; object obj3; if (!((Object)(object)val2 != (Object)null)) { obj3 = null;