Decompiled source of Station Radius v0.1.0

FrizzQOL.StationRadius.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
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("FrizzQOL.StationRadius")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+9353a9f49ea00fbb1a0ba2066001b09bc90b766a")]
[assembly: AssemblyProduct("FrizzQOL.StationRadius")]
[assembly: AssemblyTitle("FrizzQOL.StationRadius")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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;
		}
	}
}
public static class RadiusRules
{
	public static bool IsValid(float configured)
	{
		return configured > 0f;
	}

	public static float Resolve(float configured, float vanilla)
	{
		if (IsValid(configured))
		{
			return configured;
		}
		return vanilla;
	}

	public static float TotalBuild(float baseRange, float extensionBonus)
	{
		return baseRange + extensionBonus;
	}
}
namespace StationRadius
{
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetSceneAwakePatch
	{
		private static void Postfix(ZNetScene __instance)
		{
			StationCatalog.DiscoverFromScene(__instance);
		}
	}
	[HarmonyPatch(typeof(CraftingStation), "Start")]
	internal static class CraftingStationStartPatch
	{
		private static void Postfix(CraftingStation __instance)
		{
			StationCatalog.BindFromInstance(__instance);
			RadiusApplier.Apply(__instance);
		}
	}
	[BepInPlugin("com.frizzqol.stationradius", "FrizzQOL Station Radius", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.frizzqol.stationradius";

		public const string PluginName = "FrizzQOL Station Radius";

		public const string PluginVersion = "0.1.0";

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			Instance = this;
			StationCatalog.Initialize(((BaseUnityPlugin)this).Config);
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				RadiusApplier.ApplyAllLoaded();
			};
			_harmony = new Harmony("com.frizzqol.stationradius");
			try
			{
				_harmony.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"FrizzQOL Station Radius 0.1.0 loaded");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Harmony patch failed: " + ex.Message));
			}
		}

		internal static void LogInfo(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)message);
			}
		}

		internal static void LogWarning(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)message);
			}
		}

		internal static void LogError(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogError((object)message);
			}
		}
	}
	internal static class RadiusApplier
	{
		private static readonly FieldInfo RangeBuildField = AccessTools.Field(typeof(CraftingStation), "m_rangeBuild");

		private static readonly FieldInfo UseDistanceField = AccessTools.Field(typeof(CraftingStation), "m_useDistance");

		private static bool _loggedMissingUseField;

		public static void Apply(CraftingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return;
			}
			string prefabName = StationCatalog.GetPrefabName(((Component)station).gameObject);
			if (string.IsNullOrEmpty(prefabName))
			{
				Plugin.LogWarning("CraftingStation missing prefab name. Skipped.");
				return;
			}
			StationCatalog.StationConfig stationConfig = StationCatalog.Get(prefabName) ?? StationCatalog.BindFromInstance(station);
			if (stationConfig == null)
			{
				Plugin.LogWarning("No config for crafting station '" + prefabName + "'. Skipped.");
				return;
			}
			float num = RadiusRules.Resolve(stationConfig.BuildRadius.Value, stationConfig.VanillaBuild);
			if (!RadiusRules.IsValid(stationConfig.BuildRadius.Value))
			{
				Plugin.LogWarning($"[{prefabName}] BuildRadius {stationConfig.BuildRadius.Value} is invalid. Using vanilla {stationConfig.VanillaBuild}.");
			}
			if (RangeBuildField != null)
			{
				RangeBuildField.SetValue(station, num);
			}
			float num2 = RadiusRules.Resolve(stationConfig.UseRadius.Value, stationConfig.VanillaUse);
			if (!RadiusRules.IsValid(stationConfig.UseRadius.Value))
			{
				Plugin.LogWarning($"[{prefabName}] UseRadius {stationConfig.UseRadius.Value} is invalid. Using vanilla {stationConfig.VanillaUse}.");
			}
			if (UseDistanceField != null)
			{
				UseDistanceField.SetValue(station, num2);
			}
			else if (!_loggedMissingUseField)
			{
				_loggedMissingUseField = true;
				Plugin.LogError("CraftingStation.m_useDistance not found. Build radius still applies.");
			}
			RefreshCircle(station, num);
		}

		public static void ApplyAllLoaded()
		{
			CraftingStation[] array = Object.FindObjectsByType<CraftingStation>((FindObjectsSortMode)0);
			if (array != null)
			{
				CraftingStation[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					Apply(array2[i]);
				}
			}
		}

		private static void RefreshCircle(CraftingStation station, float radius)
		{
			CircleProjector componentInChildren = ((Component)station).GetComponentInChildren<CircleProjector>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(CircleProjector), "m_radius");
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(componentInChildren, radius);
				}
			}
		}
	}
	internal static class StationCatalog
	{
		internal sealed class StationConfig
		{
			public float VanillaBuild;

			public float VanillaUse;

			public ConfigEntry<float> BuildRadius;

			public ConfigEntry<float> UseRadius;
		}

		private static ConfigFile _config;

		private static readonly Dictionary<string, StationConfig> Entries = new Dictionary<string, StationConfig>();

		public static void Initialize(ConfigFile config)
		{
			_config = config;
		}

		public static void DiscoverFromScene(ZNetScene scene)
		{
			if (_config == null || (Object)(object)scene == (Object)null)
			{
				return;
			}
			if (AccessTools.Field(typeof(ZNetScene), "m_prefabs")?.GetValue(scene) is List<GameObject> { Count: not 0 } list)
			{
				int num = 0;
				foreach (GameObject item in list)
				{
					if (!((Object)(object)item == (Object)null))
					{
						CraftingStation component = item.GetComponent<CraftingStation>();
						if (!((Object)(object)component == (Object)null) && Bind(item, component))
						{
							num++;
						}
					}
				}
				if (num == 0 && Entries.Count == 0)
				{
					Plugin.LogWarning("No CraftingStation prefabs found in ZNetScene.");
				}
				else if (num > 0)
				{
					Plugin.LogInfo($"Bound config for {num} crafting stations.");
				}
			}
			else
			{
				Plugin.LogWarning("ZNetScene prefab list empty. Station config will bind when stations load.");
			}
		}

		public static StationConfig BindFromInstance(CraftingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return null;
			}
			Bind(((Component)station).gameObject, station);
			return Get(GetPrefabName(((Component)station).gameObject));
		}

		public static StationConfig Get(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return null;
			}
			if (!Entries.TryGetValue(prefabName, out var value))
			{
				return null;
			}
			return value;
		}

		public static IEnumerable<KeyValuePair<string, StationConfig>> All()
		{
			return Entries;
		}

		private static bool Bind(GameObject obj, CraftingStation station)
		{
			string prefabName = GetPrefabName(obj);
			if (string.IsNullOrEmpty(prefabName) || _config == null)
			{
				return false;
			}
			if (Entries.ContainsKey(prefabName))
			{
				return false;
			}
			float num = ReadFloat(station, "m_rangeBuild", 20f);
			float num2 = ReadFloat(station, "m_useDistance", 5f);
			StationConfig value = new StationConfig
			{
				VanillaBuild = num,
				VanillaUse = num2,
				BuildRadius = _config.Bind<float>(prefabName, "BuildRadius", num, "Build circle radius in meters. Values <= 0 keep vanilla."),
				UseRadius = _config.Bind<float>(prefabName, "UseRadius", num2, "Use / open radius in meters. Values <= 0 keep vanilla.")
			};
			Entries[prefabName] = value;
			return true;
		}

		internal static string GetPrefabName(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return null;
			}
			string name = ((Object)obj).name;
			int num = name.IndexOf("(Clone)");
			if (num < 0)
			{
				return name;
			}
			return name.Substring(0, num).Trim();
		}

		private static float ReadFloat(object instance, string fieldName, float fallback)
		{
			FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName);
			if (fieldInfo == null)
			{
				return fallback;
			}
			object value = fieldInfo.GetValue(instance);
			if (value is float)
			{
				return (float)value;
			}
			return fallback;
		}
	}
}