Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VehicleRemoval v1.6.0
VehicleRemoval_v1.6.0.dll
Decompiled a month agousing 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.6.0.0")] [assembly: AssemblyInformationalVersion("1.6.0")] [assembly: AssemblyProduct("VehicleRemoval")] [assembly: AssemblyTitle("VehicleRemoval")] [assembly: AssemblyVersion("1.6.0.0")] namespace VehicleRemoval; [BepInPlugin("frost.vehicleremoval", "VehicleRemoval", "1.6.0")] public class VehicleRemovalPlugin : BaseUnityPlugin { public const string PluginGuid = "frost.vehicleremoval"; public const string PluginName = "VehicleRemoval"; public const string PluginVersion = "1.6.0"; internal static ManualLogSource Log; internal static ConfigEntry<string> VehicleMaterials; internal static ConfigEntry<bool> RequireWorkbench; private void Awake() { //IL_008c: 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,ElderBark:40,DeerHide:10", "Материалы возврата, если у транспорта нет Piece/рецепта в игре. Формат: Префаб=Предмет:кол-во,Предмет:кол-во;... Имена предметов — префабы ObjectDB. У Piece-транспорта (корабли 1.0.15) берётся настоящая стоимость из Piece.m_resources, рецепт предмета имеет второй приоритет, это запасной путь"); RequireWorkbench = ((BaseUnityPlugin)this).Config.Bind<bool>("VehicleRemoval", "RequireWorkbench", true, "Разбор транспорта требует станцию в радиусе (как ванильный снос деталей; мировая настройка NoWorkbench её отменяет) / Dismantling requires a station in range like vanilla piece removal (NoWorkbench world setting overrides)"); VehicleRemovalState.Parse(VehicleMaterials.Value); VehicleMaterials.SettingChanged += delegate { VehicleRemovalState.Parse(VehicleMaterials.Value); }; new Harmony("frost.vehicleremoval").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"VehicleRemoval 1.6.0 загружен"); } } internal static class VehicleRemovalState { private static readonly Dictionary<string, string> ItemAliases = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "AncientBark", "ElderBark" } }; 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) { string text = array4[0].Trim(); if (ItemAliases.TryGetValue(text, out var value)) { VehicleRemovalPlugin.Log.LogInfo((object)("Псевдоним предмета: " + text + " -> " + value)); text = value; } list.Add(new KeyValuePair<string, int>(text, 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 const string FallbackStationName = "$piece_workbench"; 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0234: 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; } Piece componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>(); GameObject val2; if ((Object)(object)componentInParent != (Object)null) { val2 = ((Component)componentInParent).gameObject; } else { Ship componentInParent2 = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Ship>(); val2 = ((componentInParent2 != null) ? ((Component)componentInParent2).gameObject : null); if ((Object)(object)val2 == (Object)null) { Vagon componentInParent3 = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Vagon>(); val2 = ((componentInParent3 != null) ? ((Component)componentInParent3).gameObject : null); } if ((Object)(object)val2 == (Object)null) { return false; } } if ((Object)(object)componentInParent != (Object)null && !componentInParent.m_canBeRemoved) { return false; } if (Location.IsInsideNoBuildLocation(val2.transform.position)) { ((Character)player).Message((MessageType)2, "$msg_nobuildzone", 0, (Sprite)null, false); return false; } if (!PrivateArea.CheckAccess(val2.transform.position, 0f, true, false)) { ((Character)player).Message((MessageType)2, "$msg_privatezone", 0, (Sprite)null, false); return false; } if (!CheckStationInRange(player, componentInParent)) { return false; } if ((Object)(object)componentInParent != (Object)null && !componentInParent.CanBeRemoved()) { ((Character)player).Message((MessageType)2, "$msg_cantremovenow", 0, (Sprite)null, false); return false; } Ship componentInParent4 = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Ship>(); if ((Object)(object)componentInParent == (Object)null && (Object)(object)componentInParent4 != (Object)null && !componentInParent4.CanBeRemoved()) { ((Character)player).Message((MessageType)2, "$msg_cantremovenow", 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) { DropVehicleCargo(val2); } Vector3 dropPoint = ((RaycastHit)(ref val)).point + Vector3.up * 0.3f; if (flag) { if ((Object)(object)componentInParent != (Object)null) { DropPieceResources(componentInParent, dropPoint); } else { DropRecipeResources(val2, dropPoint); } } 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)("Разобран транспорт: префаб=" + Utils.GetPrefabName(val2) + ", объект=" + ((Object)val2).name + (((Object)(object)componentInParent != (Object)null) ? " (Piece, стоимость из m_resources)" : " (без Piece)"))); return true; } private static bool CheckStationInRange(Player player, Piece piece) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!VehicleRemovalPlugin.RequireWorkbench.Value) { return true; } if (ZoneSystem.instance.GetGlobalKey((GlobalKeys)27)) { return true; } string text = (((Object)(object)piece != (Object)null && (Object)(object)piece.m_craftingStation != (Object)null) ? piece.m_craftingStation.m_name : "$piece_workbench"); if ((Object)(object)CraftingStation.HaveBuildStationInRange(text, ((Component)player).transform.position) != (Object)null) { return true; } VehicleRemovalPlugin.Log.LogInfo((object)("Снос отменён: нет станции " + text + " в радиусе")); ((Character)player).Message((MessageType)2, "$msg_missingstation", 0, (Sprite)null, false); return false; } private static void DropVehicleCargo(GameObject target) { MethodInfo methodInfo = AccessTools.Method(typeof(Container), "DropAllItems", (Type[])null, (Type[])null); if (methodInfo == null) { VehicleRemovalPlugin.Log.LogWarning((object)"Container.DropAllItems не найден — груз мог пропасть"); return; } int num = 0; int num2 = 0; Container[] componentsInChildren = target.GetComponentsInChildren<Container>(true); foreach (Container val in componentsInChildren) { Inventory inventory = val.GetInventory(); if (inventory != null) { int num3 = inventory.NrOfItems(); if (num3 != 0) { methodInfo.Invoke(val, null); num++; num2 += num3; } } } if (num > 0) { VehicleRemovalPlugin.Log.LogInfo((object)$"Груз возвращён: контейнеров {num}, стаков {num2}"); } } private static void DropPieceResources(Piece piece, Vector3 dropPoint) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return; } int num = 0; Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.m_recover && val.m_amount > 0) { SpawnDrop(instance, Utils.GetPrefabName(((Object)val.m_resItem).name), val.m_amount, dropPoint); num++; } } VehicleRemovalPlugin.Log.LogInfo((object)("Стоимость Piece " + Utils.GetPrefabName(((Component)piece).gameObject) + ": возвращено позиций " + num)); } private static void DropRecipeResources(GameObject target, Vector3 dropPoint) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) 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, val, dropPoint, prefabName); } else if (!DropFromConfig(instance, prefabName, dropPoint)) { LogRecipeDiagnostics(instance, prefabName); VehicleRemovalPlugin.Log.LogWarning((object)("Материалы для " + prefabName + " не возвращены: рецепта нет и в VehicleMaterials пусто")); } } } private static void DropFromRecipe(ObjectDB db, Recipe found, Vector3 dropPoint, string prefabName) { //IL_0046: 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, dropPoint); num++; } } VehicleRemovalPlugin.Log.LogInfo((object)("Рецепт " + prefabName + ": материалов возвращено позиций " + num)); } private static bool DropFromConfig(ObjectDB db, string prefabName, Vector3 dropPoint) { //IL_0034: 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, dropPoint); } 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) ? "ЕСТЬ" : "НЕТ")); } }