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

FREE FLootRespawn : 1.0.0 1.0.0

Нет прав для скачивания
C#:
using System.Collections.Generic;
using Network;
using UnityEngine;

namespace Oxide.Plugins;

[Info("FLootRespawn", "fufeldev", "1.0.0")]
public class FLootRespawn : RustPlugin
{
    private const float RespawnDelay = 30f;
    private const float OreRespawnDelay = 180f;
    private const float TreeRespawnDelay = 120f;
    private const float AnimalRespawnDelay = 240f;
    private static readonly string[] BarrelPrefabs =
    {
        "assets/bundled/prefabs/radtown/loot_barrel_1.prefab",
        "assets/bundled/prefabs/radtown/loot_barrel_2.prefab",
        "assets/bundled/prefabs/radtown/oil_barrel.prefab",
        "assets/bundled/prefabs/autospawn/resource/loot/loot-barrel-1.prefab",
        "assets/bundled/prefabs/autospawn/resource/loot/loot-barrel-2.prefab",
        "assets/prefabs/missions/tutorialisland/loot-barrel-tutorial.prefab"
    };
    private static readonly string[] RoadCratePrefabs =
    {
        "assets/bundled/prefabs/radtown/crate_basic.prefab",
        "assets/bundled/prefabs/radtown/crate_basic_jungle.prefab",
        "assets/bundled/prefabs/radtown/crate_normal.prefab",
        "assets/bundled/prefabs/radtown/crate_normal_2.prefab",
        "assets/bundled/prefabs/radtown/crate_normal_2_food.prefab",
        "assets/bundled/prefabs/radtown/crate_normal_2_medical.prefab",
        "assets/bundled/prefabs/radtown/crate_tools.prefab",
        "assets/bundled/prefabs/radtown/crate_mine.prefab",
        "assets/bundled/prefabs/radtown/crate_shore.prefab",
        "assets/bundled/prefabs/radtown/crate_cannons.prefab",
        "assets/bundled/prefabs/radtown/crate_elite.prefab",
        "assets/bundled/prefabs/radtown/underwater_labs/crate_elite.prefab"
    };

    private readonly HashSet<NetworkableId> _processing = new HashSet<NetworkableId>();
    private readonly HashSet<NetworkableId> _opened = new HashSet<NetworkableId>();
    private readonly HashSet<NetworkableId> _looted = new HashSet<NetworkableId>();
    private readonly HashSet<uint> _barrelPrefabs = new HashSet<uint>();
    private readonly HashSet<uint> _roadCratePrefabs = new HashSet<uint>();
    private readonly HashSet<string> _roadCrateNames = new HashSet<string>
    {
        "crate_basic",
        "crate_basic_jungle",
        "crate_normal",
        "crate_normal_2",
        "crate_normal_2_food",
        "crate_normal_2_medical",
        "crate_tools",
        "crate_mine",
        "crate_shore",
        "crate_cannons",
        "crate_elite"
    };

    private void OnServerInitialized()
    {
        _barrelPrefabs.Clear();
        foreach (string prefab in BarrelPrefabs)
            _barrelPrefabs.Add(StringPool.Get(prefab));

        _roadCratePrefabs.Clear();
        foreach (string prefab in RoadCratePrefabs)
            _roadCratePrefabs.Add(StringPool.Get(prefab));
    }

    private void Unload()
    {
        _processing.Clear();
        _opened.Clear();
        _looted.Clear();
        _barrelPrefabs.Clear();
        _roadCratePrefabs.Clear();
    }

    private void OnLootEntity(BasePlayer player, BaseEntity entity)
    {
        LootContainer container = entity as LootContainer;
        if (container?.net != null)
            _opened.Add(container.net.ID);
    }

    private void OnItemRemovedFromContainer(ItemContainer container, Item item)
    {
        LootContainer loot = container?.entityOwner as LootContainer;
        if (loot?.net == null || loot.inventory != container || !_opened.Contains(loot.net.ID)) return;

        MarkLooted(loot);
    }

    private void OnItemSplit(Item item, int amount)
    {
        LootContainer loot = item?.parent?.entityOwner as LootContainer;
        if (loot?.net == null || !_opened.Contains(loot.net.ID)) return;

        MarkLooted(loot);
    }

    private void OnLootEntityEnd(BasePlayer player, StorageContainer container)
    {
        LootContainer loot = container as LootContainer;
        if (loot?.net == null) return;
        _opened.Remove(loot.net.ID);

        if (IsRoadCrate(loot))
        {
            _looted.Remove(loot.net.ID);
            DropRemainingRoadCrateLoot(player, loot);
            ReplaceLootContainer(loot, true);
            return;
        }

        if (!_looted.Remove(loot.net.ID) && !loot.HasBeenLooted) return;

        ReplaceLootContainer(loot, true);
    }

