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

FREE OreEcology : 1.1.1 1.1.1

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

namespace Oxide.Plugins
{
    [Info("Ore Ecology", "Quen", "1.1.1")]
    [Description("Balances ore node density per biome, with multipliers per ore type. With cleanup & admin stats command (in chat).")]
    public class OreEcology : RustPlugin
    {
        private ConfigData config;
        private StoredData data;

        private class StoredData
        {
            public HashSet<ulong> SpawnedNodeNetIDs = new HashSet<ulong>();
        }

        #region Hooks

        private void OnServerInitialized()
        {
            LoadData();
            CleanupInvalidNodes();

            AdjustBiomeNodes();
            timer.Every(config.CheckIntervalMinutes * 60f, AdjustBiomeNodes);

            permission.RegisterPermission("oreecology.admin", this);
        }

        private void Unload()
        {
            RemoveSpawnedNodes();
            SaveData();
        }

        #endregion

        #region Commands

        [ChatCommand("oreeco")]
        private void CmdOreEco(BasePlayer player, string command, string[] args)
        {
            if (!permission.UserHasPermission(player.UserIDString, "oreecology.admin"))
            {
                SendReply(player, "<color=#ff6666>You do not have permission to use this command.</color>");
                return;
            }

            var stats = GetBiomeStatsString();
            SendReply(player, "<color=#ffd700>=== Ore Ecology Current Node Counts ===</color>");
            foreach (var line in stats)
            {
                SendReply(player, line);
            }
            // Removed the bottom divider as requested
        }

        #endregion

        #region Config

        private class ConfigData
        {
            public Dictionary<string, Dictionary<string, float>> BiomeMultipliers;
            public int MaxExtraNodesPerBiome;
            public float CheckIntervalMinutes;
            public float MaxSlope;
            public float BiomeThreshold;
            public bool RemoveOnUnload;
        }

        protected override void LoadDefaultConfig()
        {
            config = new ConfigData
            {
                BiomeMultipliers = new Dictionary<string, Dictionary<string, float>>
                {
                    { "Arid", new Dictionary<string, float>
                        {
                            { "Metal", 1.5f },
                            { "Sulfur", 1.0f },
                            { "Stone", 0.8f }
                        }
                    },
                    { "Temperate", new Dictionary<string, float>
                        {
                            { "Metal", 1.0f },
                            { "Sulfur", 1.0f },
                            { "Stone", 1.0f }
                        }
                    },
                    { "Tundra", new Dictionary<string, float>
                        {
                            { "Metal", 0.9f },
                            { "Sulfur", 1.3f },
                            { "Stone", 1.1f }
                        }
                    },
                    { "Arctic", new Dictionary<string, float>
                        {
                            { "Metal", 0.7f },
                            { "Sulfur", 2.0f },
                            { "Stone", 1.2f }
                        }
                    }
                },

                MaxExtraNodesPerBiome = 100,
                CheckIntervalMinutes = 5f,
                MaxSlope = 35f,
                BiomeThreshold = 0.6f,
                RemoveOnUnload = true
            };

            SaveConfig();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            config = Config.ReadObject<ConfigData>();

            if (config == null || config.BiomeMultipliers == null)
            {
                PrintWarning("Invalid config detected. Regenerating...");
                LoadDefaultConfig();
            }
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(config, true);
        }

        #endregion

        #region Data Management

        private void LoadData()
        {
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
            if (data == null)
                data = new StoredData();
        }

        private void SaveData()
        {
            Interface.Oxide.DataFileSystem.WriteObject(Name, data);
        }

        #endregion

        #region Data

        private readonly Dictionary<string, string> orePrefabs = new Dictionary<string, string>
        {
            { "Metal", "assets/bundled/prefabs/autospawn/resource/ores/metal-ore.prefab" },
            { "Sulfur", "assets/bundled/prefabs/autospawn/resource/ores/sulfur-ore.prefab" },
            { "Stone", "assets/bundled/prefabs/autospawn/resource/ores/stone-ore.prefab" }
        };

