Decompiled source of Ballista Reloader v0.217.25

ReloadTurrets.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ReloadTurrets")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Reload Ballista From Nearby Containers")]
[assembly: AssemblyCopyright("Copyright Byte-Artificer  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3f8cf903-7f89-437c-abb5-4a79ecc7573a")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace FriendlyTurrets;

public class NearbyContainers : BaseUnityPlugin
{
	public class ConnectionParams
	{
		public GameObject connection = null;

		public Vector3 stationPos;
	}

	public static ConfigEntry<float> m_range;

	public static ConfigEntry<bool> ignoreShipContainers;

	public static ConfigEntry<bool> ignoreWagonContainers;

	public static ConfigEntry<bool> ignoreWoodChests;

	public static ConfigEntry<bool> ignorePrivateChests;

	public static ConfigEntry<bool> ignoreBlackMetalChests;

	public static ConfigEntry<bool> ignoreReinforcedChests;

	public static ConfigEntry<bool> allowChangingAmmoTypes;

	public static ConfigEntry<int> reloadTurretsBelow;

	public static ConfigEntry<bool> modEnabled;

	public static ConfigEntry<bool> isDebug;

	public static ConfigEntry<bool> printDebugMessages;

	public static List<Container> containerList = new List<Container>();

	public static void Dbgl(string str = "", bool pref = true)
	{
		if (isDebug.Value)
		{
			Debug.Log((object)((pref ? (typeof(NearbyContainers).Namespace + " ") : "") + str));
		}
	}

	public static void Init(ConfigFile config)
	{
		modEnabled = config.Bind<bool>("General", "Enabled", true, "Enable this mod");
		isDebug = config.Bind<bool>("General", "IsDebug", false, "Show debug messages in log");
		m_range = config.Bind<float>("General", "ContainerRange", 10f, "The maximum range from which to pull items from");
		ignoreShipContainers = config.Bind<bool>("Container Types", "IgnoreShipContainers", false, "If true, will ignore this type of container.");
		ignoreWagonContainers = config.Bind<bool>("Container Types", "IgnoreWagonContainers", false, "If true, will ignore this type of container.");
		ignoreWoodChests = config.Bind<bool>("Container Types", "IgnoreWoodChests", false, "If true, will ignore this type of container.");
		ignorePrivateChests = config.Bind<bool>("Container Types", "IgnorePrivateChests", false, "If true, will ignore this type of container.");
		ignoreBlackMetalChests = config.Bind<bool>("Container Types", "IgnoreBlackMetalChests", false, "If true, will ignore this type of container.");
		ignoreReinforcedChests = config.Bind<bool>("Container Types", "IgnoreReinforcedChests", false, "If true, will ignore this type of container.");
		allowChangingAmmoTypes = config.Bind<bool>("General", "AllowChangingAmmoTypes", true, "If false, ballista will only reload with the previous ammo type when empty.");
		reloadTurretsBelow = config.Bind<int>("General", "ReloadTurretsBelow", 5, "Ballista will automatically reload when their stored ammo drops below this amount.");
		if (modEnabled.Value)
		{
		}
	}

	public static List<Container> GetNearbyContainers(Vector3 center)
	{
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		List<Container> list = new List<Container>();
		foreach (Container container in containerList)
		{
			if ((Object)(object)container != (Object)null && (Object)(object)((Component)container).GetComponentInParent<Piece>() != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)((container != null) ? ((Component)container).transform : null) != (Object)null && container.GetInventory() != null && (m_range.Value <= 0f || Vector3.Distance(center, ((Component)container).transform.position) < m_range.Value) && (!container.m_checkGuardStone || PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)) && Traverse.Create((object)container).Method("CheckAccess", new object[1] { Player.m_localPlayer.GetPlayerID() }).GetValue<bool>() && !container.IsInUse() && AllowContainerType(container))
			{
				list.Add(container);
			}
		}
		return list;
	}

	private static bool AllowContainerType(Container __instance)
	{
		Transform parent = ((Component)__instance).gameObject.transform.parent;
		Ship val = ((parent != null) ? ((Component)parent).GetComponent<Ship>() : null);
		return (!((Object)(object)val != (Object)null) || !ignoreShipContainers.Value) && (!Object.op_Implicit((Object)(object)__instance.m_wagon) || !ignoreWagonContainers.Value) && (!((Object)__instance).name.StartsWith("piece_chest_wood(") || !ignoreWoodChests.Value) && (!((Object)__instance).name.StartsWith("piece_chest_private(") || !ignorePrivateChests.Value) && (!((Object)__instance).name.StartsWith("piece_chest_blackmetal(") || !ignoreBlackMetalChests.Value) && (!((Object)__instance).name.StartsWith("piece_chest(") || !ignoreReinforcedChests.Value);
	}

	public static IEnumerator AddContainer(Container container, ZNetView nview)
	{
		yield return null;
		try
		{
			int num;
			if (container.GetInventory() != null)
			{
				if (((nview != null) ? nview.GetZDO() : null) != null)
				{
					num = ((((Object)container).name.StartsWith("piece_") || ((Object)container).name.StartsWith("Container") || nview.GetZDO().GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L) != 0) ? 1 : 0);
					goto IL_00ad;
				}
			}
			num = 0;
			goto IL_00ad;
			IL_00ad:
			if (num != 0)
			{
				containerList.Add(container);
			}
		}
		catch
		{
		}
	}

	public static void PullResources(Turret turret, int qty, Action<string> loadTurretAction)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		string lastAmmo = turret.GetAmmoItem().m_shared.m_name;
		Dbgl($"looking for {qty} {lastAmmo} for {((Object)turret).name}");
		Dbgl("Allowed ammo types: ");
		foreach (AmmoType item in turret.m_allowedAmmo)
		{
			Dbgl(((Object)item.m_ammo).name + " : " + item.m_ammo.m_itemData.m_shared.m_name);
		}
		AmmoType val = turret.m_allowedAmmo.First((AmmoType x) => x.m_ammo.m_itemData.m_shared.m_name == lastAmmo);
		bool flag = PullResourcesCore(turret, qty, val, loadTurretAction);
		Dbgl("resournces found: " + flag);
		if (!flag)
		{
			Dbgl($"turret has ammo: {turret.HasAmmo()}");
		}
		if (!allowChangingAmmoTypes.Value || flag || turret.HasAmmo())
		{
			return;
		}
		foreach (AmmoType item2 in turret.m_allowedAmmo)
		{
			Dbgl("next ammo type: " + ((Object)item2.m_ammo).name);
			if ((Object)(object)item2.m_ammo == (Object)(object)val.m_ammo)
			{
				Dbgl(((Object)item2.m_ammo).name + " is the same as " + ((Object)val.m_ammo).name + ", skipping ");
			}
			else if (PullResourcesCore(turret, qty, item2, loadTurretAction))
			{
				break;
			}
		}
	}

	private static bool PullResourcesCore(Turret turret, int qty, AmmoType ammoType, Action<string> loadTurretAction)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		string name = ammoType.m_ammo.m_itemData.m_shared.m_name;
		Dbgl($"looking for {qty} {name} for {((Object)turret).name}");
		List<Container> nearbyContainers = GetNearbyContainers(((Component)turret).transform.position);
		string text = name;
		int num = 0;
		bool result = false;
		foreach (Container item2 in nearbyContainers)
		{
			lock (item2)
			{
				Dbgl($"checking container {item2}");
				Inventory inventory = item2.GetInventory();
				int num2 = Mathf.Min(inventory.CountItems(text, -1, true), qty - num);
				Dbgl($"Container at {((Component)item2).transform.position} has {inventory.CountItems(text, -1, true)}");
				if (num2 == 0)
				{
					continue;
				}
				for (int i = 0; i < inventory.GetAllItems().Count; i++)
				{
					ItemData item = inventory.GetItem(i);
					if (!(item.m_shared.m_name == text))
					{
						continue;
					}
					Dbgl($"Got stack of {item.m_stack} {text}");
					int num3 = Mathf.Min(item.m_stack, qty - num);
					Dbgl($"Sending {num3} {text} to turret");
					int ammo = turret.GetAmmo();
					for (int j = 0; j < num3; j++)
					{
						loadTurretAction(((Object)ammoType.m_ammo).name);
					}
					if (turret.GetAmmo() > ammo)
					{
						if (num3 == item.m_stack)
						{
							inventory.RemoveItem(i);
						}
						else
						{
							item.m_stack -= num3;
						}
					}
					result = true;
					num += num3;
					Dbgl($"total amount is now {num}/{qty} {text}");
					if (num >= qty)
					{
						break;
					}
				}
				((object)item2).GetType().GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(item2, new object[0]);
				((object)inventory).GetType().GetMethod("Changed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(inventory, new object[0]);
				if (num < qty)
				{
					continue;
				}
				Dbgl("pulled enough " + text);
				break;
			}
		}
		return result;
	}
}
[BepInPlugin("ByteArtificer.ReloadTurretsFromContainers", "Reload Ballista From Nearby Containers", "1.0.1")]
[BepInProcess("valheim.exe")]
public class ReloadTurrets : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Turret), "ShootProjectile")]
	public static class Turret_ShootProjectile_Prefix
	{
		private static void Postfix(ref Turret __instance)
		{
			Turret turret = __instance;
			int ammo = __instance.GetAmmo();
			_logger.LogMessage((object)$"Turret fired, {ammo}/{__instance.m_maxAmmo} ammo remains");
			if (ammo < NearbyContainers.reloadTurretsBelow.Value)
			{
				_logger.LogMessage((object)"Turret needs reloading");
				NearbyContainers.PullResources(__instance, __instance.m_maxAmmo - ammo, delegate(string ammoType)
				{
					((object)turret).GetType().GetMethod("RPC_AddAmmo", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(turret, new object[2] { 0, ammoType });
				});
			}
		}
	}

	[HarmonyPatch(typeof(Container), "Awake")]
	private static class Container_Awake_Patch
	{
		private static void Postfix(Container __instance, ZNetView ___m_nview)
		{
			((MonoBehaviour)_context).StartCoroutine(NearbyContainers.AddContainer(__instance, ___m_nview));
		}
	}

	[HarmonyPatch(typeof(Container), "OnDestroyed")]
	private static class Container_OnDestroyed_Patch
	{
		private static void Prefix(Container __instance)
		{
			NearbyContainers.containerList.Remove(__instance);
		}
	}

	private readonly Harmony harmony = new Harmony("ByteArtificer.ReloadTurretsFromContainers");

	public static ManualLogSource _logger;

	public static ConfigEntry<bool> ignoreShipContainers;

	private static ReloadTurrets _context;

	public void Awake()
	{
		_logger = ((BaseUnityPlugin)this).Logger;
		_context = this;
		NearbyContainers.Init(((BaseUnityPlugin)this).Config);
		harmony.PatchAll();
	}
}