    private void OnEntityDeath(LootContainer loot, HitInfo info)
    {
        if (loot?.net == null || info?.InitiatorPlayer == null || !_barrelPrefabs.Contains(loot.prefabID)) return;

        ReplaceEntity(loot, RespawnDelay, false);
    }

    private void OnEntityDeath(ResourceEntity entity, HitInfo info)
    {
        if (entity?.net == null || info?.InitiatorPlayer == null) return;

        if (entity is OreResourceEntity)
        {
            ReplaceEntity(entity, OreRespawnDelay, false);
            return;
        }

        if (entity is TreeEntity)
            ReplaceEntity(entity, TreeRespawnDelay, false);

        else
            ReplaceEntity(entity, OreRespawnDelay, false);
    }

    private void OnEntityDeath(BaseAnimalNPC animal, HitInfo info)
    {
        if (animal?.net == null || info?.InitiatorPlayer == null) return;

        ReplaceEntity(animal, AnimalRespawnDelay, false);
    }

    [ConsoleCommand("floot.respawncrates")]
    private void CmdRespawnCrates(ConsoleSystem.Arg arg)
    {
        BasePlayer player = arg.Player();
        if (player != null && !player.IsAdmin) return;

        int restored;
        int count = RespawnAllRoadCrates(out restored);
        SendReply(arg, $"Пересоздано ящиков: {count}. Восстановлено пустых спавнеров: {restored}");
    }

    private void MarkLooted(LootContainer loot)
    {
        if (loot.net != null && !_processing.Contains(loot.net.ID))
            _looted.Add(loot.net.ID);
    }

    private void ReplaceLootContainer(LootContainer loot, bool killOld)
    {
        ReplaceEntity(loot, RespawnDelay, killOld);
    }

    private void DropRemainingRoadCrateLoot(BasePlayer player, LootContainer loot)
    {
        if (!IsRoadCrateWithLoot(loot)) return;

        loot.DropItems(player);
    }

    private bool IsRoadCrateWithLoot(LootContainer loot)
    {
        return IsRoadCrate(loot) && loot.inventory?.itemList != null && loot.inventory.itemList.Count > 0;
    }

    private bool IsRoadCrate(LootContainer loot)
    {
        return loot != null && (_roadCratePrefabs.Contains(loot.prefabID) || _roadCrateNames.Contains(loot.ShortPrefabName));
    }

    private int RespawnAllRoadCrates(out int restored)
    {
        List<LootContainer> crates = Facepunch.Pool.Get<List<LootContainer>>();
        foreach (BaseNetworkable networkable in BaseNetworkable.serverEntities)
        {
            LootContainer loot = networkable as LootContainer;
            if (IsRoadCrate(loot) && loot.net != null && !loot.IsDestroyed)
                crates.Add(loot);
        }

        restored = RestoreEmptyRoadCrateSpawners();
        int count = crates.Count;
        for (int i = 0; i < crates.Count; i++)
            RespawnLootContainerNow(crates[i]);

        Facepunch.Pool.FreeUnmanaged(ref crates);
        return count;
    }

    private int RestoreEmptyRoadCrateSpawners()
    {
        SpawnHandler handler = SingletonComponent<SpawnHandler>.Instance;
        if (handler == null) return 0;

        int count = 0;
        for (int i = 0; i < handler.SpawnGroups.Count; i++)
        {
            ISpawnGroup spawnGroup = handler.SpawnGroups[i];
            if (spawnGroup == null || !IsRoadCrateSpawner(spawnGroup)) continue;

            ClearDeadSpawnerInstances(spawnGroup);
            if (NeedsSpawnerFill(spawnGroup))
            {
                spawnGroup.Fill();
                count++;
            }
        }

        return count;
    }

    private bool NeedsSpawnerFill(ISpawnGroup spawnGroup)
    {
        SpawnGroup group = spawnGroup as SpawnGroup;
        if (group != null) return group.currentPopulation < group.maxPopulation;

        IndividualSpawner individual = spawnGroup as IndividualSpawner;
        return individual != null && individual.currentPopulation <= 0;
    }

    private void ClearDeadSpawnerInstances(ISpawnGroup spawnGroup)
    {
        SpawnGroup group = spawnGroup as SpawnGroup;
        if (group?.spawnInstances != null)
        {
            for (int i = group.spawnInstances.Count - 1; i >= 0; i--)
            {
                SpawnPointInstance instance = group.spawnInstances[i];
                BaseEntity entity = instance == null ? null : instance.GetComponent<BaseEntity>();
                if (entity == null || entity.IsDestroyed)
                    group.spawnInstances.RemoveAt(i);
            }
        }

        IndividualSpawner individual = spawnGroup as IndividualSpawner;
        if (individual?.spawnInstance != null)
        {
            BaseEntity entity = individual.spawnInstance.GetComponent<BaseEntity>();
            if (entity == null || entity.IsDestroyed)
                individual.spawnInstance = null;
        }
    }

