using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace TempBed; [BepInPlugin("flo.tempbed", "TempBed", "1.3.0")] public class TempBedPlugin : BaseUnityPlugin { internal class ConfigurationManagerAttributes { public bool? ReadOnly; } public const string GUID = "flo.tempbed"; public const string NAME = "TempBed"; public const string VERSION = "1.3.0"; private const string RpcName = "TempBed_Cfg"; internal const string RpcSet = "TempBed_Set"; private const float PushInterval = 2f; internal const string ZdoSince = "flo_tb_since"; internal const string ZdoMark = "flo_tb_mark"; internal static ManualLogSource Log; internal static ConfigEntry cfgEnabled; internal static ConfigEntry cfgAllowPlacement; internal static ConfigEntry cfgDecayMinutes; internal static ConfigEntry cfgAnyStation; internal static ConfigEntry cfgStationNames; internal static ConfigEntry cfgOnlyUnsupportedPlaced; internal static ConfigEntry cfgPermanentWhenStationBuilt; internal static ConfigEntry cfgDropResources; internal static ConfigEntry cfgShowTimer; internal static ConfigEntry cfgTimerText; internal static ConfigEntry cfgIgnoreRoof; internal static ConfigEntry cfgIgnoreWet; internal static ConfigEntry cfgIgnoreFire; internal static ConfigEntry cfgServerSync; internal static bool ServerOverride; internal static bool IsAdminHere; private static bool applyingFromServer; internal static TempBedPlugin Instance; private static bool sEnabled = true; private static bool sAllowPlacement = true; private static float sDecayMinutes = 15f; private static bool sAnyStation; private static string sStationNames = "$piece_workbench"; private static bool sOnlyUnsupportedPlaced = true; private static bool sPermanent = true; private static bool sDropResources; private static bool sIgnoreRoof = true; private static bool sIgnoreWet = true; private static bool sIgnoreFire; private static readonly List LockAttributes = new List(); private Harmony harmony; internal float pushTimer; private int lastPeerCount = -1; private static readonly Dictionary OriginalStations = new Dictionary(); internal static bool IsRemoteClient => (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer(); internal static bool EffEnabled { get { if (ServerOverride) { return sEnabled; } if (IsRemoteClient) { return false; } return cfgEnabled.Value; } } internal static bool EffAllowPlacement => (!ServerOverride) ? cfgAllowPlacement.Value : sAllowPlacement; internal static float EffDecayMinutes => (!ServerOverride) ? cfgDecayMinutes.Value : sDecayMinutes; internal static bool EffAnyStation => (!ServerOverride) ? cfgAnyStation.Value : sAnyStation; internal static string EffStationNames => (!ServerOverride) ? cfgStationNames.Value : sStationNames; internal static bool EffOnlyUnsupportedPlaced => (!ServerOverride) ? cfgOnlyUnsupportedPlaced.Value : sOnlyUnsupportedPlaced; internal static bool EffPermanent => (!ServerOverride) ? cfgPermanentWhenStationBuilt.Value : sPermanent; internal static bool EffDropResources => (!ServerOverride) ? cfgDropResources.Value : sDropResources; internal static bool EffIgnoreRoof => (!ServerOverride) ? cfgIgnoreRoof.Value : sIgnoreRoof; internal static bool EffIgnoreWet => (!ServerOverride) ? cfgIgnoreWet.Value : sIgnoreWet; internal static bool EffIgnoreFire => (!ServerOverride) ? cfgIgnoreFire.Value : sIgnoreFire; private static ConfigDescription Desc(string text, AcceptableValueBase range) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes(); configurationManagerAttributes.ReadOnly = false; ConfigurationManagerAttributes configurationManagerAttributes2 = configurationManagerAttributes; LockAttributes.Add(configurationManagerAttributes2); return (range != null) ? new ConfigDescription(text, range, new object[1] { configurationManagerAttributes2 }) : new ConfigDescription(text, (AcceptableValueBase)null, new object[1] { configurationManagerAttributes2 }); } private static void SetLocked(bool locked) { for (int i = 0; i < LockAttributes.Count; i++) { LockAttributes[i].ReadOnly = locked; } } private void Awake() { //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; cfgEnabled = ((BaseUnityPlugin)this).Config.Bind("1 - Allgemein", "Enabled", true, Desc("Mod aktiv. false = alles bleibt Vanilla (Bett braucht wieder eine Werkbank).\nAuf Clients ohne Wirkung - dort gilt immer die Server-Einstellung.", null)); cfgAllowPlacement = ((BaseUnityPlugin)this).Config.Bind("2 - Bauen", "AllowPlacementWithoutStation", true, Desc("Betten können ohne Werkbank in Reichweite gebaut werden.", null)); cfgDecayMinutes = ((BaseUnityPlugin)this).Config.Bind("3 - Verfall", "DecayMinutes", 15f, Desc("Minuten, die ein Bett ohne Werkbank in Reichweite überlebt. Danach wird es abgebaut.\nDer Timer läuft über die Weltzeit, ein Server-Neustart verlängert ihn also nicht.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 1440f))); cfgOnlyUnsupportedPlaced = ((BaseUnityPlugin)this).Config.Bind("3 - Verfall", "OnlyBedsPlacedWithoutStation", true, Desc("true = nur Betten verfallen, die ohne Werkbank gesetzt wurden (bestehende Betten sind sicher).\nfalse = jedes Bett ohne Werkbank in Reichweite verfällt, auch älteres.", null)); cfgPermanentWhenStationBuilt = ((BaseUnityPlugin)this).Config.Bind("3 - Verfall", "PermanentWhenStationBuilt", true, Desc("Stellt jemand nachträglich eine Werkbank dazu, wird das Bett dauerhaft und verfällt auch später nicht mehr.", null)); cfgDropResources = ((BaseUnityPlugin)this).Config.Bind("3 - Verfall", "DropResources", false, Desc("true = beim Verfall fallen die Baumaterialien heraus.", null)); cfgAnyStation = ((BaseUnityPlugin)this).Config.Bind("4 - Werkbank", "AnyCraftingStation", false, Desc("true = jede Handwerksstation zählt (Werkbank, Schmiede, Steinschneider ...).\nfalse = nur die unter StationNames genannten.", null)); cfgStationNames = ((BaseUnityPlugin)this).Config.Bind("4 - Werkbank", "StationNames", "$piece_workbench", Desc("Kommagetrennte Liste der Stationen, die ein Bett stützen. Vanilla-Werkbank ist $piece_workbench.", null)); cfgIgnoreRoof = ((BaseUnityPlugin)this).Config.Bind("5 - Schlafen", "IgnoreRoofRequirement", true, Desc("Bett darf unter freiem Himmel benutzt werden - hebt \"Das Bett braucht ein Dach\" und \"zu ungeschützt\" auf.\nGilt auch fürs Setzen des Spawnpunkts.", null)); cfgIgnoreWet = ((BaseUnityPlugin)this).Config.Bind("5 - Schlafen", "IgnoreWetRequirement", true, Desc("Nass sein verhindert das Schlafen nicht mehr. Ohne Dach wird man im Regen sonst sofort nass\nund könnte trotz IgnoreRoofRequirement nicht schlafen.", null)); cfgIgnoreFire = ((BaseUnityPlugin)this).Config.Bind("5 - Schlafen", "IgnoreFireRequirement", false, Desc("Feuer in der Nähe wird nicht mehr verlangt. Vanilla verlangt es ohnehin nicht -\nnur relevant, wenn eine andere Mod das ändert.", null)); cfgShowTimer = ((BaseUnityPlugin)this).Config.Bind("6 - Anzeige", "ShowTimerInHoverText", true, Desc("Restzeit im Hover-Text des Bettes anzeigen.", null)); cfgTimerText = ((BaseUnityPlugin)this).Config.Bind("6 - Anzeige", "TimerText", "Ohne Werkbank - verfällt in {0}", Desc("{0} wird durch die Restzeit ersetzt (mm:ss).", null)); cfgServerSync = ((BaseUnityPlugin)this).Config.Bind("7 - Server", "ServerSync", true, "Nur serverseitig relevant: true = der Server erzwingt seine Werte bei allen Clients."); ((BaseUnityPlugin)this).Config.SettingChanged += OnLocalSettingChanged; harmony = new Harmony("flo.tempbed"); harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)"TempBed 1.3.0 geladen."); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null) { if (ServerOverride) { ServerOverride = false; IsAdminHere = false; SetLocked(locked: false); } } else { if (!ZNet.instance.IsServer() || !cfgServerSync.Value || ZRoutedRpc.instance == null) { return; } int count = ZNet.instance.GetPeers().Count; pushTimer -= Time.deltaTime; if (pushTimer > 0f && count == lastPeerCount) { return; } lastPeerCount = count; pushTimer = 2f; try { string text = Serialize(); List peers = ZNet.instance.GetPeers(); for (int i = 0; i < peers.Count; i++) { ZNetPeer val = peers[i]; if (val != null) { bool flag = val.m_socket != null && ZNet.instance.IsAdmin(val.m_socket.GetHostName()); ZPackage val2 = new ZPackage(); val2.Write(text + "|" + ((!flag) ? "0" : "1")); ZRoutedRpc.instance.InvokeRoutedRPC(val.m_uid, "TempBed_Cfg", new object[1] { val2 }); } } } catch (Exception ex) { Log.LogWarning((object)("Config-Push fehlgeschlagen: " + ex.Message)); } } } private static string Serialize() { return string.Join("|", "1", (!EffEnabled) ? "0" : "1", (!EffAllowPlacement) ? "0" : "1", EffDecayMinutes.ToString(CultureInfo.InvariantCulture), (!EffAnyStation) ? "0" : "1", (!EffOnlyUnsupportedPlaced) ? "0" : "1", (!EffPermanent) ? "0" : "1", (!EffDropResources) ? "0" : "1", EffStationNames.Replace('|', ','), (!EffIgnoreRoof) ? "0" : "1", (!EffIgnoreWet) ? "0" : "1", (!EffIgnoreFire) ? "0" : "1"); } internal static void RPC_Config(long sender, ZPackage pkg) { try { if (((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) || pkg == null) { return; } string text = pkg.ReadString(); if (string.IsNullOrEmpty(text)) { return; } string[] array = text.Split('|'); if (array.Length >= 12 && !(array[0] != "1")) { bool flag = !ServerOverride; sEnabled = array[1] == "1"; sAllowPlacement = array[2] == "1"; sDecayMinutes = float.Parse(array[3], CultureInfo.InvariantCulture); sAnyStation = array[4] == "1"; sOnlyUnsupportedPlaced = array[5] == "1"; sPermanent = array[6] == "1"; sDropResources = array[7] == "1"; sStationNames = array[8]; sIgnoreRoof = array[9] == "1"; sIgnoreWet = array[10] == "1"; sIgnoreFire = array[11] == "1"; ServerOverride = true; IsAdminHere = array.Length > 12 && array[12] == "1"; SetLocked(!IsAdminHere); if (IsAdminHere) { MirrorToConfig(); } ApplyPrefabs(); if (flag) { Log.LogInfo((object)("Server-Konfiguration übernommen: Verfall nach " + sDecayMinutes + " min.")); } } } catch (Exception ex) { Log.LogWarning((object)("Server-Config konnte nicht gelesen werden: " + ex.Message)); } } private static string ConfigString() { return string.Join("|", (!cfgEnabled.Value) ? "0" : "1", (!cfgAllowPlacement.Value) ? "0" : "1", cfgDecayMinutes.Value.ToString(CultureInfo.InvariantCulture), (!cfgAnyStation.Value) ? "0" : "1", (!cfgOnlyUnsupportedPlaced.Value) ? "0" : "1", (!cfgPermanentWhenStationBuilt.Value) ? "0" : "1", (!cfgDropResources.Value) ? "0" : "1", cfgStationNames.Value.Replace('|', ','), (!cfgIgnoreRoof.Value) ? "0" : "1", (!cfgIgnoreWet.Value) ? "0" : "1", (!cfgIgnoreFire.Value) ? "0" : "1"); } private static void MirrorToConfig() { applyingFromServer = true; try { cfgEnabled.Value = sEnabled; cfgAllowPlacement.Value = sAllowPlacement; cfgDecayMinutes.Value = sDecayMinutes; cfgAnyStation.Value = sAnyStation; cfgOnlyUnsupportedPlaced.Value = sOnlyUnsupportedPlaced; cfgPermanentWhenStationBuilt.Value = sPermanent; cfgDropResources.Value = sDropResources; cfgStationNames.Value = sStationNames; cfgIgnoreRoof.Value = sIgnoreRoof; cfgIgnoreWet.Value = sIgnoreWet; cfgIgnoreFire.Value = sIgnoreFire; } catch (Exception ex) { Log.LogWarning((object)("Spiegeln: " + ex.Message)); } finally { applyingFromServer = false; } } private void OnLocalSettingChanged(object sender, SettingChangedEventArgs e) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if (applyingFromServer || !IsRemoteClient || !IsAdminHere) { return; } try { if (ZRoutedRpc.instance != null) { ZPackage val = new ZPackage(); val.Write(ConfigString()); ZRoutedRpc.instance.InvokeRoutedRPC("TempBed_Set", new object[1] { val }); } } catch (Exception ex) { Log.LogWarning((object)("Senden an Server fehlgeschlagen: " + ex.Message)); } } private static bool SenderIsAdmin(long sender) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return false; } ZNetPeer peer = instance.GetPeer(sender); if (peer == null || peer.m_socket == null) { return false; } return instance.IsAdmin(peer.m_socket.GetHostName()); } internal static void RPC_SetConfig(long sender, ZPackage pkg) { try { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || pkg == null) { return; } if (!SenderIsAdmin(sender)) { Log.LogWarning((object)("Konfigurationsänderung von Nicht-Admin abgelehnt (Peer " + sender + ").")); return; } string[] array = pkg.ReadString().Split('|'); if (array.Length < 8) { return; } applyingFromServer = true; try { cfgEnabled.Value = array[0] == "1"; cfgAllowPlacement.Value = array[1] == "1"; cfgDecayMinutes.Value = float.Parse(array[2], CultureInfo.InvariantCulture); cfgAnyStation.Value = array[3] == "1"; cfgOnlyUnsupportedPlaced.Value = array[4] == "1"; cfgPermanentWhenStationBuilt.Value = array[5] == "1"; cfgDropResources.Value = array[6] == "1"; cfgStationNames.Value = array[7]; if (array.Length > 10) { cfgIgnoreRoof.Value = array[8] == "1"; cfgIgnoreWet.Value = array[9] == "1"; cfgIgnoreFire.Value = array[10] == "1"; } } finally { applyingFromServer = false; } Log.LogInfo((object)("Konfiguration durch Admin geändert (Peer " + sender + ").")); ApplyPrefabs(); if ((Object)(object)Instance != (Object)null) { Instance.pushTimer = 0f; } } catch (Exception ex) { Log.LogWarning((object)("Adminänderung konnte nicht übernommen werden: " + ex.Message)); } } internal static void ApplyPrefabs() { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return; } bool flag = EffEnabled && EffAllowPlacement; int num = 0; foreach (GameObject prefab in instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Bed component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { continue; } Piece component2 = prefab.GetComponent(); if ((Object)(object)component2 != (Object)null) { CraftingStation value; if (flag) { if ((Object)(object)component2.m_craftingStation != (Object)null) { OriginalStations[((Object)prefab).name] = component2.m_craftingStation; component2.m_craftingStation = null; } } else if ((Object)(object)component2.m_craftingStation == (Object)null && OriginalStations.TryGetValue(((Object)prefab).name, out value)) { component2.m_craftingStation = value; } } if ((Object)(object)prefab.GetComponent() == (Object)null) { prefab.AddComponent(); } num++; } Log.LogInfo((object)(num + " Bett-Prefabs angepasst (ohne Werkbank baubar: " + flag + ").")); } internal static bool HasSupportingStation(Vector3 pos) { //IL_00b6: 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_0049: Unknown result type (might be due to invalid IL or missing references) try { if (EffAnyStation) { List instances = CraftingStation.Instances; if (instances == null) { return false; } for (int i = 0; i < instances.Count; i++) { IMonoUpdater obj = instances[i]; CraftingStation val = (CraftingStation)(object)((obj is CraftingStation) ? obj : null); if (!((Object)(object)val == (Object)null) && Vector3.Distance(pos, ((Component)val).transform.position) <= val.GetStationBuildRange()) { return true; } } return false; } string[] array = EffStationNames.Split(','); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length != 0 && (Object)(object)CraftingStation.HaveBuildStationInRange(text2, pos) != (Object)null) { return true; } } return false; } catch (Exception ex) { Log.LogWarning((object)("Stationsprüfung: " + ex.Message)); return true; } } internal static float RemainingSeconds(ZDO zdo) { if (zdo == null || (Object)(object)ZNet.instance == (Object)null) { return -1f; } long num = zdo.GetLong("flo_tb_since", 0L); if (num == 0) { return -1f; } double timeSeconds = ZNet.instance.GetTimeSeconds(); float num2 = (float)((double)EffDecayMinutes * 60.0 - (timeSeconds - (double)num)); return (!(num2 < 0f)) ? num2 : 0f; } } public class BedDecay : MonoBehaviour { private ZNetView nview; private float timer; private void Awake() { nview = ((Component)this).GetComponent(); timer = Random.Range(0f, 1f); } private void Update() { timer -= Time.deltaTime; if (!(timer > 0f)) { timer = 1f; Tick(); } } private void Tick() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (!TempBedPlugin.EffEnabled || (Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner() || (Object)(object)ZNet.instance == (Object)null) { return; } ZDO zDO = nview.GetZDO(); if (zDO == null || (TempBedPlugin.EffOnlyUnsupportedPlaced && zDO.GetInt("flo_tb_mark", 0) == 0)) { return; } bool flag = TempBedPlugin.HasSupportingStation(((Component)this).transform.position); long num = (long)ZNet.instance.GetTimeSeconds(); if (flag) { if (zDO.GetLong("flo_tb_since", 0L) != 0) { zDO.Set("flo_tb_since", 0L); } if (TempBedPlugin.EffPermanent && zDO.GetInt("flo_tb_mark", 0) != 0) { zDO.Set("flo_tb_mark", 0); } return; } long num2 = zDO.GetLong("flo_tb_since", 0L); if (num2 == 0 || num2 > num) { zDO.Set("flo_tb_since", num); } else if (num - num2 >= (long)(TempBedPlugin.EffDecayMinutes * 60f)) { TempBedPlugin.Log.LogInfo((object)("Bett ohne Werkbank verfallen bei " + ((Component)this).transform.position)); WearNTear component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null) { component.Remove(!TempBedPlugin.EffDropResources); } else { nview.Destroy(); } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class Patch_ZNetScene_Awake { private static void Postfix() { TempBedPlugin.ApplyPrefabs(); } } [HarmonyPatch(typeof(Piece), "OnPlaced")] internal static class Patch_Piece_OnPlaced { private static void Postfix(Piece __instance) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (!TempBedPlugin.EffEnabled || (Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).GetComponent() == (Object)null) { return; } ZNetView component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return; } ZDO zDO = component.GetZDO(); if (zDO != null) { bool flag = TempBedPlugin.HasSupportingStation(((Component)__instance).transform.position); zDO.Set("flo_tb_mark", (!flag) ? 1 : 0); if (!flag && (Object)(object)ZNet.instance != (Object)null) { zDO.Set("flo_tb_since", (long)ZNet.instance.GetTimeSeconds()); } } } } [HarmonyPatch(typeof(Bed), "GetHoverText")] internal static class Patch_Bed_GetHoverText { private static void Postfix(Bed __instance, ref string __result) { try { if (!TempBedPlugin.EffEnabled || !TempBedPlugin.cfgShowTimer.Value) { return; } ZNetView component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (zDO != null && (!TempBedPlugin.EffOnlyUnsupportedPlaced || zDO.GetInt("flo_tb_mark", 0) != 0)) { float num = TempBedPlugin.RemainingSeconds(zDO); if (!(num < 0f)) { int num2 = (int)(num / 60f); int num3 = (int)(num % 60f); string arg = num2 + ":" + num3.ToString("00"); __result = __result + "\n" + string.Format(TempBedPlugin.cfgTimerText.Value, arg) + ""; } } } catch { } } } [HarmonyPatch(typeof(Bed), "CheckExposure")] internal static class Patch_Bed_CheckExposure { private static bool Prefix(ref bool __result) { if (!TempBedPlugin.EffEnabled || !TempBedPlugin.EffIgnoreRoof) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Bed), "CheckWet")] internal static class Patch_Bed_CheckWet { private static bool Prefix(ref bool __result) { if (!TempBedPlugin.EffEnabled || !TempBedPlugin.EffIgnoreWet) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Bed), "CheckFire")] internal static class Patch_Bed_CheckFire { private static bool Prefix(ref bool __result) { if (!TempBedPlugin.EffEnabled || !TempBedPlugin.EffIgnoreFire) { return true; } __result = true; return false; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class Patch_ZRoutedRpc_Ctor { private static void Postfix(ZRoutedRpc __instance) { __instance.Register("TempBed_Cfg", (Action)TempBedPlugin.RPC_Config); __instance.Register("TempBed_Set", (Action)TempBedPlugin.RPC_SetConfig); } }