Decompiled source of DecayControl v1.0.0

Landoria.DecayControl.dll

Decompiled 21 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Landoria.SharedLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Landoria.DecayControl")]
[assembly: AssemblyDescription("Controls rain wear and fuel consumption for player-built pieces.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Landoria")]
[assembly: AssemblyProduct("Landoria.DecayControl")]
[assembly: AssemblyCopyright("Copyright © 2026 End3rbyte")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("0F691AC2-F9E1-45CB-B34E-7B57171ADCE7")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("1.0.0.40036")]
namespace Landoria.DecayControl
{
	internal static class CreatorActivityPolicy
	{
		internal static HashSet<long> GetActiveCreators(IEnumerable<long> onlinePlayers)
		{
			return new HashSet<long>(onlinePlayers);
		}

		internal static bool IsCreatorActive(long creator, ISet<long> onlinePlayers)
		{
			return onlinePlayers.Contains(creator);
		}
	}
	internal static class DecayControlArgumentPolicy
	{
		internal static DecayControlMode Resolve(string[] arguments, string name, DecayControlMode configured)
		{
			string text = ReadValue(arguments, name);
			if (text == null)
			{
				return configured;
			}
			if (string.Equals(text, "default", StringComparison.OrdinalIgnoreCase))
			{
				return DecayControlMode.Default;
			}
			if (string.Equals(text, "player-online", StringComparison.OrdinalIgnoreCase))
			{
				return DecayControlMode.PlayerOnline;
			}
			if (string.Equals(text, "disabled", StringComparison.OrdinalIgnoreCase))
			{
				return DecayControlMode.Disabled;
			}
			throw new InvalidOperationException("Command-line switch " + name + " requires default, player-online, or disabled.");
		}

		private static string ReadValue(string[] arguments, string name)
		{
			string text = null;
			for (int i = 0; i < arguments.Length; i++)
			{
				if (string.Equals(arguments[i], name, StringComparison.OrdinalIgnoreCase))
				{
					if (text != null || i + 1 >= arguments.Length)
					{
						throw new InvalidOperationException("Command-line switch " + name + " is missing or duplicated.");
					}
					text = arguments[++i];
				}
			}
			return text;
		}
	}
	internal enum DecayControlMode
	{
		Default,
		PlayerOnline,
		Disabled
	}
	internal static class DecayEffectPolicy
	{
		internal static bool ShouldApplyEnvironmentalWear(bool isVanillaRainTick, bool isPlayerBuilt, DecayControlMode mode, float activityMultiplier)
		{
			if (isVanillaRainTick && isPlayerBuilt)
			{
				switch (mode)
				{
				case DecayControlMode.Default:
					break;
				case DecayControlMode.PlayerOnline:
					return activityMultiplier > 0f;
				default:
					return false;
				}
			}
			return true;
		}

		internal static bool ShouldPauseFuel(bool isPlayerBuilt, bool firstUpdate, DecayControlMode mode, float activityMultiplier)
		{
			if (!isPlayerBuilt || mode == DecayControlMode.Default)
			{
				return false;
			}
			if (!(mode == DecayControlMode.Disabled || firstUpdate))
			{
				return activityMultiplier <= 0f;
			}
			return true;
		}
	}
	internal static class DecayProtection
	{
		[HarmonyPatch(typeof(WearNTear), "ApplyDamage")]
		private static class RainDamagePatch
		{
			private static bool Prefix(WearNTear __instance, float damage, HitData hitData)
			{
				float num = __instance.m_health * 0.05f;
				bool isVanillaRainTick = hitData == null && __instance.IsWet() && __instance.GetHealthPercentage() > 0.5f && Mathf.Approximately(damage, num);
				Piece component = ((Component)__instance).GetComponent<Piece>();
				return DecayEffectPolicy.ShouldApplyEnvironmentalWear(isPlayerBuilt: (Object)(object)component != (Object)null && component.IsPlacedByPlayer(), activityMultiplier: GetActivityMultiplier(component), isVanillaRainTick: isVanillaRainTick, mode: DecayControlPlugin.Settings.EnvironmentalBuildingWear);
			}
		}

		[HarmonyPatch(typeof(Fireplace), "UpdateFireplace")]
		private static class FireplaceFuelPatch
		{
			private static void Prefix(Fireplace __instance, out float __state)
			{
				__state = __instance.m_secPerFuel;
				Piece component = ((Component)__instance).GetComponent<Piece>();
				int num;
				int num2;
				if ((Object)(object)component != (Object)null)
				{
					num = (component.IsPlacedByPlayer() ? 1 : 0);
					if (num != 0)
					{
						num2 = ((!initializedFireplaces.TryGetValue(__instance, out var _)) ? 1 : 0);
						goto IL_0037;
					}
				}
				else
				{
					num = 0;
				}
				num2 = 0;
				goto IL_0037;
				IL_0037:
				bool flag = (byte)num2 != 0;
				if (flag)
				{
					initializedFireplaces.Add(__instance, new object());
				}
				if (DecayEffectPolicy.ShouldPauseFuel(activityMultiplier: GetActivityMultiplier(component), isPlayerBuilt: (byte)num != 0, firstUpdate: flag, mode: DecayControlPlugin.Settings.FuelConsumption))
				{
					__instance.m_secPerFuel = float.PositiveInfinity;
				}
			}