        private const int BiomeArid = 1;
        private const int BiomeTemperate = 2;
        private const int BiomeTundra = 4;
        private const int BiomeArctic = 8;

        #endregion

        #region Core Logic

        private void AdjustBiomeNodes()
        {
            var nodes = UnityEngine.Object.FindObjectsOfType<ResourceEntity>();
            var biomeCounts = new Dictionary<string, Dictionary<string, int>>();

            foreach (var node in nodes)
            {
                if (node == null || node.ShortPrefabName == null) continue;

                string oreType = GetOreType(node.ShortPrefabName);
                if (oreType == null) continue;

                string biome = GetBiomeName(node.transform.position);
                if (biome == "Unknown") continue;

                if (!biomeCounts.ContainsKey(biome))
                {
                    biomeCounts[biome] = new Dictionary<string, int> { { "Metal", 0 }, { "Sulfur", 0 }, { "Stone", 0 } };
                }

                biomeCounts[biome][oreType]++;
            }

            foreach (var biomeKey in config.BiomeMultipliers.Keys)
            {
                int biomeInt = BiomeNameToInt(biomeKey);
                if (biomeInt == 0) continue;

                foreach (var ore in orePrefabs.Keys)
                {
                    int current = biomeCounts.ContainsKey(biomeKey) ? biomeCounts[biomeKey][ore] : 0;
                    float multiplier = config.BiomeMultipliers[biomeKey][ore];
                    int target = Mathf.RoundToInt(current * multiplier);
                    int toSpawn = Mathf.Clamp(target - current, 0, config.MaxExtraNodesPerBiome);

                    if (toSpawn > 0)
                    {
                        int spawned = SpawnNodes(biomeKey, biomeInt, ore, toSpawn);
                        if (spawned > 0)
                        {
                            Puts($"Biome [{biomeKey}] → Spawned {spawned}x {ore} nodes.");
                        }
                    }
                }
            }
        }

        private int SpawnNodes(string biomeName, int biomeInt, string oreType, int count)
        {
            string prefab = orePrefabs[oreType];
            int spawned = 0;

            for (int i = 0; i < count * 3 && spawned < count; i++)
            {
                Vector3 pos = FindValidPos(biomeInt);
                if (pos == Vector3.zero) continue;

                var entity = GameManager.server.CreateEntity(prefab, pos);
                if (entity == null) continue;

                entity.Spawn();
                spawned++;

                data.SpawnedNodeNetIDs.Add(entity.net.ID.Value);
            }

            if (spawned < count)
            {
                Puts($"Warning: Only spawned {spawned}/{count} {oreType} nodes in {biomeName} (limited valid positions).");
            }

            SaveData();

            return spawned;
        }

        private Vector3 FindValidPos(int biomeInt)
        {
            int attempts = 80;
            for (int i = 0; i < attempts; i++)
            {
                Vector3 pos = new Vector3(
                    UnityEngine.Random.Range(-TerrainMeta.Size.x / 2 + 100f, TerrainMeta.Size.x / 2 - 100f),
                    0,
                    UnityEngine.Random.Range(-TerrainMeta.Size.z / 2 + 100f, TerrainMeta.Size.z / 2 - 100f)
                );

                pos.y = TerrainMeta.HeightMap.GetHeight(pos);

                float strength = TerrainMeta.BiomeMap.GetBiome(pos, biomeInt);
                if (strength < config.BiomeThreshold) continue;

                var normal = TerrainMeta.HeightMap.GetNormal(pos);
                float slope = Vector3.Angle(Vector3.up, normal);
                if (slope > config.MaxSlope) continue;

                if (AntiHack.TestInsideTerrain(pos)) continue;

                return pos;
            }

            return Vector3.zero;
        }

        #endregion

        #region Stats

