Decompiled source of RepairEnemyStuctures v1.0.1

RepairEnemyStructures.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ConditionalConfigSync;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RepairEnemyStructures")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("RepairEnemyStructures")]
[assembly: AssemblyTitle("RepairEnemyStructures")]
[assembly: AssemblyVersion("1.0.1.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 RepairEnemyStructures
{
	public enum Station
	{
		None,
		Workbench,
		Cauldron,
		Forge,
		ArtisanTable,
		Stonecutter,
		MageTable,
		BlackForge
	}
	internal class RepairRequiresStation : MonoBehaviour
	{
		public string StationName;
	}
	[BepInPlugin("com.dreich.repairenemystructures", "Repair Enemy Structures", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class RepairEnemyStructuresPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.dreich.repairenemystructures";

		public const string PluginName = "Repair Enemy Structures";

		public const string PluginVersion = "1.0.1";

		internal const string ConfigSyncGuid = "_shudnal.ConditionalConfigSync";

		internal static bool ConfigSyncAvailable;

		private static ConfigEntry<bool> lockConfigurationSetting;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> RepairDvergr;

		internal static ConfigEntry<bool> RepairFuling;

		internal static ConfigEntry<string> DvergrPrefabKeywords;

		internal static ConfigEntry<string> FulingPrefabKeywords;

		internal static ConfigEntry<Station> FulingStation;

		internal static ConfigEntry<Station> DvergrDefaultStation;

		internal static ConfigEntry<string> DvergrGroupAKeywords;

		internal static ConfigEntry<Station> DvergrGroupAStation;

		internal static ConfigEntry<string> DvergrGroupBKeywords;

		internal static ConfigEntry<Station> DvergrGroupBStation;

		internal static ConfigEntry<string> StationOverrides;

		internal static ConfigEntry<string> RepairEffectPrefab;

		internal static ConfigEntry<bool> LogPatched;

		internal static ConfigEntry<bool> LogUnmatchedStructures;

		private static Harmony harmony;

		private void Awake()
		{
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigSyncAvailable = Chainloader.PluginInfos.ContainsKey("_shudnal.ConditionalConfigSync");
			if (ConfigSyncAvailable)
			{
				ConfigSyncCompat.Initialize("com.dreich.repairenemystructures", "Repair Enemy Structures", "1.0.1");
			}
			else
			{
				Log.LogInfo((object)"ConditionalConfigSync not found; configuration will not be synced from the server.");
			}
			lockConfigurationSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Lock Configuration", true, "If on, the configuration is locked and can be changed by server admins only. Requires ConditionalConfigSync.");
			if (ConfigSyncAvailable)
			{
				ConfigSyncCompat.AddLockingConfigEntry(lockConfigurationSetting);
			}
			RepairDvergr = BindServerControlled("General", "RepairDvergr", defaultValue: true, "Allow hammer repair on Dvergr structures.");
			RepairFuling = BindServerControlled("General", "RepairFuling", defaultValue: true, "Allow hammer repair on Fuling structures.");
			DvergrPrefabKeywords = BindServerControlled("General", "DvergrPrefabKeywords", "dvergr,dverger", "Comma-separated keywords; a structure prefab whose name contains any of them counts as a Dvergr structure.");
			FulingPrefabKeywords = BindServerControlled("General", "FulingPrefabKeywords", "goblin", "Comma-separated keywords; a structure prefab whose name contains any of them counts as a Fuling structure.");
			FulingStation = BindServerControlled("Stations", "FulingStation", Station.Workbench, "Station that must be nearby to repair Fuling structures. None = no station needed.");
			DvergrDefaultStation = BindServerControlled("Stations", "DvergrDefaultStation", Station.Workbench, "Station needed for Dvergr structures unless a keyword list below matches.");
			DvergrGroupAKeywords = BindServerControlled("Stations", "DvergrGroupAKeywords", "door,wisp,ferment", "Comma-separated prefab-name keywords for Dvergr group A (default: doors, wisp torch, fermenter).");
			DvergrGroupAStation = BindServerControlled("Stations", "DvergrGroupAStation", Station.Forge, "Station needed for Dvergr structures matching group A.");
			DvergrGroupBKeywords = BindServerControlled("Stations", "DvergrGroupBKeywords", "marble,crown", "Comma-separated prefab-name keywords for Dvergr group B (default: marble, crown).");
			DvergrGroupBStation = BindServerControlled("Stations", "DvergrGroupBStation", Station.Stonecutter, "Station needed for Dvergr structures matching group B.");
			StationOverrides = BindServerControlled("Stations", "StationOverrides", "", "Exact per-prefab overrides, comma-separated, as prefabname=Station (e.g. dvergrtown_creep_door=Forge,dvergrprops_marble_wall=Stonecutter). Checked before keywords.");
			RepairEffectPrefab = BindClientControlled("Effects", "RepairEffectPrefab", "wood_floor", "Name of a vanilla build piece whose placement sound and effects play when a Dvergr or Fuling structure is repaired. Leave empty for no effects.");
			LogPatched = BindClientControlled("Debug", "LogPatchedPrefabs", defaultValue: false, "Log every prefab that gets patched.");
			LogUnmatchedStructures = BindClientControlled("Debug", "LogUnmatchedStructures", defaultValue: false, "Log the names of structure prefabs that have no Piece and did not match the Dvergr/Fuling keywords, to help find the right names.");
			harmony = new Harmony("com.dreich.repairenemystructures");
			harmony.PatchAll();
		}

		private ConfigEntry<T> BindServerControlled<T>(string section, string key, T defaultValue, string description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			if (ConfigSyncAvailable)
			{
				ConfigSyncCompat.AddConfigEntry<T>(val, serverControlled: true);
			}
			return val;
		}

		private ConfigEntry<T> BindClientControlled<T>(string section, string key, T defaultValue, string description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			if (ConfigSyncAvailable)
			{
				ConfigSyncCompat.AddConfigEntry<T>(val, serverControlled: false);
			}
			return val;
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			harmony = null;
		}

		internal static bool IsRepairablePrefab(string prefabName)
		{
			string name = prefabName.ToLowerInvariant();
			if (RepairDvergr.Value && ContainsAnyKeyword(name, DvergrPrefabKeywords.Value))
			{
				return true;
			}
			if (RepairFuling.Value && ContainsAnyKeyword(name, FulingPrefabKeywords.Value))
			{
				return true;
			}
			return false;
		}

		internal static Station GetStationFor(string prefabName)
		{
			string text = prefabName.ToLowerInvariant();
			string[] array = StationOverrides.Value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '=' });
				if (array2.Length == 2 && !(array2[0].Trim().ToLowerInvariant() != text) && Enum.TryParse<Station>(array2[1].Trim(), ignoreCase: true, out var result))
				{
					return result;
				}
			}
			if (ContainsAnyKeyword(text, FulingPrefabKeywords.Value))
			{
				return FulingStation.Value;
			}
			if (ContainsAnyKeyword(text, DvergrGroupAKeywords.Value))
			{
				return DvergrGroupAStation.Value;
			}
			if (ContainsAnyKeyword(text, DvergrGroupBKeywords.Value))
			{
				return DvergrGroupBStation.Value;
			}
			return DvergrDefaultStation.Value;
		}

		private static bool ContainsAnyKeyword(string name, string keywordList)
		{
			string[] array = keywordList.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim().ToLowerInvariant();
				if (text.Length > 0 && name.Contains(text))
				{
					return true;
				}
			}
			return false;
		}

		internal static string GetStationPrefabName(Station station)
		{
			return station switch
			{
				Station.Workbench => "piece_workbench", 
				Station.Cauldron => "piece_cauldron", 
				Station.Forge => "forge", 
				Station.ArtisanTable => "piece_artisanstation", 
				Station.Stonecutter => "piece_stonecutter", 
				Station.MageTable => "piece_magetable", 
				Station.BlackForge => "blackforge", 
				_ => null, 
			};
		}
	}
	internal static class ConfigSyncCompat
	{
		private static object configSync;

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void Initialize(string guid, string name, string version)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			configSync = (object)new ConfigSync(guid)
			{
				DisplayName = name,
				CurrentVersion = version,
				MinimumRequiredVersion = version,
				ModRequired = false,
				ModRequirementMode = (ModRequirementMode)1
			};
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void AddLockingConfigEntry(ConfigEntry<bool> entry)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			((ConditionalConfigSync)(ConfigSync)configSync).AddLockingConfigEntry<bool>(entry);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void AddConfigEntry<T>(ConfigEntry<T> entry, bool serverControlled)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			((ConditionalConfigSync)(ConfigSync)configSync).AddConfigEntry<T>(entry, (ConfigSyncMode)((!serverControlled) ? 2 : 0));
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class EnemyStructurePrefabPatch
	{
		private static Piece FindEffectSource(ZNetScene scene)
		{
			string text = RepairEnemyStructuresPlugin.RepairEffectPrefab.Value.Trim();
			if (text.Length == 0)
			{
				return null;
			}
			GameObject prefab = scene.GetPrefab(text);
			if (!((Object)(object)prefab != (Object)null))
			{
				return null;
			}
			return prefab.GetComponent<Piece>();
		}

		private static string FindStationName(ZNetScene scene, Station station, string prefabName)
		{
			string stationPrefabName = RepairEnemyStructuresPlugin.GetStationPrefabName(station);
			if (stationPrefabName == null)
			{
				return null;
			}
			GameObject prefab = scene.GetPrefab(stationPrefabName);
			CraftingStation val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<CraftingStation>() : null);
			if ((Object)(object)val == (Object)null)
			{
				RepairEnemyStructuresPlugin.Log.LogWarning((object)("Station prefab '" + stationPrefabName + "' not found for " + prefabName));
				return null;
			}
			return val.m_name;
		}

		private static void Postfix(ZNetScene __instance)
		{
			Piece val = FindEffectSource(__instance);
			int num = 0;
			List<string> list = new List<string>();
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				bool flag = (Object)(object)prefab.GetComponent<WearNTear>() != (Object)null;
				RepairRequiresStation repairRequiresStation = prefab.GetComponent<RepairRequiresStation>();
				bool flag2 = (Object)(object)prefab.GetComponent<Piece>() != (Object)null;
				if (!RepairEnemyStructuresPlugin.IsRepairablePrefab(((Object)prefab).name))
				{
					if ((Object)(object)repairRequiresStation != (Object)null)
					{
						repairRequiresStation.StationName = null;
					}
					else if (flag && !flag2)
					{
						list.Add(((Object)prefab).name);
					}
				}
				else
				{
					if (!flag)
					{
						continue;
					}
					if (!flag2)
					{
						Piece val2 = prefab.AddComponent<Piece>();
						val2.m_name = ((Object)prefab).name;
						val2.m_canBeRemoved = false;
						((StaticTarget)val2).m_primaryTarget = false;
						((StaticTarget)val2).m_randomTarget = false;
						val2.m_targetNonPlayerBuilt = false;
						if ((Object)(object)val != (Object)null)
						{
							val2.m_placeEffect = val.m_placeEffect;
						}
					}
					Station stationFor = RepairEnemyStructuresPlugin.GetStationFor(((Object)prefab).name);
					string stationName = FindStationName(__instance, stationFor, ((Object)prefab).name);
					if ((Object)(object)repairRequiresStation == (Object)null)
					{
						repairRequiresStation = prefab.AddComponent<RepairRequiresStation>();
					}
					repairRequiresStation.StationName = stationName;
					num++;
					if (RepairEnemyStructuresPlugin.LogPatched.Value)
					{
						RepairEnemyStructuresPlugin.Log.LogInfo((object)$"Patched {((Object)prefab).name} (needs {stationFor}, Piece already existed: {flag2})");
					}
				}
			}
			RepairEnemyStructuresPlugin.Log.LogInfo((object)$"Patched {num} prefabs.");
			if (RepairEnemyStructuresPlugin.LogUnmatchedStructures.Value && list.Count > 0)
			{
				list.Sort();
				RepairEnemyStructuresPlugin.Log.LogInfo((object)("Structures without a Piece that did not match: " + string.Join(", ", list.ToArray())));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Repair")]
	internal static class RepairStationRequirementPatch
	{
		private static bool Prefix(Player __instance, Piece repairPiece)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)repairPiece == (Object)null)
			{
				return true;
			}
			RepairRequiresStation component = ((Component)repairPiece).GetComponent<RepairRequiresStation>();
			if ((Object)(object)component == (Object)null || string.IsNullOrEmpty(component.StationName))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(component.StationName, ((Component)__instance).transform.position)))
			{
				return true;
			}
			string text = Localization.instance.Localize(component.StationName);
			((Character)__instance).Message((MessageType)2, "Requires a nearby " + text + " to repair", 0, (Sprite)null, false);
			return false;
		}
	}
}