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();
}
}