Иконка ресурса

FREE IQLoot : 1.3.2 1.3.2

Нет прав для скачивания
C#:
using System.Collections.Generic;
using Object = System.Object;
using System.Collections;
using System;
using System.Reflection;
using Rust;
using HarmonyLib;
using System.Linq;
using Oxide.Core;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("IQLoot", "Scrooge", "1.3.2")]
    [Description("Cпасибо скруджу")]
    public class IQLoot : RustPlugin {
        private void LoadContainers(String prefabName, LootContainer lootContainer) {
            if (dataContainers.ContainsKey(prefabName)) return;
            ContainerPreset preset = PresetGenerated(lootContainer);
            dataContainers.Add(prefabName, preset);
            WriteData(prefabName, preset, false);
        }
        private ContainerPreset GeneratePreset(List<ItemAmountRanged> allItems, (Int32 minLoot, Int32 maxLoot) lootSlots) {
            ContainerPreset preset = new ContainerPreset {
                enabled = true, amountLoot = new ContainerPreset.AmountController {
                    minAmount = lootSlots.minLoot, maxAmount = lootSlots.maxLoot
                }
            }
            ;
            foreach (ItemAmountRanged item in allItems) {
                ItemDefinition itemDef = item.itemDef;
                TypeLootContents typeLootContents = itemDef.category == ItemCategory.Weapon ? TypeLootContents.Weapon : TypeLootContents.Other;
                preset.lootPresets.Add(new ContainerPreset.LootPreset {
                    shortname = itemDef.shortname, conditionMin = itemDef.condition.foundCondition.fractionMin * 100f, conditionMax = itemDef.condition.foundCondition.fractionMax * 100f, displayName = string.Empty, skinID = 0, isBplueprint = false, rareDrop = rareDropDefault[itemDef.rarity], amount = new ContainerPreset.AmountController {
                        minAmount = (Int32)item.startAmount, maxAmount = (Int32)(item.maxAmount <= 0 ? item.startAmount : item.maxAmount)
                    }
                    , ammoWeapon = new ContainerPreset.LootPreset.AmmoWeapon {
                        shortname = "", amount = 0
                    }
                    , typeContents = typeLootContents, contents = new List<ContainerPreset.LootPreset.ItemContent>()
                }
                );
            }
            return preset;
        }
        private Dictionary<String, ContainerPreset> npcContainers = new Dictionary<String, ContainerPreset>();
        public class ContainerPreset {
            public AmountController amountLoot = new AmountController();
            public class LootPreset {
                public AmmoWeapon ammoWeapon;
                public String shortname;
                public Int32 rareDrop;
                public Single conditionMin;
                public String displayName;
                public class AmmoWeapon {
                    public Int32 amount;
                    public String shortname;
                }
                public AmountController amount;
                public Boolean isBplueprint;
                public Single conditionMax;
                public class ItemContent {
                    public String shortname;
                    public UInt64 skinID;
                    public Int32 amount;
                    public Item GetContentItem() {
                        Item contentItem = ItemManager.CreateByName(shortname);
                        return contentItem;
                    }
                }
                public List<ItemContent> contents = new List<ItemContent>();
                public UInt64 skinID;
                public TypeLootContents typeContents;
                public Item BuildItem() {
                    Item buildedItem;
                    if (isBplueprint) {
                        ItemDefinition definition = ItemManager.FindItemDefinition(shortname);
                        buildedItem = ItemManager.Create(ItemManager.blueprintBaseDef);
                        buildedItem.instanceData ??= new ProtoBuf.Item.InstanceData();
                        buildedItem.instanceData.ShouldPool = false;
                        buildedItem.instanceData.blueprintAmount = 1;
                        buildedItem.instanceData.blueprintTarget = definition.itemid;
                        buildedItem.MarkDirty();
                        return buildedItem;
                    }
                    buildedItem = ItemManager.CreateByName(shortname, amount.GetAmount(), skinID);
                    if(!String.IsNullOrWhiteSpace(displayName)) buildedItem.name = displayName;
                    if (buildedItem.hasCondition) {
                        Int32 currentCondition = Mathf.RoundToInt(buildedItem.maxCondition * (Oxide.Core.Random.Range(conditionMin, conditionMax) / 100f));
                        buildedItem.maxCondition = buildedItem.maxCondition;
                        buildedItem.condition = Math.Min(currentCondition, buildedItem.maxCondition);
                        buildedItem.busyTime = buildedItem.busyTime;
                    }
                    if (typeContents == TypeLootContents.Weapon) {
                        if (!String.IsNullOrWhiteSpace(ammoWeapon.shortname) && ammoWeapon.amount > 0) {
                            BaseProjectile weaponItem = buildedItem.GetHeldEntity() as BaseProjectile;
                            if (weaponItem) {
                                ItemDefinition ammoDef = ItemManager.FindItemDefinition(ammoWeapon.shortname);
                                if (ammoDef) {
                                    weaponItem.primaryMagazine.ammoType = ammoDef;
                                    weaponItem.primaryMagazine.contents = ammoWeapon.amount;
                                }
                            }
                        }
                    }
                    if (contents != null && contents.Count != 0) {
                        foreach (ItemContent mod in contents) {
                            Item modItem = mod.GetContentItem();
                            if(modItem == null) continue;
                            try {
                                buildedItem.contents.AddItem(mod.GetContentItem().info, mod.amount, mod.skinID);
                            }
                            catch (Exception e) {
                                modItem.Remove();
                                throw;
                            }
                        }
                    }
                    return buildedItem;
                }
            }
            public readonly List<LootPreset> lootPresets = new List<LootPreset>();
            public List<LootPreset> GetRandomLoots(Int32 requestedCount) {
                if (lootPresets == null || lootPresets.Count == 0 || requestedCount <= 0) {
                    // Debug.LogError($"Ref slot random list : {requestedCount}");
                    return null;
                }
                List<LootPreset> uniqueLoots = new ();
                HashSet<String> seenShortnames = new ();
                foreach (LootPreset loot in lootPresets) {
                    if(loot.shortname == "scrap") continue;
                    if (seenShortnames.Add(loot.shortname)) uniqueLoots.Add(loot);
                }
                Int32 count = Math.Min(requestedCount, uniqueLoots.Count);
                Single totalWeight = uniqueLoots.Sum(loot => Math.Clamp(loot.rareDrop, 0f, 100f));
                List<LootPreset> selectedLoots = new List<LootPreset>();
                for (Int32 i = 0; i < count; i++) {
                    Single randomValue = Core.Random.Range(0f, totalWeight);
                    Single cumulativeWeight = 0f;
                    foreach (LootPreset loot in uniqueLoots) {
                        Single weight = Math.Clamp(loot.rareDrop, 0f, 100f);
                        cumulativeWeight += weight;
                        if (randomValue <= cumulativeWeight) {
                            selectedLoots.Add(loot);
                            uniqueLoots.Remove(loot);
                            totalWeight -= weight;
                            break;
                        }
                    }
                }
                return selectedLoots;
            }
            public Boolean enabled;
            public Item GetScrap() {
                Int32 scrapIndex = lootPresets.FindIndex(x => x.shortname == "scrap");
                if (scrapIndex == -1) return null;
                Int32 amountScrap = lootPresets[scrapIndex].amount.GetAmount();
                if (amountScrap <= 0) return null;
                return Core.Random.Range(0, 100) < lootPresets[scrapIndex].rareDrop ? ItemManager.CreateByName("scrap", amountScrap) : null;
            }
            public class AmountController {
                public Int32 minAmount;
                public Int32 maxAmount;
                public Int32 GetAmount() {
                    Int32 min = Math.Min(minAmount, maxAmount);
                    Int32 max = Math.Max(minAmount, maxAmount) + 1;
                    Int32 amount = Core.Random.Range(min, max);
                    return Math.Max(amount, 1);
                }
            }
        }
        private void Unload() {
            if (instance == null) return;
            HarmonyInstance?.UnpatchAll(HarmonyInstance.Id);
            dataContainers?.Clear();
            npcContainers?.Clear();
            if (routinePrefabs != null) {
                ServerMgr.Instance.StopCoroutine(routinePrefabs);
                routinePrefabs = null;
            }
            instance = null;
        }
        private Boolean finalWarningShown = false;
        [HarmonyPatch(typeof(LootContainer), nameof(LootContainer.SpawnLoot))]
        public class Patch_LootContainer_SpawnLoot {
            [HarmonyPostfix]
            public static void SpawnLoot_Postfix(LootContainer __instance) {
                ApplyLootContainer(__instance);
            }
        }
        public enum TypeLootContents {
            Weapon, Other
        }
        // - Улучшить на сайте настройку % (сделать не только ползунок)
        // - Превью крейта с которым сейчас работаешь (на сайте фотку)
        //
        // - Вагоны
        // - Подарки яички
        // - У прочности тоже разбросик
        // - Пак предметов (то есть создать арбалет и к нему со 100 шансом падает стрелы)
        //Update :
        // Обновление плагина :
        // - Исправлена проблема, заставляющая мусорки на земле (junkiles) переспавниваться лишний раз.// - Заменен метод получения префаба, который мог вызывать варнинги/ошибки при загрузке из-за требования сцены для проверки определенного префаба
        private const Boolean LanguageEn = false;
        private static String FormatTime(Single secondsTotal) {
            Int32 minutes = (Int32)(secondsTotal / 60);
            Int32 seconds = (Int32)(secondsTotal % 60);
            return LanguageEn ?$"{minutes} min {seconds} sec" : $"{minutes} мин {seconds} сек";
        }
        private void ReadData() {
            ReadDataFolder("IQSystem/IQLoot/Containers/", dataContainers);
            ReadDataFolder("IQSystem/IQLoot/NPCs/", npcContainers);
        }
        private void LoadHarmonyPatches() {
            Type[] types = GetType().GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            foreach (Type type in types) {
                if (type.GetCustomAttributes(typeof(HarmonyPatch), false).Length == 0) continue;
                List<MethodInfo> harmonyMethods = HarmonyInstance.CreateClassProcessor(type)?.Patch();
                if (harmonyMethods == null || harmonyMethods.Count == 0) {
                    Interface.Oxide.LogWarning($"[{Title}] AutoPatch attribute found on '{type.Name}' but no HarmonyPatch methods found.Skipping.");
                    continue;
                }
                foreach (MethodInfo method in harmonyMethods) {
                    Interface.Oxide.LogInfo($"[{Title}] Automatically Harmony patched '{method.Name}' method.({type.Name})");
                }
            }
        }
        private static Coroutine routinePrefabs = null;
        private void RegenerateLootServer() {
            foreach (LootContainer container in BaseNetworkable.serverEntities.Where(p => p is LootContainer && p)) ApplyLootContainer(container);
        }
        private void OnServerInitialized() {
            if (LanguageEn) {
                PrintWarning("Link to configure settings via the website: https://iqloot.skyplugins.ru/");
                PrintWarning($"Web access code: {codeOthers}");
            }
            else {
                if (isAlkad) {
                    PrintWarning("Ссылка для настройки конфигураций через сайт - https://iqloot.skyplugins.ru/");
                    PrintWarning($"Web access code: {codeOthers}");
                }
                else PrintWarning("Ссылка для настройки конфигураций через сайт - https://iqloot.skyplugins.ru/");
            }
            routinePrefabs = ServerMgr.Instance.StartCoroutine(InitPrefabManifest());
        }
        private void ReadDataFolder(String baseFolder, Dictionary<String, ContainerPreset> targetDict) {
            try {
                String[] files = Interface.Oxide.DataFileSystem.GetFiles(baseFolder, "*.json");
                foreach (String fullPath in files) {
                    String fileKey = fullPath.Substring(0, fullPath.Length - 5);
                    try {
                        Object rawObj = Interface.Oxide.DataFileSystem.ReadObject<Object>(fileKey);
                        String rawJson = JsonConvert.SerializeObject(rawObj);
                        JObject jObject = JObject.Parse(rawJson);
                        Boolean isLegacy = false;
                        if (jObject["lootPresets"] is JArray lootPresets) {
                            foreach (JToken loot in lootPresets) {
                                JToken conditionToken = loot["condition"];
                                if (conditionToken != null && loot["conditionMin"] == null && loot["conditionMax"] == null) {
                                    Single conditionValue = conditionToken.ToObject<Single>();
                                    loot["conditionMin"] = conditionValue;
                                    loot["conditionMax"] = conditionValue;
                                    ((JObject)loot).Remove("condition");
                                    isLegacy = true;
                                }
                            }
                        }
                        ContainerPreset preset = jObject.ToObject<ContainerPreset>();
                        if (preset == null) continue;
                        String prefabName = System.IO.Path.GetFileNameWithoutExtension(fileKey);
                        targetDict.TryAdd(prefabName, preset);
                        if (isLegacy) {
                            Interface.Oxide.DataFileSystem.WriteObject(fileKey, preset, true);
                            Puts(LanguageEn ? $"→ Updated legacy preset: {prefabName}.json" : $"→ Обновлён устаревший пресет: {prefabName}.json");
                        }
                    }
                    catch (Exception ex) {
                        PrintError(LanguageEn ? $"Error reading {fullPath}: {ex.Message}" : $"Ошибка при чтении {fullPath}: {ex.Message}");
                    }
                }
            }
            catch (Exception ex) {
                PrintError(LanguageEn ? $"Error scanning folder {baseFolder}: {ex.Message}" : $"Ошибка при сканировании папки {baseFolder}: {ex.Message}");
            }
        }
        private readonly HashSet<String> lootPrefabKeysIgnore = new(StringComparer.OrdinalIgnoreCase) {
            "test", "mission", "invisible", "fx", "ui", "sounds", "spawners", "misc", "client", "preview", "invisible", "marker"
        }
        ;
        private (Int32 minLoot, Int32 maxLoot) CalculateLootRange(LootContainer container) {
            if (!container.name.Contains("road")) return EstimateMinMaxLoot(container);
            Int32 count = container.inventory?.itemList?.Count ?? 2;
            return (1, count);
        }
        private (Int32 minLoot, Int32 maxLoot) CalculateLootRange(HumanNPC npc) => EstimateMinMaxLootSpawnSloot(npc.LootSpawnSlots);
        private IEnumerator InitPrefabManifest() {
            PrintWarning(LanguageEn ? "Prefab manifest processing started.Please wait..." : "Запущен обработчик манифеста префабов, этот процесс ресурсоемкий и может вызвать некоторую задержку.\nНе перезагружайте плагин пока не увидите сообщение о завершении процесса");
            Int32 count = GameManifest.Current.prefabProperties.Length;
            const Single delay = 0.01f;
            Single totalSeconds = count * delay;
            Int32 minutes = (Int32)(totalSeconds / 60);
            Int32 seconds = (Int32)(totalSeconds % 60);
            PrintWarning(LanguageEn ? $"Estimated processing time: {minutes}m {seconds}s.It usually happens faster." : $"Примерное время обработки: {minutes} мин {seconds} сек.Обычно это происходит быстрее");
            Single halfTime = totalSeconds / 2f;
            const Single finalReminderThreshold = 30f;
            Single elapsedTime = 0f;
            for (Int32 i = 0; i < count; i++) {
                GameManifest.PrefabProperties prefabInManifest = GameManifest.Current.prefabProperties[i];
                if (prefabInManifest == null) continue;
                if (!prefabInManifest.name.EndsWith(".prefab")) continue;
                GameObject prefab = FindPrefab(prefabInManifest.name);
                if (!prefab) continue;
                String prefabName = prefab.name.ToLower();
                if (!IsValidLootPrefab(prefabName) || IsIgnoreLootPrefab(prefabName)) continue;
                if (prefab.TryGetComponent(out LootContainer lootContainer)) LoadContainers(prefabName, lootContainer);
                else if (prefab.TryGetComponent(out HumanNPC npcPlayer)) LoadNpcs(prefabName, npcPlayer);
                elapsedTime += delay;
                if (!halfWarningShown && elapsedTime >= halfTime) {
                    halfWarningShown = true;
                    PrintWarning(LanguageEn ? $"~50% complete.Remaining: {FormatTime(totalSeconds - elapsedTime)}" : $"~50% завершено.Осталось примерно: {FormatTime(totalSeconds - elapsedTime)}");
                }
                if (!finalWarningShown && totalSeconds - elapsedTime <= finalReminderThreshold) {
                    finalWarningShown = true;
                    PrintWarning(LanguageEn ? $"Almost done.Remaining: {FormatTime(totalSeconds - elapsedTime)}" : $"Почти готово.Осталось: {FormatTime(totalSeconds - elapsedTime)}");
                }
                yield return CoroutineEx.waitForSeconds(delay);
            }
            PrintWarning(LanguageEn ? "Prefab manifest processing complete." : "Обработка манифестов завершена");
            LoadHarmonyPatches();
            RegenerateLootServer();
            yield return null;
        }
        private List<ItemAmountRanged> GetAllLootItems(LootContainer container) {
            var items = new List<ItemAmountRanged>();
            if (container.lootDefinition) items.AddRange(ProcessLootSpawn(container.lootDefinition));
            if (items.Count <= 3 && container.LootSpawnSlots != null) {
                foreach (LootContainer.LootSpawnSlot slot in container.LootSpawnSlots) {
                    if (slot.definition) items.AddRange(ProcessLootSpawn(slot.definition));
                }
            }
            if (container.scrapAmount > 0) {
                items.Add(new ItemAmountRanged(ItemManager.FindItemDefinition("scrap"), container.scrapAmount, container.scrapAmount));
            }
            List<ItemAmountRanged> uniqueItems = items.GroupBy(i => i.itemDef.shortname).Select(g => g.First()).ToList();
            return uniqueItems;
        }
        private static IQLoot instance;
        private static GameObject FindPrefab(String strPrefab) {
            GameObject prefab = GameManager.server.preProcessed.Find(strPrefab);
            return prefab ? prefab : null;
        }
        private readonly Dictionary<Rarity, Int32> rareDropDefault = new Dictionary<Rarity, Int32>() {
            [Rarity.None]
            = 100, [Rarity.Common] = 100, [Rarity.Uncommon] = 75, [Rarity.Rare] = 50, [Rarity.VeryRare] = 25,
        }
        ;
        private const String codeOthers = "";
        private Dictionary<String, ContainerPreset> dataContainers = new Dictionary<String, ContainerPreset>();
        private readonly HashSet<String> lootPrefabKeys = new(StringComparer.OrdinalIgnoreCase) {
            // Ящики и контейнеры
            "crate", "loot", "barrel", "trash-pile", "dm ", "foodbox", "food_cache", "tech_parts", "heli_crate", "bradley_crate", "minecart", "wagon_crate", "oil_barrel", "presentdrop", "supply_drop", "giftbox_loot", "beehive", "codelockedhackablecrate", "roadsign", "vehicle_parts",  // NPC (Scientist, Tunnel Dweller, и т.д.)
            "npc", "scientist", "tunneldweller", "underwaterdweller", "gingerbread"
        }
        ;
        private List<ItemAmountRanged> ProcessLootSpawn(LootSpawn lootSpawn) {
            List<ItemAmountRanged> items = new();
            if (!lootSpawn) return items;
            if (lootSpawn.subSpawn is {
                Length : > 0
            }
            ) {
                foreach (LootSpawn.Entry subSpawn in lootSpawn.subSpawn) {
                    if (subSpawn.category) items.AddRange(ProcessLootSpawn(subSpawn.category));
                }
            }
            if (lootSpawn.items is {
                Length : > 0
            }
            ) items.AddRange(lootSpawn.items);
            return items;
        }
        private ContainerPreset PresetGenerated(LootContainer lootContainer) {
            List<ItemAmountRanged> allItems = GetAllLootItems(lootContainer);
            (Int32 minLoot, Int32 maxLoot) lootSlots = CalculateLootRange(lootContainer);
            return GeneratePreset(allItems, lootSlots);
        }
        private static void ApplyLootContainer(LootContainer container) {
            if (!container || !instance.dataContainers.TryGetValue(container.ShortPrefabName, out ContainerPreset dataContainer) || !dataContainer.enabled) return;
            if (container.skinID != 0) return;
            if (instance.ignoredOwnerIdsOtherPlugins.Contains(container.OwnerID)) return;
            if (container.inventory is null) {
                container.CreateInventory(true);
                container.OnInventoryFirstCreated(container.inventory);
            }
            if (container.inventory.itemList.Count > 0) {
                container.inventory.Clear();
                ItemManager.DoRemoves();
                container.HasBeenLooted = false;
            }
            Int32 slotAmount = dataContainer.amountLoot.GetAmount();
            Item scrap = dataContainer.GetScrap();
            if (scrap != null) {
                if (!scrap.MoveToContainer(container.inventory)) scrap.Remove();
                else slotAmount--;
            }
            List<ContainerPreset.LootPreset> presets = dataContainer.GetRandomLoots(slotAmount);
            if (presets == null && scrap == null) {
                Interface.Oxide.LogWarning($"WARNING: Loot container nulled.Prefab: {container.ShortPrefabName}");
                container.Kill();
                return;
            }
            if (presets == null) return;
            foreach (ContainerPreset.LootPreset loot in presets) {
                Item item = loot.BuildItem();
                if (item == null) continue;
                if (!item.MoveToContainer(container.inventory)) item.Remove();
                else item.OnVirginSpawn();
            }
            container.inventory.MarkDirty();
        }
        private ContainerPreset PresetGenerated(HumanNPC npc) {
            List<ItemAmountRanged> allItems = GetAllLootItems(npc);
            (Int32 minLoot, Int32 maxLoot) lootSlots = CalculateLootRange(npc);
            return GeneratePreset(allItems, lootSlots);
        }
        private static (Int32 min, Int32 max) EstimateMinMaxLootSpawnSloot(LootContainer.LootSpawnSlot[] slots) {
            Int32 minTotal = 0;
            Int32 maxTotal = 0;
            foreach (LootContainer.LootSpawnSlot slot in slots) {
                if (slot.eras is {
                    Length : > 0
                }
                && Array.IndexOf(slot.eras, ConVar.Server.Era) == -1) continue;
                Int32 attempts = slot.numberToSpawn;
                maxTotal += attempts;
                Int32 minSlot = (Int32)Math.Floor(attempts * slot.probability);
                minTotal += minSlot;
            }
            return (minTotal, maxTotal);
        }
        private const Boolean isAlkad = false;
        private void Init() {
            instance = this;
            ReadData();
        }
        private void LoadNpcs(String prefabName, HumanNPC npc) {
            if (npcContainers.ContainsKey(prefabName)) return;
            ContainerPreset preset = PresetGenerated(npc);
            npcContainers.Add(prefabName, preset);
            WriteData(prefabName, preset, true);
        }
        private void WriteData(String prefabName, ContainerPreset preset, Boolean isNpc) {
            Dictionary<String, ContainerPreset> dict = isNpc ? npcContainers : dataContainers;
            if (!dict.ContainsKey(prefabName)) return;
            String folder = isNpc ? "NPCs" : "Containers";
            String path = $"IQSystem/IQLoot/{folder}/{prefabName}";
            try {
                Interface.Oxide.DataFileSystem.WriteObject(path, preset);
                Puts(LanguageEn ? $"A new container ({folder}) '{prefabName}' has been detected.It has been added to {path} and is disabled by default." : $"Обнаружен новый контейнер ({folder}) `{prefabName}`, он добавлен в {path} и по стандарту выключен");
            }
            catch (Exception ex) {
                PrintError(LanguageEn ? $"Failed to write file {prefabName}: {ex.Message}" : $"Ошибка при записи файла {prefabName}: {ex.Message}");
            }
        }
        private Boolean halfWarningShown = false;
        private Boolean IsValidLootPrefab(String prefabName) => lootPrefabKeys.Any(validKey => prefabName.IndexOf(validKey, StringComparison.OrdinalIgnoreCase) >= 0);
        private static (Int32 min, Int32 max) EstimateMinMaxLoot(LootContainer container) {
            Int32 minTotal = 0;
            Int32 maxTotal = 0;
            if (container.LootSpawnSlots is {
                Length : > 0
            }
            ) {
                (Int32 min, Int32 max) slotsInfo = EstimateMinMaxLootSpawnSloot(container.LootSpawnSlots);
                minTotal = Math.Max(1, slotsInfo.min - GetOffset(slotsInfo.min));
                maxTotal = slotsInfo.max;
            }
            else if (container.lootDefinition) {
                minTotal = Math.Max(1, container.maxDefinitionsToSpawn - GetOffset(container.maxDefinitionsToSpawn));
                maxTotal += container.maxDefinitionsToSpawn;
            }
            return (minTotal, maxTotal);
            Int32 GetOffset(Int32 total) => minTotal <= 3 ? 0 : Math.Min(3, minTotal / 2);
        }
        private Boolean IsIgnoreLootPrefab(String prefabName) => lootPrefabKeysIgnore.Any(validKey => prefabName.IndexOf(validKey, StringComparison.OrdinalIgnoreCase) >= 0);
        [HarmonyPatch(typeof(NPCPlayer), nameof(NPCPlayer.CreateCorpse))]
        public class Patch_NPCPlayer_CreateCorpse {
            [HarmonyPostfix]
            public static void CreateCorpse_Postfix(BaseCorpse __result, NPCPlayer __instance) {
                if (__result is not NPCPlayerCorpse corpse) return;
                if (!instance.npcContainers.TryGetValue(__instance.ShortPrefabName, out ContainerPreset dataContainer) || !dataContainer.enabled) return;
                if (corpse.containers.Length == 0 || !(corpse.containers[0] is ItemContainer inv)) return;
                if (__instance.skinID != 0) return;
                if (instance.ignoredOwnerIdsOtherPlugins.Contains(__instance.OwnerID)) return;
                if (inv.itemList.Count > 0) {
                    inv.Clear();
                    ItemManager.DoRemoves();
                }
                Int32 slotAmount = dataContainer.amountLoot.GetAmount();
                Item scrap = dataContainer.GetScrap();
                if (scrap != null) {
                    if (!scrap.MoveToContainer(inv)) scrap.Remove();
                    else slotAmount--;
                }
                var presets = dataContainer.GetRandomLoots(slotAmount);
                if (presets == null && scrap == null) {
                    Interface.Oxide.LogWarning($"WARNING: NPC loot nulled.Prefab: {corpse.ShortPrefabName}");
                    corpse.Kill();
                    return;
                }
                if (presets == null) return;
                foreach (ContainerPreset.LootPreset loot in presets) {
                    Item item = loot.BuildItem();
                    if (item == null) continue;
                    if (!item.MoveToContainer(inv)) item.Remove();
                }
            }
        }
        private List<ItemAmountRanged> GetAllLootItems(HumanNPC npc) {
            var items = new List<ItemAmountRanged>();
            if (npc.LootSpawnSlots == null) return items;
            foreach (LootContainer.LootSpawnSlot slot in npc.LootSpawnSlots) {
                if (slot.definition) items.AddRange(ProcessLootSpawn(slot.definition));
            }
            return items;
        }
        private readonly HashSet<UInt64> ignoredOwnerIdsOtherPlugins = new HashSet<UInt64>() {
            1235847, 8856355, 999073677, 577365, 3766520, 488855, 7655463
        }
        ;
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху