Decompiled source of StructureProtection v1.0.0

Landoria.StructureProtection.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.StructureProtection")]
[assembly: AssemblyDescription("Protects offline structures from deliberate creature targeting and player attacks inside active wards when no authorized player is online.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Landoria")]
[assembly: AssemblyProduct("Landoria.StructureProtection")]
[assembly: AssemblyCopyright("Copyright © 2026 End3rbyte")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("C6FAAFDF-2D25-4CD3-BD71-59BAA98F1D20")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("1.0.0.40065")]
namespace Landoria.StructureProtection
{
	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 CreatureProtection
	{
		[HarmonyPatch(typeof(StaticTarget), "IsPriorityTarget")]
		private static class PriorityTargetPatch
		{
			private static void Postfix(StaticTarget __instance, ref bool __result)
			{
				__result = CreatureProtectionPolicy.CanTarget(StructureProtectionPlugin.Settings.CreatureTargetingEnabled, __result, GetActivity(__instance));
			}
		}

		[HarmonyPatch(typeof(StaticTarget), "IsRandomTarget")]
		private static class RandomTargetPatch
		{
			private static void Postfix(StaticTarget __instance, ref bool __result)
			{
				__result = CreatureProtectionPolicy.CanTarget(StructureProtectionPlugin.Settings.CreatureTargetingEnabled, __result, GetActivity(__instance));
			}
		}

		[HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(StaticTarget) })]
		private static class VisibilityPatch
		{
			private static void Postfix(StaticTarget target, ref bool __result)
			{
				__result = CreatureProtectionPolicy.CanTarget(StructureProtectionPlugin.Settings.CreatureTargetingEnabled, __result, GetActivity(target));
			}
		}

		private static float GetActivity(StaticTarget target)
		{
			return PieceActivity.GetMultiplier((target != null) ? ((Component)target).GetComponentInParent<Piece>() : null);
		}
	}
	internal static class CreatureProtectionPolicy
	{
		internal static bool CanTarget(bool enabled, bool vanillaCanTarget, float activityMultiplier)
		{
			if (vanillaCanTarget)
			{
				if (enabled)
				{
					return activityMultiplier > 0f;
				}
				return true;
			}
			return false;
		}
	}
	[BepInPlugin("Landoria.StructureProtection", "Landoria.StructureProtection", "1.0.0")]
	public sealed class StructureProtectionPlugin : LandoriaPlugin
	{
		private const string PluginGuid = "Landoria.StructureProtection";

		private const string PluginName = "Landoria.StructureProtection";

		private const string PluginVersion = "1.0.0";

		internal static ModLog Log { get; private set; }

		internal static StructureProtectionSettings Settings { get; private set; }

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

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

		private void OnDestroy()
		{
			StructureProtectionSession.Reset();
			Log?.LogInfo("Landoria.StructureProtection 1.0.0 is unloaded.");
			ShutdownPlugin();
			Settings = null;
			Log = null;
		}
	}
	internal static class StructureProtectionArgumentPolicy
	{
		internal static bool Resolve(string[] arguments, string name, bool defaultValue)
		{
			string text = ReadValue(arguments, name);
			if (text == null)
			{
				return defaultValue;
			}
			if (bool.TryParse(text, out var result))
			{
				return result;
			}
			throw new InvalidOperationException("Command-line switch " + name + " requires true or false.");
		}

		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 sealed class StructureProtectionServerConfiguration
	{
		internal bool CreatureTargetingEnabled { get; private set; }

		internal bool WardPlayerDamageEnabled { get; private set; }

		internal static StructureProtectionServerConfiguration FromArguments(string[] arguments)
		{
			return new StructureProtectionServerConfiguration
			{
				CreatureTargetingEnabled = StructureProtectionArgumentPolicy.Resolve(arguments, "--structure-protection-creature-targeting", defaultValue: true),
				WardPlayerDamageEnabled = StructureProtectionArgumentPolicy.Resolve(arguments, "--structure-protection-ward-player-damage", defaultValue: true)
			};
		}
	}
	internal static class StructureProtectionSession
	{
		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class PlayerSpawnPatch
		{
			private static void Postfix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					identityServer = 0L;
					Update();
				}
			}
		}

		private const string IdentityRpc = "Landoria_StructureProtection_Identity";

		private const string SnapshotRpc = "Landoria_StructureProtection_Snapshot";

		private static readonly Dictionary<long, long> PeerPlayers = new Dictionary<long, long>();

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

		private static ZRoutedRpc registeredRpc;

		private static long identityServer;

		internal static void Update()
		{
			RegisterRpcs();
			SendLocalIdentity();
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && RemoveDisconnectedPeers())
			{
				BroadcastSnapshot();
			}
		}

		internal static void Reset()
		{
			registeredRpc = null;
			identityServer = 0L;
			ClearState();
		}

		private static void ClearState()
		{
			PeerPlayers.Clear();
			OnlinePlayers.Clear();
			StructureProtectionPlugin.Settings?.ResetClientState();
		}

		internal static HashSet<long> GetOnlinePlayers()
		{
			return new HashSet<long>(OnlinePlayers);
		}

		private static void RegisterRpcs()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != registeredRpc)
			{
				instance.Register<long>("Landoria_StructureProtection_Identity", (Action<long, long>)ReceiveIdentity);
				instance.Register<ZPackage>("Landoria_StructureProtection_Snapshot", (Action<long, ZPackage>)ReceiveSnapshot);
				ClearState();
				registeredRpc = instance;
				identityServer = 0L;
			}
		}

		private static void SendLocalIdentity()
		{
			ZNet instance = ZNet.instance;
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)localPlayer == (Object)null) && !instance.IsServer() && registeredRpc != null)
			{
				ZNetPeer serverPeer = instance.GetServerPeer();
				if (serverPeer != null && serverPeer.m_uid != identityServer)
				{
					identityServer = serverPeer.m_uid;
					registeredRpc.InvokeRoutedRPC(serverPeer.m_uid, "Landoria_StructureProtection_Identity", new object[1] { localPlayer.GetPlayerID() });
				}
			}
		}

		private static void ReceiveIdentity(long sender, long playerId)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ZNet.instance.GetPeer(sender) != null && playerId != 0L)
			{
				PeerPlayers[sender] = playerId;
				OnlinePlayers.Add(playerId);
				BroadcastSnapshot();
			}
		}

		private static bool RemoveDisconnectedPeers()
		{
			bool result = false;
			foreach (long item in new List<long>(PeerPlayers.Keys))
			{
				ZNetPeer peer = ZNet.instance.GetPeer(item);
				if (peer == null || !peer.IsReady())
				{
					OnlinePlayers.Remove(PeerPlayers[item]);
					PeerPlayers.Remove(item);
					result = true;
				}
			}
			return result;
		}

		private static void BroadcastSnapshot()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			if (registeredRpc != null)
			{
				ZPackage val = new ZPackage();
				WriteMappings(val);
				registeredRpc.InvokeRoutedRPC(ZRoutedRpc.Everybody, "Landoria_StructureProtection_Snapshot", new object[1] { val });
			}
		}

		private static void WriteMappings(ZPackage package)
		{
			StructureProtectionPlugin.Settings.WriteClientState(package);
			package.Write(PeerPlayers.Count);
			foreach (KeyValuePair<long, long> peerPlayer in PeerPlayers)
			{
				package.Write(peerPlayer.Value);
			}
		}

		private static void ReceiveSnapshot(long sender, ZPackage package)
		{
			if (IsTrustedServer(sender))
			{
				StructureProtectionPlugin.Settings.ReadClientState(package);
				OnlinePlayers.Clear();
				int num = package.ReadInt();
				for (int i = 0; i < num; i++)
				{
					long item = package.ReadLong();
					OnlinePlayers.Add(item);
				}
			}
		}

		private static bool IsTrustedServer(long sender)
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || instance.IsServer())
			{
				if ((Object)(object)instance != (Object)null)
				{
					return instance.IsServer();
				}
				return false;
			}
			ZNetPeer serverPeer = instance.GetServerPeer();
			if (serverPeer == null)
			{
				return false;
			}
			return serverPeer.m_uid == sender;
		}
	}
	internal sealed class StructureProtectionSettings
	{
		private bool serverInitialized;

		internal bool CreatureTargetingEnabled { get; private set; }

		internal bool WardPlayerDamageEnabled { get; private set; }

		internal void InitializeServer(ModLog logger)
		{
			if (!serverInitialized && ServerRole.IsDedicatedServer)
			{
				StructureProtectionServerConfiguration structureProtectionServerConfiguration = StructureProtectionServerConfiguration.FromArguments(Environment.GetCommandLineArgs());
				CreatureTargetingEnabled = structureProtectionServerConfiguration.CreatureTargetingEnabled;
				WardPlayerDamageEnabled = structureProtectionServerConfiguration.WardPlayerDamageEnabled;
				serverInitialized = true;
				logger.LogInfo("Effective structure protection settings: " + $"creatureTargeting={CreatureTargetingEnabled}, " + $"wardPlayerDamage={WardPlayerDamageEnabled}.");
			}
		}

		internal void WriteClientState(ZPackage package)
		{
			package.Write(CreatureTargetingEnabled);
		}

		internal void ReadClientState(ZPackage package)
		{
			CreatureTargetingEnabled = package.ReadBool();
		}

		internal void ResetClientState()
		{
			if (!serverInitialized)
			{
				CreatureTargetingEnabled = false;
				WardPlayerDamageEnabled = false;
			}
		}
	}
	internal static class PieceActivity
	{
		internal static float GetMultiplier(Piece piece)
		{
			if ((Object)(object)piece == (Object)null || !piece.IsPlacedByPlayer())
			{
				return 1f;
			}
			long creator = piece.GetCreator();
			if (creator == 0L)
			{
				return 1f;
			}
			if (!CreatorActivityPolicy.IsCreatorActive(creator, StructureProtectionSession.GetOnlinePlayers()))
			{
				return 0f;
			}
			return 1f;
		}
	}
	internal static class WardProtection
	{
		[HarmonyPatch(typeof(PrivateArea), "Awake")]
		private static class WardAwakePatch
		{
			private static void Postfix(PrivateArea __instance)
			{
				Wards.Add(__instance);
			}
		}

		[HarmonyPatch(typeof(PrivateArea), "OnDestroy")]
		private static class WardDestroyPatch
		{
			private static void Prefix(PrivateArea __instance)
			{
				Wards.Remove(__instance);
			}
		}

		[HarmonyPatch(typeof(WearNTear), "RPC_Damage")]
		private static class PlayerDamagePatch
		{
			private static bool Prefix(WearNTear __instance, HitData hit)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Invalid comparison between Unknown and I4
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				if (StructureProtectionPlugin.Settings.WardPlayerDamageEnabled && hit != null && (int)hit.m_hitType == 2)
				{
					return !ShouldBlockPlayerDamage(((Component)__instance).transform.position);
				}
				return true;
			}
		}

		private static readonly HashSet<PrivateArea> Wards = new HashSet<PrivateArea>();

		private static bool ShouldBlockPlayerDamage(Vector3 position)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			bool result = false;
			HashSet<long> onlinePlayers = StructureProtectionSession.GetOnlinePlayers();
			foreach (PrivateArea ward in Wards)
			{
				if (TryGetWardState(ward, position, out var creator, out var permitted))
				{
					result = true;
					if (WardProtectionPolicy.HasOnlineAuthorizedPlayer(creator, permitted, onlinePlayers))
					{
						return false;
					}
				}
			}
			return result;
		}

		private static bool TryGetWardState(PrivateArea ward, Vector3 position, out long creator, out List<long> permitted)
		{
			//IL_003d: 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)
			creator = 0L;
			permitted = null;
			ZNetView obj = (((Object)(object)ward != (Object)null) ? ((Component)ward).GetComponent<ZNetView>() : null);
			ZDO val = ((obj != null) ? obj.GetZDO() : null);
			if (val == null || !val.GetBool(ZDOVars.s_enabled, false) || Utils.DistanceXZ(((Component)ward).transform.position, position) >= ward.m_radius)
			{
				return false;
			}
			Piece component = ((Component)ward).GetComponent<Piece>();
			creator = (((Object)(object)component != (Object)null) ? component.GetCreator() : 0);
			permitted = ReadPermittedPlayers(val);
			return creator != 0;
		}

		private static List<long> ReadPermittedPlayers(ZDO zdo)
		{
			List<long> list = new List<long>();
			int num = zdo.GetInt(ZDOVars.s_permitted, 0);
			for (int i = 0; i < num; i++)
			{
				long num2 = zdo.GetLong("pu_id" + i, 0L);
				if (num2 != 0L)
				{
					list.Add(num2);
				}
			}
			return list;
		}
	}
	internal static class WardProtectionPolicy
	{
		internal static bool HasOnlineAuthorizedPlayer(long creator, IEnumerable<long> permittedPlayers, ISet<long> onlinePlayers)
		{
			if (onlinePlayers.Contains(creator))
			{
				return true;
			}
			foreach (long permittedPlayer in permittedPlayers)
			{
				if (onlinePlayers.Contains(permittedPlayer))
				{
					return true;
				}
			}
			return false;
		}
	}
}
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;
			}
		}
	}
}