			private static void Postfix(Fireplace __instance, float __state)
			{
				__instance.m_secPerFuel = __state;
			}
		}

		private const float VanillaRainDamageFraction = 0.05f;

		private static readonly HashSet<long> ActiveCreators = new HashSet<long>();

		private static ConditionalWeakTable<Fireplace, object> initializedFireplaces = new ConditionalWeakTable<Fireplace, object>();

		private static bool hasServerState;

		internal static void Reset()
		{
			ActiveCreators.Clear();
			hasServerState = false;
			initializedFireplaces = new ConditionalWeakTable<Fireplace, object>();
		}

		internal static void WriteState(ZPackage package)
		{
			HashSet<long> activeCreators = GetActiveCreators();
			package.Write(activeCreators.Count);
			foreach (long item in activeCreators)
			{
				package.Write(item);
			}
		}

		internal static void ReadState(ZPackage package)
		{
			ActiveCreators.Clear();
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				ActiveCreators.Add(package.ReadLong());
			}
			hasServerState = true;
		}

		internal static float GetActivityMultiplier(Piece piece)
		{
			if ((Object)(object)piece == (Object)null || !piece.IsPlacedByPlayer())
			{
				return 1f;
			}
			long creator = piece.GetCreator();
			if (creator == 0L)
			{
				return 1f;
			}
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				if (!IsCreatorActive(creator, GetOnlinePlayers()))
				{
					return 0f;
				}
				return 1f;
			}
			if (hasServerState && !ActiveCreators.Contains(creator))
			{
				return 0f;
			}
			return 1f;
		}

		private static HashSet<long> GetActiveCreators()
		{
			return CreatorActivityPolicy.GetActiveCreators(GetOnlinePlayers());
		}

		private static bool IsCreatorActive(long creator, HashSet<long> onlinePlayers)
		{
			return CreatorActivityPolicy.IsCreatorActive(creator, onlinePlayers);
		}

		private static HashSet<long> GetOnlinePlayers()
		{
			HashSet<long> hashSet = new HashSet<long>();
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return hashSet;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer.IsReady() && !((ZDOID)(ref peer.m_characterID)).IsNone())
				{
					hashSet.Add(((ZDOID)(ref peer.m_characterID)).UserID);
				}
			}
			if (!ServerRole.IsDedicatedServer && (Object)(object)Game.instance != (Object)null)
			{
				hashSet.Add(Game.instance.GetPlayerProfile().GetPlayerID());
			}
			return hashSet;
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class DecayStateOnSpawnPatch
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				DecayStateRpc.RequestOnSpawn();
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnDestroy")]
	internal static class DecayControlDisconnectPatch
	{
		private static void Prefix()
		{
			DecayStateRpc.ResetSession();
		}
	}
	internal static class DecayStateRpc
	{
		private const string RequestRpc = "Landoria_DecayControl_Request";

		private const string ResponseRpc = "Landoria_DecayControl_Response";

		private static ZRoutedRpc registeredRpc;

		private static ZNetPeer serverPeer;

		private static bool requestSent;

		internal static void Update()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != registeredRpc)
			{
				instance.Register("Landoria_DecayControl_Request", (Action<long>)ReceiveRequest);
				instance.Register<ZPackage>("Landoria_DecayControl_Response", (Action<long, ZPackage>)ReceiveResponse);
				registeredRpc = instance;
			}
		}

		internal static void RequestOnSpawn()
		{
			Update();
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && ZRoutedRpc.instance != null && !requestSent)
			{
				serverPeer = ZNet.instance.GetServerPeer();
				if (serverPeer != null)
				{
					requestSent = true;
					ZRoutedRpc.instance.InvokeRoutedRPC(serverPeer.m_uid, "Landoria_DecayControl_Request", Array.Empty<object>());
				}
			}
		}

		internal static void ResetSession()
		{
			serverPeer = null;
			requestSent = false;
			DecayControlPlugin.Settings?.ResetState();
			DecayProtection.Reset();
		}

		private static void ReceiveRequest(long sender)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if (ServerRole.IsDedicatedServer && ZNet.instance.GetPeer(sender) != null && ZRoutedRpc.instance != null)
			{
				ZPackage val = new ZPackage();
				DecayControlPlugin.Settings.WriteState(val);
				DecayProtection.WriteState(val);
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Landoria_DecayControl_Response", new object[1] { val });
			}
		}

		private static void ReceiveResponse(long sender, ZPackage package)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && serverPeer != null && serverPeer.m_uid == sender)
			{
				DecayControlPlugin.Settings.ReadState(package);
				DecayProtection.ReadState(package);
			}
		}
	}
	[BepInPlugin("Landoria.DecayControl", "Landoria.DecayControl", "1.0.0")]
	public sealed class DecayControlPlugin : LandoriaPlugin
	{
		private const string PluginGuid = "Landoria.DecayControl";

		private const string PluginName = "Landoria.DecayControl";

		private const string PluginVersion = "1.0.0";

		internal static ModLog Log { get; private set; }

		internal static DecayControlSettings Settings { get; private set; }

		private void Awake()
		{
			Log = InitializePlugin("Landoria.DecayControl");
			Settings = new DecayControlSettings();
			Settings.InitializeServer(Log);
			Log.LogInfo("Landoria.DecayControl 1.0.0 is loaded.");
		}

		private void Update()
		{
			DecayStateRpc.Update();
		}

		private void OnDestroy()
		{
			DecayStateRpc.ResetSession();
			DecayProtection.Reset();
			Log?.LogInfo("Landoria.DecayControl 1.0.0 is unloaded.");
			ShutdownPlugin();
			Settings = null;
			Log = null;
		}
	}
	internal sealed class DecayControlServerConfiguration
	{
		internal DecayControlMode FuelConsumption { get; private set; }

		internal DecayControlMode EnvironmentalBuildingWear { get; private set; }

		internal static DecayControlServerConfiguration FromArguments(string[] arguments)
		{
			return new DecayControlServerConfiguration
			{
				FuelConsumption = DecayControlArgumentPolicy.Resolve(arguments, "--decay-control-fuel-consumption", DecayControlMode.Default),
				EnvironmentalBuildingWear = DecayControlArgumentPolicy.Resolve(arguments, "--decay-control-environmental-building-wear", DecayControlMode.Default)
			};
		}
	}
	internal sealed class DecayControlSettings
	{
		private bool serverInitialized;

		internal DecayControlMode FuelConsumption { get; private set; }

		internal DecayControlMode EnvironmentalBuildingWear { get; private set; }

		internal DecayControlSettings()
		{
			ResetState();
		}

		internal void InitializeServer(ModLog logger)
		{
			if (!serverInitialized && ServerRole.IsDedicatedServer)
			{
				DecayControlServerConfiguration decayControlServerConfiguration = DecayControlServerConfiguration.FromArguments(Environment.GetCommandLineArgs());
				FuelConsumption = decayControlServerConfiguration.FuelConsumption;
				EnvironmentalBuildingWear = decayControlServerConfiguration.EnvironmentalBuildingWear;
				serverInitialized = true;
				logger.LogInfo($"Effective decay settings: fuelConsumption={FuelConsumption}, " + $"environmentalBuildingWear={EnvironmentalBuildingWear}.");
			}
		}

		internal void WriteState(ZPackage package)
		{
			package.Write((int)FuelConsumption);
			package.Write((int)EnvironmentalBuildingWear);
		}

		internal void ReadState(ZPackage package)
		{
			FuelConsumption = (DecayControlMode)package.ReadInt();
			EnvironmentalBuildingWear = (DecayControlMode)package.ReadInt();
		}

		internal void ResetState()
		{
			if (!serverInitialized)
			{
				FuelConsumption = DecayControlMode.Default;
				EnvironmentalBuildingWear = DecayControlMode.Default;
			}
		}
	}
}
namespace Landoria.SharedLib
{
	public abstract class LandoriaPlugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		private bool _patchesApplied;