    private bool IsRoadCrateSpawner(ISpawnGroup spawnGroup)
    {
        SpawnGroup group = spawnGroup as SpawnGroup;
        if (group?.prefabs != null)
        {
            for (int i = 0; i < group.prefabs.Count; i++)
            {
                SpawnGroup.SpawnEntry entry = group.prefabs[i];
                if (IsRoadCratePrefab(entry?.prefab?.resourcePath)) return true;
            }
        }

        IndividualSpawner individual = spawnGroup as IndividualSpawner;
        return IsRoadCratePrefab(individual?.entityPrefab?.resourcePath);
    }

    private bool IsRoadCratePrefab(string prefab)
    {
        if (string.IsNullOrEmpty(prefab)) return false;

        prefab = prefab.ToLowerInvariant();
        for (int i = 0; i < RoadCratePrefabs.Length; i++)
            if (prefab == RoadCratePrefabs[i])
                return true;

        return false;
    }

    private void RespawnLootContainerNow(LootContainer loot)
    {
        if (loot?.net == null || !_processing.Add(loot.net.ID)) return;

        NetworkableId id = loot.net.ID;
        SpawnPointInstance instance = loot.GetComponent<SpawnPointInstance>();
        ISpawnPointUser spawnUser = instance?.parentSpawnPointUser;
        BaseSpawnPoint spawnPoint = instance?.parentSpawnPoint;
        string prefabName = loot.PrefabName;
        Vector3 position = loot.transform.position;
        Quaternion rotation = loot.transform.rotation;
        bool enableSaving = loot.enableSaving;

        CloseLooters(loot);
        loot.Kill();

        NextTick(() =>
        {
            _processing.Remove(id);
            _opened.Remove(id);
            _looted.Remove(id);
            SpawnDirect(prefabName, position, rotation, enableSaving, spawnUser, spawnPoint);
        });
    }

    private void ReplaceEntity(BaseEntity entityToReplace, float delay, bool killOld)
    {
        if (entityToReplace.net == null || !_processing.Add(entityToReplace.net.ID)) return;

        NetworkableId id = entityToReplace.net.ID;
        SpawnPointInstance instance = entityToReplace.GetComponent<SpawnPointInstance>();
        ISpawnPointUser spawnUser = instance?.parentSpawnPointUser;
        BaseSpawnPoint spawnPoint = instance?.parentSpawnPoint;
        string prefabName = entityToReplace.PrefabName;
        Vector3 position = entityToReplace.transform.position;
        Quaternion rotation = entityToReplace.transform.rotation;
        bool enableSaving = entityToReplace.enableSaving;

        timer.Once(delay, () =>
        {
            if (killOld && entityToReplace != null && !entityToReplace.IsDestroyed)
            {
                CloseLooters(entityToReplace);
                entityToReplace.Kill();
            }

            NextTick(() =>
            {
                _processing.Remove(id);
                _opened.Remove(id);
                _looted.Remove(id);

                if (killOld && SpawnDirect(prefabName, position, rotation, enableSaving, spawnUser, spawnPoint))
                    return;

                if (spawnUser is SpawnGroup group)
                {
                    group.Spawn();
                    return;
                }

                if (spawnUser is IndividualSpawner individual)
                {
                    individual.TrySpawnEntity();
                    return;
                }

                BaseEntity entity = GameManager.server.CreateEntity(prefabName, position, rotation);
                if (entity == null) return;

                entity.enableSaving = enableSaving;
                entity.Spawn();
            });
        });
    }

    private bool SpawnDirect(string prefabName, Vector3 position, Quaternion rotation, bool enableSaving, ISpawnPointUser spawnUser, BaseSpawnPoint spawnPoint)
    {
        BaseEntity entity = GameManager.server.CreateEntity(prefabName, position, rotation);
        if (entity == null) return false;

        entity.enableSaving = enableSaving;
        entity.Spawn();

        if (spawnUser != null || spawnPoint != null)
        {
            SpawnPointInstance newInstance = entity.gameObject.AddComponent<SpawnPointInstance>();
            newInstance.parentSpawnPointUser = spawnUser;
            newInstance.parentSpawnPoint = spawnPoint;
            newInstance.Notify();
        }

        return true;
    }

    private void CloseLooters(BaseEntity entity)
    {
        foreach (BasePlayer player in BasePlayer.activePlayerList)
            if (player?.inventory?.loot?.entitySource == entity)
                player.inventory.loot.Clear();
    }
}

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