Decompiled source of VehicleRemoval v1.5.1

VehicleRemoval_v1.5.1.dll

Decompiled 2 days 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.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("VehicleRemoval")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.1.0")]
[assembly: AssemblyInformationalVersion("1.5.1")]
[assembly: AssemblyProduct("VehicleRemoval")]
[assembly: AssemblyTitle("VehicleRemoval")]
[assembly: AssemblyVersion("1.5.1.0")]
namespace VehicleRemoval;

[BepInPlugin("frost.vehicleremoval", "VehicleRemoval", "1.5.1")]
public class VehicleRemovalPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "frost.vehicleremoval";

	public const string PluginName = "VehicleRemoval";

	public const string PluginVersion = "1.5.1";

	internal static ManualLogSource Log;

	internal static ConfigEntry<string> VehicleMaterials;

	private void Awake()
	{
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		VehicleMaterials = ((BaseUnityPlugin)this).Config.Bind<string>("VehicleRemoval", "VehicleMaterials", "Cart=Wood:20,BronzeNails:10;Raft=Wood:20,GreyDwarfEye:5,Resin:10;Karve=FineWood:30,BronzeNails:80,DeerHide:10,Resin:20;VikingShip=FineWood:40,IronNails:100,AncientBark:40,DeerHide:10", "Материалы возврата, если у транспорта нет рецепта в игре (у телеги и кораблей их нет: крафт special-cased). Формат: Префаб=Предмет:кол-во,Предмет:кол-во;... Имена предметов — префабы ObjectDB. Рецепт из игры имеет приоритет, это запасной путь");
		VehicleRemovalState.Parse(VehicleMaterials.Value);
		VehicleMaterials.SettingChanged += delegate
		{
			VehicleRemovalState.Parse(VehicleMaterials.Value);
		};
		new Harmony("frost.vehicleremoval").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"VehicleRemoval 1.5.1 загружен");
	}
}
internal static class VehicleRemovalState
{
	private static readonly Dictionary<string, List<KeyValuePair<string, int>>> _map = new Dictionary<string, List<KeyValuePair<string, int>>>(StringComparer.OrdinalIgnoreCase);

	public static void Parse(string config)
	{
		_map.Clear();
		string[] array = config.Split(';');
		for (int i = 0; i < array.Length; i++)
		{
			string[] array2 = array[i].Split('=');
			if (array2.Length != 2 || array2[0].Trim().Length == 0)
			{
				continue;
			}
			List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>();
			string[] array3 = array2[1].Split(',');
			for (int j = 0; j < array3.Length; j++)
			{
				string[] array4 = array3[j].Split(':');
				if (array4.Length == 2 && int.TryParse(array4[1].Trim(), out var result) && array4[0].Trim().Length > 0)
				{
					list.Add(new KeyValuePair<string, int>(array4[0].Trim(), result));
				}
			}
			if (list.Count > 0)
			{
				_map[array2[0].Trim()] = list;
			}
		}
		VehicleRemovalPlugin.Log.LogInfo((object)("Таблица материалов транспорта: " + string.Join(", ", _map.Keys)));
	}

	public static List<KeyValuePair<string, int>> Get(string prefabName)
	{
		if (!_map.TryGetValue(prefabName, out var value))
		{
			return null;
		}
		return value;
	}
}
[HarmonyPatch(typeof(Player), "RemovePiece")]
internal static class Player_RemovePiece_Patch
{
	private static readonly FieldInfo RemoveEffectsField = AccessTools.Field(typeof(Player), "m_removeEffects");

	private static readonly MethodInfo GetBuildStaminaMethod = AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null);

	private static void Postfix(Player __instance, bool __result)
	{
		if (__result)
		{
			return;
		}
		try
		{
			TryRemoveVehicle(__instance);
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[VehicleRemoval] Ошибка сноса транспорта: " + ex));
		}
	}

	private static bool TryRemoveVehicle(Player player)
	{
		//IL_0017: 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_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		GameCamera instance = GameCamera.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return false;
		}
		RaycastHit val = default(RaycastHit);
		if (!Physics.Raycast(((Component)instance).transform.position, ((Component)instance).transform.forward, ref val, 50f, LayerMask.GetMask(new string[1] { "vehicle" })))
		{
			return false;
		}
		Ship componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Ship>();
		GameObject val2 = ((componentInParent != null) ? ((Component)componentInParent).gameObject : null);
		if ((Object)(object)val2 == (Object)null)
		{
			Vagon componentInParent2 = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Vagon>();
			val2 = ((componentInParent2 != null) ? ((Component)componentInParent2).gameObject : null);
		}
		if ((Object)(object)val2 == (Object)null)
		{
			return false;
		}
		if (!PrivateArea.CheckAccess(val2.transform.position, 0f, true, false))
		{
			((Character)player).Message((MessageType)2, "$msg_privatezone", 0, (Sprite)null, false);
			return false;
		}
		ZNetView component = val2.GetComponent<ZNetView>();
		bool flag = (Object)(object)component == (Object)null || !component.IsValid();
		if (!flag)
		{
			component.ClaimOwnership();
			flag = component.IsOwner();
		}
		if (flag)
		{
			DropRecipeResources(val2);
		}
		object? obj = RemoveEffectsField?.GetValue(player);
		EffectList val3 = (EffectList)((obj is EffectList) ? obj : null);
		if (val3 != null)
		{
			val3.Create(val2.transform.position, val2.transform.rotation, val2.transform, 1f, -1, ((Character)player).GetZDOID());
		}
		float num = ((GetBuildStaminaMethod != null) ? ((float)GetBuildStaminaMethod.Invoke(player, null)) : 0f);
		((Character)player).UseStamina(num);
		((Character)player).AddNoise(50f);
		player.FaceLookDirection();
		if (flag)
		{
			ZNetScene.instance.Destroy(val2);
			((Character)player).Message((MessageType)1, "Транспорт разобран — материалы возвращены", 0, (Sprite)null, false);
		}
		else
		{
			WearNTear component2 = val2.GetComponent<WearNTear>();
			if ((Object)(object)component2 == (Object)null)
			{
				return false;
			}
			component2.Remove(false);
			((Character)player).Message((MessageType)1, "Транспорт уничтожен — материалы в обломках", 0, (Sprite)null, false);
		}
		VehicleRemovalPlugin.Log.LogInfo((object)("Разобран транспорт: " + ((Object)val2).name));
		return true;
	}

	private static void DropRecipeResources(GameObject target)
	{
		ObjectDB instance = ObjectDB.instance;
		string prefabName = Utils.GetPrefabName(target);
		if (!((Object)(object)instance == (Object)null) && !string.IsNullOrEmpty(prefabName))
		{
			Recipe val = FindRecipe(instance, prefabName);
			if ((Object)(object)val != (Object)null)
			{
				DropFromRecipe(instance, target, val, prefabName);
			}
			else if (!DropFromConfig(instance, target, prefabName))
			{
				LogRecipeDiagnostics(instance, prefabName);
				VehicleRemovalPlugin.Log.LogWarning((object)("Материалы для " + prefabName + " не возвращены: рецепта нет и в VehicleMaterials пусто"));
			}
		}
	}

	private static void DropFromRecipe(ObjectDB db, GameObject target, Recipe found, string prefabName)
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		Requirement[] resources = found.m_resources;
		foreach (Requirement val in resources)
		{
			if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0)
			{
				string prefabName2 = Utils.GetPrefabName(((Object)val.m_resItem).name);
				SpawnDrop(db, prefabName2, val.m_amount, target.transform.position + Vector3.up);
				num++;
			}
		}
		VehicleRemovalPlugin.Log.LogInfo((object)("Рецепт " + prefabName + ": материалов возвращено позиций " + num));
	}

	private static bool DropFromConfig(ObjectDB db, GameObject target, string prefabName)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		List<KeyValuePair<string, int>> list = VehicleRemovalState.Get(prefabName);
		if (list == null || list.Count == 0)
		{
			return false;
		}
		foreach (KeyValuePair<string, int> item in list)
		{
			SpawnDrop(db, item.Key, item.Value, target.transform.position + Vector3.up);
		}
		VehicleRemovalPlugin.Log.LogInfo((object)("Материалы из конфига для " + prefabName + ": " + list.Count + " позиций"));
		return true;
	}

	private static void SpawnDrop(ObjectDB db, string itemName, int amount, Vector3 position)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		GameObject itemPrefab = db.GetItemPrefab(itemName);
		if ((Object)(object)itemPrefab == (Object)null)
		{
			VehicleRemovalPlugin.Log.LogWarning((object)("Предмет для возврата не найден в ObjectDB: " + itemName));
			return;
		}
		int num = amount;
		while (num > 0)
		{
			ItemDrop component = Object.Instantiate<GameObject>(itemPrefab, position, Quaternion.identity).GetComponent<ItemDrop>();
			component.SetStack(Mathf.Min(num, component.m_itemData.m_shared.m_maxStackSize));
			ItemDrop.OnCreateNew(component, false);
			num -= component.m_itemData.m_stack;
		}
		VehicleRemovalPlugin.Log.LogInfo((object)$"Возврат: {itemName} x{amount}");
	}

	private static Recipe FindRecipe(ObjectDB db, string prefabName)
	{
		Recipe val = null;
		foreach (Recipe recipe in db.m_recipes)
		{
			if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null) && ((Object)((Component)recipe.m_item).gameObject).name == prefabName)
			{
				return recipe;
			}
		}
		string b = "Recipe_" + prefabName;
		foreach (Recipe recipe2 in db.m_recipes)
		{
			if (!((Object)(object)recipe2 == (Object)null))
			{
				if (string.Equals(((Object)recipe2).name, b, StringComparison.OrdinalIgnoreCase))
				{
					return recipe2;
				}
				if ((Object)(object)val == (Object)null && ((Object)recipe2).name != null && ((Object)recipe2).name.ToLowerInvariant().Contains(prefabName.ToLowerInvariant()))
				{
					val = recipe2;
				}
			}
		}
		GameObject itemPrefab = db.GetItemPrefab(prefabName);
		ItemDrop val2 = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
		if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null)
		{
			SharedData shared = val2.m_itemData.m_shared;
			foreach (Recipe recipe3 in db.m_recipes)
			{
				if (!((Object)(object)recipe3 == (Object)null) && !((Object)(object)recipe3.m_item == (Object)null) && recipe3.m_item.m_itemData != null && recipe3.m_item.m_itemData.m_shared != null && recipe3.m_item.m_itemData.m_shared == shared)
				{
					return recipe3;
				}
			}
		}
		foreach (Recipe recipe4 in db.m_recipes)
		{
			if (!((Object)(object)recipe4 == (Object)null) && !((Object)(object)recipe4.m_item == (Object)null) && string.Equals(((Object)((Component)recipe4.m_item).gameObject).name, prefabName, StringComparison.OrdinalIgnoreCase))
			{
				return recipe4;
			}
		}
		return val;
	}

	private static void LogRecipeDiagnostics(ObjectDB db, string prefabName)
	{
		int num = 0;
		List<string> list = new List<string>();
		string value = prefabName.ToLowerInvariant();
		foreach (Recipe recipe in db.m_recipes)
		{
			if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null))
			{
				num++;
				string name = ((Object)((Component)recipe.m_item).gameObject).name;
				if (list.Count < 10 && name.ToLowerInvariant().Contains(value))
				{
					list.Add(name);
				}
			}
		}
		GameObject itemPrefab = db.GetItemPrefab(prefabName);
		VehicleRemovalPlugin.Log.LogWarning((object)string.Format("Рецепт для {0} не найден. Рецептов всего: {1}; кандидаты по подстроке: [{2}]; предмет {0} в ObjectDB: {3}", prefabName, num, string.Join(", ", list), ((Object)(object)itemPrefab != (Object)null) ? "ЕСТЬ" : "НЕТ"));
		foreach (Recipe recipe2 in db.m_recipes)
		{
			if (!((Object)(object)recipe2 == (Object)null) && !((Object)(object)recipe2.m_item == (Object)null) && !((Object)(object)recipe2.m_craftingStation == (Object)null) && !(recipe2.m_craftingStation.m_name != "$piece_workbench"))
			{
				VehicleRemovalPlugin.Log.LogInfo((object)$"Верстак: {((Object)recipe2).name} -> предмет {((Object)((Component)recipe2.m_item).gameObject).name}");
			}
		}
	}
}