Decompiled source of CrossZoneZombieSupply v1.1.0

CrossZoneZombieSupply.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using LazyBearTechnology;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace CrossZoneZombieSupply;

[BepInPlugin("sieme.gk2.cross-zone-zombie-supply", "Cross Zone Zombie Supply", "1.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> GlobalConstructionStorage;

	private void Awake()
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Allow caretaker zombies to supply from chests in every world zone.");
		GlobalConstructionStorage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "GlobalConstructionStorage", true, "Allow construction outside work zones to use materials from all saved-scene chests and the player backpack.");
		new Harmony("sieme.gk2.cross-zone-zombie-supply").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Cross Zone Zombie Supply loaded");
	}
}
[HarmonyPatch(typeof(WgoData), "GetCraftableMultiInventory")]
internal static class GlobalConstructionInventory
{
	private static void Postfix(WgoData __instance, bool __0, ref MultiInventory __result)
	{
		if (!Plugin.GlobalConstructionStorage.Value || __0 || __result == null || __instance.WorldZoneData != null)
		{
			return;
		}
		HashSet<Inventory> hashSet = new HashSet<Inventory>(__result.inventoryList);
		MainGame instance = MainGame.Instance;
		Inventory val = (((Object)(object)instance == (Object)null || instance.GameSave == null || instance.GameSave.playerData == null) ? null : instance.GameSave.playerData.Inventory);
		if (val != null && hashSet.Add(val))
		{
			__result.Add(val);
		}
		foreach (WgoData item in Supply.AllChests())
		{
			Inventory inventory = item.Inventory;
			if (hashSet.Add(inventory))
			{
				__result.Add(inventory);
			}
		}
	}
}
internal static class Supply
{
	internal static IEnumerable<WgoData> AllChests()
	{
		MainGame game = MainGame.Instance;
		if ((Object)(object)game == (Object)null || game.GameSave == null || game.GameSave.worldData == null)
		{
			yield break;
		}
		HashSet<WgoData> seen = new HashSet<WgoData>();
		foreach (GameSceneData scene in game.GameSave.worldData.gameSceneDataList)
		{
			if (scene == null || scene.wgoDataList == null)
			{
				continue;
			}
			foreach (WgoData chest in scene.wgoDataList)
			{
				if (chest != null && ((ObjectLinkedToDefinition<WGODef>)(object)chest).Definition != null && ((ObjectLinkedToDefinition<WGODef>)(object)chest).Definition.OpenInMultiInventory && chest.Inventory != null && seen.Add(chest))
				{
					yield return chest;
				}
			}
		}
	}

	internal static bool Accepts(WgoData chest, Item item)
	{
		if (chest == null || chest.Inventory == null || ((ObjectLinkedToDefinition<WGODef>)(object)chest).Definition == null || item == null)
		{
			return false;
		}
		ItemDef definition = ((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition;
		if (definition != null && ((ItemFilter)((ObjectLinkedToDefinition<WGODef>)(object)chest).Definition.inventoryWhiteList).Contains(definition))
		{
			return !((ItemFilter)((ObjectLinkedToDefinition<WGODef>)(object)chest).Definition.inventoryBlackList).Contains(definition);
		}
		return false;
	}

	internal static int Count(WgoData chest, Item item)
	{
		return chest.Inventory.Data.GetTotalCountInInventory(((ObjectLinkedToDefinition<ItemDef>)(object)item).id, (Item)null, false);
	}

	internal static bool HasEnough(Item item, int alreadyCarried)
	{
		if (item == null)
		{
			return false;
		}
		int num = item.Count - alreadyCarried;
		if (num <= 0)
		{
			return true;
		}
		foreach (WgoData item2 in AllChests())
		{
			if (Accepts(item2, item))
			{
				num -= Count(item2, item);
				if (num <= 0)
				{
					return true;
				}
			}
		}
		return false;
	}

	internal static WgoData NearestLocalChest(ZombieWgoData zombie)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		if (((WgoData)zombie).WorldZoneData == null)
		{
			return null;
		}
		WgoData result = null;
		float num = float.MaxValue;
		foreach (WgoData multiInventoryWgoData in ((WgoData)zombie).WorldZoneData.MultiInventoryWgoDatas)
		{
			if (multiInventoryWgoData != null && multiInventoryWgoData.Inventory != null)
			{
				float num2 = Vector3.Distance(((WgoData)zombie).Position, multiInventoryWgoData.Position);
				if (num2 < num)
				{
					num = num2;
					result = multiInventoryWgoData;
				}
			}
		}
		return result;
	}

	internal static List<WgoData> Sources(Item item, WgoData localTarget)
	{
		List<WgoData> list = new List<WgoData>();
		if (Accepts(localTarget, item) && Count(localTarget, item) > 0)
		{
			list.Add(localTarget);
		}
		foreach (WgoData item2 in AllChests())
		{
			if (item2 != localTarget && Accepts(item2, item) && Count(item2, item) > 0)
			{
				list.Add(item2);
			}
		}
		return list;
	}
}
[HarmonyPatch(typeof(WorldZoneData), "CanDeliveryOrderBeTakenOnExecution")]
internal static class GlobalOrderCheck
{
	private static void Postfix(WorldZoneData __instance, DeliveryOrder __0, int __1, ref bool __result)
	{
		if (!__result && Plugin.Enabled.Value && __0 != null && ((OrderBase)__0).Item != null && __instance.MultiInventoryWgoDatas != null && __instance.MultiInventoryWgoDatas.Count != 0)
		{
			__result = Supply.HasEnough(((OrderBase)__0).Item, __1);
		}
	}
}
[HarmonyPatch(typeof(ZombieWgoData), "CaretakerTryMoveToNearestInventoryWithRequiredItemCountToPickUp")]
internal static class ChooseLocalChest
{
	private static bool Prefix(ZombieWgoData __instance)
	{
		if (!Plugin.Enabled.Value)
		{
			return true;
		}
		OrderBase value = Traverse.Create((object)__instance).Property("CaretakerExecutingOrder", (object[])null).GetValue<OrderBase>();
		if (!(value is DeliveryOrder) || value.Item == null)
		{
			return true;
		}
		Item caretakerPortableItem = __instance.CaretakerPortableItem;
		int alreadyCarried = ((caretakerPortableItem != null && !caretakerPortableItem.IsEmpty) ? caretakerPortableItem.Count : 0);
		if (!Supply.HasEnough(value.Item, alreadyCarried))
		{
			return true;
		}
		WgoData val = Supply.NearestLocalChest(__instance);
		if (val == null)
		{
			return true;
		}
		Traverse.Create((object)__instance).Field("caretakerCurrentTargetUniqueId").SetValue((object)val.UniqueId);
		Traverse.Create((object)__instance).Method("CaretakerTryMoveToCurrentTarget", new object[0]).GetValue();
		return false;
	}
}
[HarmonyPatch(typeof(ZombieWgoData), "CaretakerTryPickUpFromInventory")]
internal static class TakeAcrossZones
{
	private static readonly FieldInfo PickupTime = AccessTools.Field(typeof(ZombieWgoData), "caretakerPickingUpFromInventoryTime");