        private List<string> GetBiomeStatsString()
        {
            var lines = new List<string>();

            var nodes = UnityEngine.Object.FindObjectsOfType<ResourceEntity>();
            var biomeCounts = new Dictionary<string, Dictionary<string, int>>();

            foreach (var node in nodes)
            {
                if (node == null || node.ShortPrefabName == null) continue;

                string oreType = GetOreType(node.ShortPrefabName);
                if (oreType == null) continue;

                string biome = GetBiomeName(node.transform.position);
                if (biome == "Unknown") continue;

                if (!biomeCounts.ContainsKey(biome))
                {
                    biomeCounts[biome] = new Dictionary<string, int> { { "Metal", 0 }, { "Sulfur", 0 }, { "Stone", 0 } };
                }

                biomeCounts[biome][oreType]++;
            }

            foreach (var biome in config.BiomeMultipliers.Keys)
            {
                lines.Add($"<color=#ffaa00>Biome: {biome}</color>");
                foreach (var ore in orePrefabs.Keys)
                {
                    int count = biomeCounts.ContainsKey(biome) ? biomeCounts[biome][ore] : 0;
                    float mult = config.BiomeMultipliers[biome][ore];
                    int baseApprox = mult > 0 ? Mathf.RoundToInt(count / mult) : 0;
                    lines.Add($"  <color=#ffffff>{ore}:</color> <color=#88ff88>{count}</color> (mult: <color=#ffff66>{mult}x</color>, base ~<color=#66ccff>{baseApprox}</color>)");
                }
            }

            return lines;
        }

        #endregion

        #region Cleanup

        private void RemoveSpawnedNodes()
        {
            if (!config.RemoveOnUnload) return;

            int removed = 0;
            foreach (var netIdValue in data.SpawnedNodeNetIDs.ToList())
            {
                var entity = BaseNetworkable.serverEntities.Find(new NetworkableId { Value = netIdValue }) as BaseEntity;
                if (entity != null && !entity.IsDestroyed)
                {
                    entity.Kill();
                    removed++;
                }
            }

            Puts($"Removed {removed} plugin-spawned ore nodes on unload/reload.");
            data.SpawnedNodeNetIDs.Clear();
            SaveData();
        }

        private void CleanupInvalidNodes()
        {
            int cleaned = 0;
            var toRemove = new List<ulong>();

            foreach (var netIdValue in data.SpawnedNodeNetIDs)
            {
                var entity = BaseNetworkable.serverEntities.Find(new NetworkableId { Value = netIdValue });
                if (entity == null || entity.IsDestroyed)
                {
                    toRemove.Add(netIdValue);
                    cleaned++;
                }
            }

            foreach (var id in toRemove)
            {
                data.SpawnedNodeNetIDs.Remove(id);
            }

            if (cleaned > 0)
            {
                Puts($"Cleaned up {cleaned} invalid/missing tracked node IDs.");
            }
        }

        #endregion

        #region Helpers

        private string GetOreType(string shortPrefab)
        {
            if (shortPrefab.Contains("metal-ore")) return "Metal";
            if (shortPrefab.Contains("sulfur-ore")) return "Sulfur";
            if (shortPrefab.Contains("stone-ore")) return "Stone";
            return null;
        }

        private string GetBiomeName(Vector3 pos)
        {
            float arid = TerrainMeta.BiomeMap.GetBiome(pos, BiomeArid);
            float temp = TerrainMeta.BiomeMap.GetBiome(pos, BiomeTemperate);
            float tund = TerrainMeta.BiomeMap.GetBiome(pos, BiomeTundra);
            float arct = TerrainMeta.BiomeMap.GetBiome(pos, BiomeArctic);

            float max = Mathf.Max(arid, Mathf.Max(temp, Mathf.Max(tund, arct)));

            if (max < config.BiomeThreshold) return "Unknown";

            if (arid == max) return "Arid";
            if (temp == max) return "Temperate";
            if (tund == max) return "Tundra";
            if (arct == max) return "Arctic";

            return "Unknown";
        }

        private int BiomeNameToInt(string name)
        {
            switch (name)
            {
                case "Arid": return BiomeArid;
                case "Temperate": return BiomeTemperate;
                case "Tundra": return BiomeTundra;
                case "Arctic": return BiomeArctic;
                default: return 0;
            }
        }

        #endregion
    }
}

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