		protected ModLog InitializePlugin(string pluginGuid)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			ModLog modLog = new ModLog(((BaseUnityPlugin)this).Logger);
			Version version = ((object)this).GetType().Assembly.GetName().Version;
			modLog.LogInfo($"AssemblyVersion: {version}.");
			_harmony = new Harmony(pluginGuid);
			PatchOwnNamespace(modLog);
			return modLog;
		}

		protected void PatchOwnNamespace(ModLog log)
		{
			if (_patchesApplied)
			{
				log.LogDebug("Harmony patches are already active; skipping registration.");
				return;
			}
			string text = ((object)this).GetType().Namespace;
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				if (type.Namespace == text)
				{
					_harmony.CreateClassProcessor(type).Patch();
				}
			}
			_patchesApplied = true;
			log.LogDebug("Harmony patches were applied for the plugin namespace.");
		}

		protected void ShutdownPlugin()
		{
			if (_patchesApplied)
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
				_patchesApplied = false;
			}
		}
	}
	public sealed class ModLog
	{
		private readonly ManualLogSource _logger;

		public ModLog(ManualLogSource logger)
		{
			_logger = logger;
		}

		public void LogFatal(object message)
		{
			Write((LogLevel)1, message);
		}

		public void LogError(object message)
		{
			Write((LogLevel)2, message);
		}

		public void LogWarning(object message)
		{
			Write((LogLevel)4, message);
		}

		public void LogMessage(object message)
		{
			Write((LogLevel)8, message);
		}

		public void LogInfo(object message)
		{
			Write((LogLevel)16, message);
		}

		public void LogDebug(object message)
		{
			Write((LogLevel)32, message);
		}

		public void Log(LogLevel level, object message)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Write(level, message);
		}

		private void Write(LogLevel level, object message)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			string arg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
			_logger.Log(level, (object)$"[{arg}] {message}");
		}
	}
	public static class ServerRole
	{
		public static bool IsDedicatedServer
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					return ZNet.instance.IsDedicated();
				}
				return false;
			}
		}
	}
}