	private static bool Prefix(ZombieWgoData __instance, float __0)
	{
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0277: Expected O, but got Unknown
		if (!Plugin.Enabled.Value)
		{
			return true;
		}
		OrderBase value = Traverse.Create((object)__instance).Property("CaretakerExecutingOrder", (object[])null).GetValue<OrderBase>();
		if (!(value is DeliveryOrder) || value.Item == null)
		{
			return true;
		}
		Item caretakerPortableItem = __instance.CaretakerPortableItem;
		int num = ((caretakerPortableItem != null && !caretakerPortableItem.IsEmpty) ? caretakerPortableItem.Count : 0);
		int num2 = value.Item.Count - num;
		if (num2 <= 0 || !Supply.HasEnough(value.Item, num))
		{
			return true;
		}
		WgoData value2 = Traverse.Create((object)__instance).Property("CaretakerCurrentTarget", (object[])null).GetValue<WgoData>();
		if (value2 == null)
		{
			return true;
		}
		List<WgoData> list = Supply.Sources(value.Item, value2);
		float num3 = (float)PickupTime.GetValue(__instance) + __0;
		PickupTime.SetValue(__instance, num3);
		float num4 = new LazyExpression(ConstDef.Get("zombie_caretaker_picking_up_time").StringValue).EvaluateFloat((WgoData)(object)__instance);
		if (num3 < num4)
		{
			return false;
		}
		PickupTime.SetValue(__instance, 0f);
		if (!Supply.HasEnough(value.Item, num))
		{
			return true;
		}
		int num5 = num2;
		List<Tuple<Inventory, List<Item>>> list2 = new List<Tuple<Inventory, List<Item>>>();
		foreach (WgoData item in list)
		{
			int num6 = Math.Min(num5, Supply.Count(item, value.Item));
			if (num6 <= 0)
			{
				continue;
			}
			List<Item> list3 = item.Inventory.RemoveItemById(((ObjectLinkedToDefinition<ItemDef>)(object)value.Item).id, num6, (Item)null, (Item)null, false);
			list2.Add(Tuple.Create<Inventory, List<Item>>(item.Inventory, list3));
			if (list3 != null)
			{
				foreach (Item item2 in list3)
				{
					num5 -= item2.Count;
				}
			}
			if (num5 <= 0)
			{
				break;
			}
		}
		if (num5 != 0)
		{
			foreach (Tuple<Inventory, List<Item>> item3 in list2)
			{
				if (item3.Item2 == null)
				{
					continue;
				}
				foreach (Item item4 in item3.Item2)
				{
					item3.Item1.AddItemToInventory(item4, (Item)null, false);
				}
			}
			return true;
		}
		if (num == 0)
		{
			__instance.CaretakerPortableItem = new Item(((ObjectLinkedToDefinition<ItemDef>)(object)value.Item).id, num2);
		}
		else
		{
			caretakerPortableItem.Count += num2;
			__instance.CaretakerPortableItem = caretakerPortableItem;
		}
		__instance.CaretakerState = (ZombieCaretakerState)4;
		Traverse.Create((object)__instance).Method("CaretakerTryMoveToZombie", new object[0]).GetValue();
		return false;
	}
}