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

FREE CelestialBarrage : 0.0.80 0.0.80

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System.Collections.Generic;
using Oxide.Core.Plugins;
using Oxide.Core;
using UnityEngine;
using Rust;
namespace Oxide.Plugins {
    [Info("CelestialBarrage", "Ftuoil Xelrash", "0.0.80")]
    [Description("Simulate a meteor strike using rockets falling from the sky")]
    class CelestialBarrage : RustPlugin {
#region Fields
        [PluginReference]
        Plugin PopupNotifications;
        private Timer EventTimer = null;
        private List<Timer> RocketTimers = new List<Timer>();
        private HashSet<BaseEntity> meteorRockets = new HashSet<BaseEntity>();
        // Track our meteor rockets
        private List<MapMarkerGenericRadius> activeMarkers = new List<MapMarkerGenericRadius>();
        // Track map markers
        private List<VendingMachineMapMarker> activeVendingMarkers = new List<VendingMachineMapMarker>();
        // Track vending markers for hover text
#endregion
#region Oxide Hooks
        private void OnServerInitialized() {
            lang.RegisterMessages(Messages, this);
            LoadVariables();
            StartEventTimer();
        }
        private void Unload() {
            StopTimer();
            foreach (var t in RocketTimers) t.Destroy();
            var objects = UnityEngine.Object.FindObjectsOfType<ItemCarrier>();
            if (objects != null) foreach (var gameObj in objects) UnityEngine.Object.Destroy(gameObj);
            // Clean up any remaining map markers
            CleanupAllMapMarkers();
        }
        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            // Check if damage is from one of our meteor rockets
            if (info?.Initiator != null && meteorRockets.Contains(info.Initiator)) {
                LogMeteorImpact(entity, info);
            }
        }
        private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
            // Clean up tracking when our rockets explode/die
            if (entity != null && meteorRockets.Contains(entity)) {
                meteorRockets.Remove(entity);
            }
        }
#endregion
#region Functions
        private void StartEventTimer() {
            if (configData.Options.EnableAutomaticEvents) {
                if (configData.Options.EventTimers.UseRandomTimer) {
                    var random = RandomRange(configData.Options.EventTimers.RandomTimerMin, configData.Options.EventTimers.RandomTimerMax);
                    EventTimer = timer.Once(random * 60, () => {
                        StartRandomOnMap();
                        StartEventTimer();
                    }
                    );
                }
                else EventTimer = timer.Repeat(configData.Options.EventTimers.EventInterval * 60, 0, () => StartRandomOnMap());
            }
        }
        private void StopTimer() {
            if (EventTimer != null) EventTimer.Destroy();
        }
        private void StartRandomOnMap() {
            // Check minimum player requirement
            if (configData?.Options?.MinimumPlayerCount != null && BasePlayer.activePlayerList.Count < configData.Options.MinimumPlayerCount) {
                Puts($"METEOR SHOWER SKIPPED: Not enough players online ({BasePlayer.activePlayerList.Count} < {configData.Options.MinimumPlayerCount})");
                return;
            }
            // Check performance monitoring
            if (configData?.Options?.PerformanceMonitoring?.EnableFPSCheck == true) {
                float currentFPS = 1f / UnityEngine.Time.unscaledDeltaTime;
                if (currentFPS < configData.Options.PerformanceMonitoring.MinimumFPS) {
                    Puts($"METEOR SHOWER CANCELLED: Low FPS detected ({currentFPS:F1} < {configData.Options.PerformanceMonitoring.MinimumFPS})");
                    return;
                }
            }
            float mapsize = (TerrainMeta.Size.x / 2) - 600f;
            float randomX = UnityEngine.Random.Range(-mapsize, mapsize);
            float randomY = UnityEngine.Random.Range(-mapsize, mapsize);
            Vector3 callAt = new Vector3(randomX, 0f, randomY);
            // Randomly select intensity for automatic events
            // 50% Optimal, 30% Mild, 20% Extreme
            ConfigData.Settings selectedSetting;
            int randomIntensity = UnityEngine.Random.Range(1, 101);
            if (randomIntensity <= 50) selectedSetting = configData.z_IntensitySettings.Settings_Optimal;
            else if (randomIntensity <= 80) selectedSetting = configData.z_IntensitySettings.Settings_Mild;
            else selectedSetting = configData.z_IntensitySettings.Settings_Extreme;
            StartRainOfFire(callAt, selectedSetting, "Automatic Event");
        }
        private bool StartOnPlayer(string playerName, ConfigData.Settings setting, string eventType) {
            BasePlayer player = GetPlayerByName(playerName);
            if (player == null) return false;
            StartRainOfFire(player.transform.position, setting, eventType);
            return true;
        }
        private void StartBarrage(Vector3 origin, Vector3 direction) => timer.Repeat(configData.BarrageSettings.RocketDelay, configData.BarrageSettings.NumberOfRockets, () => SpreadRocket(origin, direction));
        private void StartRainOfFire(Vector3 origin, ConfigData.Settings setting, string eventType = "Manual") {
            float radius = setting.Radius;
            int numberOfRockets = setting.RocketAmount;
            float duration = setting.Duration;
            bool dropsItems = setting.ItemDropControl.EnableItemDrop;
            ItemDrop[] itemDrops = setting.ItemDropControl.ItemsToDrop;
            float intervals = duration / numberOfRockets;
            // Determine intensity level by comparing settings objects
            string intensity = "Unknown";
            if (ReferenceEquals(setting, configData.z_IntensitySettings.Settings_Mild)) intensity = "Mild";
            else if (ReferenceEquals(setting, configData.z_IntensitySettings.Settings_Optimal)) intensity = "Optimal";
            else if (ReferenceEquals(setting, configData.z_IntensitySettings.Settings_Extreme)) intensity = "Extreme";
            // Log meteor shower start to console
            string gridRef = GetGridReference(origin);
            Vector3 groundPos = GetGroundPosition(origin);
            string teleportCmd = $"teleportpos {groundPos.x:F1} {groundPos.y:F1} {groundPos.z:F1}";
            // Show warning countdown if enabled
            if (configData.Options.WarningCountdown.EnableWarning) {
                if (configData.Options.NotifyEvent) {
                    if (PopupNotifications) PopupNotifications.Call("CreatePopupNotification", $"Meteor shower incoming in {configData.Options.WarningCountdown.CountdownSeconds} seconds!");
                    else PrintToChat($"Meteor shower incoming in {configData.Options.WarningCountdown.CountdownSeconds} seconds!");
                }
                // Wait for countdown before starting
                timer.Once(configData.Options.WarningCountdown.CountdownSeconds, () => {
                    StartMeteorShowerWithEffects(origin, setting, eventType, intensity, gridRef, teleportCmd, intervals, numberOfRockets, duration, radius);
                }
                );
            }
            else {
                // Start immediately without countdown
                StartMeteorShowerWithEffects(origin, setting, eventType, intensity, gridRef, teleportCmd, intervals, numberOfRockets, duration, radius);
            }
        }
        private void StartMeteorShowerWithEffects(Vector3 origin, ConfigData.Settings setting, string eventType, string intensity, string gridRef, string teleportCmd, float intervals, int numberOfRockets, float duration, float radius) {
            Puts($"========== METEOR SHOWER STARTED ==========");
            Puts($"Type: {eventType} ({intensity})");
            Puts($"Location: ({origin.x:F0}, {origin.z:F0}) Grid: {gridRef}");
            Puts($"Stats: {numberOfRockets} rockets, {duration}s duration, {radius}m radius");
            Puts($"Teleport: {teleportCmd}");
            Puts($"==========================================");
            // Create map marker if enabled
            if (configData.Options.MapMarkers.EnableMapMarkers) {
                CreateMapMarker(origin, intensity, duration);
            }
            // Call hook for rServerMessages to detect meteor shower
            Interface.CallHook("OnMeteorShowerStarted");
            timer.Repeat(intervals, numberOfRockets, () => RandomRocket(origin, radius, setting));
            // Schedule the end event hook to fire after all rockets have been spawned
            timer.Once(duration, () => {
                Puts($"========== METEOR SHOWER ENDED ===========");
                Puts($"Type: {eventType} ({intensity})");
                Puts($"Location: ({origin.x:F0}, {origin.z:F0}) Grid: {gridRef}");
                Puts($"Teleport: {teleportCmd}");
                Puts($"==========================================");
                // Remove map marker if it exists
                // Markers auto-remove via timer, no manual cleanup needed
                Interface.CallHook("OnMeteorShowerEnded");
            }
            );
        }
        private void RandomRocket(Vector3 origin, float radius, ConfigData.Settings setting) {
            bool isFireRocket = false;
            Vector2 rand = UnityEngine.Random.insideUnitCircle;
            Vector3 offset = new Vector3(rand.x * radius, 0, rand.y * radius);
            Vector3 direction = (Vector3.up * -2.0f + Vector3.right).normalized;
            Vector3 launchPos = origin + offset - direction * 200;
            if (RandomRange(1, setting.FireRocketChance) == 1) isFireRocket = true;
            BaseEntity rocket = CreateRocket(launchPos, direction, isFireRocket);
            if (setting.ItemDropControl.EnableItemDrop) {
                var comp = rocket.gameObject.AddComponent<ItemCarrier>();
                comp.SetCarriedItems(setting.ItemDropControl.ItemsToDrop);
                comp.SetDropMultiplier(configData.Options.GlobalDropMultiplier);
            }
        }
        private void SpreadRocket(Vector3 origin, Vector3 direction) {
            var barrageSpread = configData.BarrageSettings.RocketSpread;
            direction = Quaternion.Euler(UnityEngine.Random.Range((float)(-(double)barrageSpread * 0.5), barrageSpread * 0.5f), UnityEngine.Random.Range((float)(-(double)barrageSpread * 0.5), barrageSpread * 0.5f), UnityEngine.Random.Range((float)(-(double)barrageSpread * 0.5), barrageSpread * 0.5f)) * direction;
            CreateRocket(origin, direction, false);
        }
        private BaseEntity CreateRocket(Vector3 startPoint, Vector3 direction, bool isFireRocket) {
            ItemDefinition projectileItem;
            if (isFireRocket) projectileItem = ItemManager.FindItemDefinition("ammo.rocket.fire");
            else projectileItem = ItemManager.FindItemDefinition("ammo.rocket.basic");
            ItemModProjectile component = projectileItem.GetComponent<ItemModProjectile>();
            BaseEntity entity = GameManager.server.CreateEntity(component.projectileObject.resourcePath, startPoint, new Quaternion(), true);
            TimedExplosive timedExplosive = entity.GetComponent<TimedExplosive>();
            ServerProjectile serverProjectile = entity.GetComponent<ServerProjectile>();
            serverProjectile.gravityModifier = 0;
            serverProjectile.speed = 25;
            timedExplosive.timerAmountMin = 300;
            timedExplosive.timerAmountMax = 300;
            ScaleAllDamage(timedExplosive.damageTypes, configData.DamageControl.DamageMultiplier);
            // Add visual effects if enabled (simplified approach)
            if (configData.Options.VisualEffects.EnableParticleTrails) {
                AddVisualTrail(entity);
            }
            serverProjectile.InitializeVelocity(direction.normalized * 25);
            entity.Spawn();
            // Track this rocket as one of ours
            meteorRockets.Add(entity);
            return entity;
        }
        private void AddVisualTrail(BaseEntity rocket) {
            // Create a simple visual effect using existing Rust effects
            // This spawns a fire effect that follows the rocket
            timer.Repeat(0.1f, 30, () => {
                if (rocket != null && !rocket.IsDestroyed) {
                    // Spawn small fire effect at rocket position for visual trail
                    Effect.server.Run("assets/bundled/prefabs/fx/explosions/explosion_01.prefab", rocket.transform.position, Vector3.up, null, false);
                }
            }
            );
        }
        private void ScaleAllDamage(List<DamageTypeEntry> damageTypes, float scale) {
            for (int i = 0; i < damageTypes.Count; i++) {
                damageTypes[i].amount *= scale;
            }
        }
        private void LogMeteorImpact(BaseCombatEntity entity, HitInfo info) {
            string entityType = "Unknown";
            string ownerInfo = "";
            bool isPlayerStructure = false;
            // Determine what was hit
            if (entity is BasePlayer) {
                var player = entity as BasePlayer;
                entityType = "Player";
                ownerInfo = $" ({player.displayName})";
                // Screen shake effect for the hit player if enabled
                if (configData.Options.VisualEffects.EnableScreenShake) {
                    ApplyScreenShake(player, 1.0f);
                }
            }
            else if (entity.OwnerID != 0) {
                // Player-owned structure
                isPlayerStructure = true;
                var ownerPlayer = BasePlayer.FindByID(entity.OwnerID);
                entityType = entity.ShortPrefabName;
                ownerInfo = ownerPlayer != null ? $" (Owner: {ownerPlayer.displayName})" : $" (OwnerID: {entity.OwnerID})";
                // Screen shake for nearby players if enabled
                if (configData.Options.VisualEffects.EnableScreenShake) {
                    ApplyScreenShakeToNearbyPlayers(entity.transform.position, 50f, 0.5f);
                }
            }
            else {
                // Natural/NPC entity
                entityType = entity.ShortPrefabName;
            }
            // Only log and fire hook for players or player structures
            if (entity is BasePlayer || isPlayerStructure) {
                string damageInfo = $"Damage: {info.damageTypes.Total():F1}";
                Vector3 pos = entity.transform.position;
                string posInfo = $"Position: {pos.x:F0}, {pos.y:F0}, {pos.z:F0}";
                Puts($"METEOR IMPACT: {entityType}{ownerInfo} | {damageInfo} | {posInfo}");
                // Fire the hook for other plugins
                Interface.CallHook("OnMeteorImpact", entity, info, entityType, ownerInfo);
            }
        }
        private void ApplyScreenShake(BasePlayer player, float intensity) {
            // Send screen shake effect to player
            player.SendConsoleCommand("client.shake", intensity);
        }
        private void ApplyScreenShakeToNearbyPlayers(Vector3 position, float radius, float intensity) {
            foreach (var player in BasePlayer.activePlayerList) {
                if (Vector3.Distance(player.transform.position, position) <= radius) {
                    ApplyScreenShake(player, intensity);
                }
            }
        }
        private void CreateMapMarker(Vector3 position, string intensity, float duration) {
            if (!configData.Options.MapMarkers.EnableMapMarkers) return;
            try {
                string gridRef = GetGridReference(position);
                // Create a colored circle marker FIRST (like RaidableBases/Sputnik)
                var radiusMarker = GameManager.server.CreateEntity("assets/prefabs/tools/map/genericradiusmarker.prefab", position) as MapMarkerGenericRadius;
                if (radiusMarker != null) {
                    radiusMarker.enableSaving = false;
                    radiusMarker.Spawn();
                    // SPAWN FIRST!
                    // Set circle color and size based on intensity AFTER spawning
                    switch (intensity.ToLower()) {
                        case "mild" :  // Green circle
                        radiusMarker.color1 = new Color(0f, 1f, 0f, 1f);
                        radiusMarker.color2 = new Color(0f, 1f, 0f, 1f);
                        radiusMarker.radius = 0.15f;
                        radiusMarker.alpha = 0.5f;
                        break;
                        case "extreme" :  // Red circle
                        radiusMarker.color1 = new Color(1f, 0f, 0f, 1f);
                        radiusMarker.color2 = new Color(1f, 0f, 0f, 1f);
                        radiusMarker.radius = 0.2f;
                        radiusMarker.alpha = 0.6f;
                        break;
                        case "optimal" : default :  // Yellow circle
                        radiusMarker.color1 = new Color(1f, 1f, 0f, 1f);
                        radiusMarker.color2 = new Color(1f, 1f, 0f, 1f);
                        radiusMarker.radius = 0.175f;
                        radiusMarker.alpha = 0.55f;
                        break;
                    }
                    // Send updates AFTER setting properties (like Sputnik does)
                    radiusMarker.SendUpdate();
                    radiusMarker.SendNetworkUpdate();
                    // Store marker for cleanup
                    activeMarkers.Add(radiusMarker);
                }
                // Create a vending machine marker for the hover text
                var vendingMarker = GameManager.server.CreateEntity("assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab", position) as VendingMachineMapMarker;
                if (vendingMarker != null) {
                    string markerText = "";
                    switch (intensity.ToLower()) {
                        case "mild" : markerText = $"Meteor Shower (Mild) - {gridRef}";
                        break;
                        case "extreme" : markerText = $"Meteor Storm (Extreme) - {gridRef}";
                        break;
                        case "optimal" : default : markerText = $"Meteor Shower (Optimal) - {gridRef}";
                        break;
                    }
                    vendingMarker.enableSaving = false;
                    vendingMarker.Spawn();
                    vendingMarker.markerShopName = markerText;
                    vendingMarker.SendNetworkUpdate();
                    // Store for cleanup
                    activeVendingMarkers.Add(vendingMarker);
                }
                // Schedule marker removal after duration
                timer.Once(duration + 5f, () => {
                    if (radiusMarker != null && !radiusMarker.IsDestroyed) {
                        activeMarkers.Remove(radiusMarker);
                        radiusMarker.Kill();
                    }
                    if (vendingMarker != null && !vendingMarker.IsDestroyed) {
                        activeVendingMarkers.Remove(vendingMarker);
                        vendingMarker.Kill();
                    }
                }
                );
                // Also broadcast location info to all players
                foreach (var player in BasePlayer.activePlayerList) {
                    switch (intensity.ToLower()) {
                        case "mild" : player.ChatMessage($"<color=#00FF00>● METEOR SHOWER (Mild)</color> incoming at grid <color=#FFFFFF>{gridRef}</color>");
                        break;
                        case "extreme" : player.ChatMessage($"<color=#FF0000>● METEOR STORM (Extreme)</color> incoming at grid <color=#FFFFFF>{gridRef}</color>");
                        break;
                        case "optimal" : default : player.ChatMessage($"<color=#FFFF00>● METEOR SHOWER (Optimal)</color> incoming at grid <color=#FFFFFF>{gridRef}</color>");
                        break;
                    }
                }
                Puts($"Created map markers at {position} ({gridRef}) for {intensity} intensity meteor shower");
            }
            catch (System.Exception ex) {
                Puts($"Error creating map marker: {ex.Message}");
            }
        }
        private void RemoveMapMarker(Vector3 position) {
            // This method is kept for compatibility but markers auto-remove via timer
        }
        private void CleanupAllMapMarkers() {
            foreach (var marker in activeMarkers) {
                if (marker != null && !marker.IsDestroyed) {
                    marker.Kill();
                }
            }
            activeMarkers.Clear();
            foreach (var vendingMarker in activeVendingMarkers) {
                if (vendingMarker != null && !vendingMarker.IsDestroyed) {
                    vendingMarker.Kill();
                }
            }
            activeVendingMarkers.Clear();
            Puts("Cleaned up all map markers");
        }
#endregion
#region Config editing
        private void SetIntervals(int intervals) {
            StopTimer();
            configData.Options.EventTimers.EventInterval = intervals;
            SaveConfig(configData);
            StartEventTimer();
        }
        private void SetDamageMult(float scale) {
            configData.DamageControl.DamageMultiplier = scale;
            SaveConfig(configData);
        }
        private void SetNotifyEvent(bool notify) {
            configData.Options.NotifyEvent = notify;
            SaveConfig(configData);
        }
        private void SetDropRate(float rate) {
            configData.Options.GlobalDropMultiplier = rate;
            SaveConfig(configData);
        }
#endregion
#region Commands
        [ChatCommand("cb")]
        private void cmdCB(BasePlayer player, string command, string[] args) {
            if (!player.IsAdmin || args.Length == 0) {
                SendReply(player, msg("help1", player.UserIDString));
                SendReply(player, msg("help2", player.UserIDString));
                SendReply(player, msg("help3", player.UserIDString));
                SendReply(player, msg("help4", player.UserIDString));
                SendReply(player, msg("help5", player.UserIDString));
                SendReply(player, msg("help6", player.UserIDString));
                SendReply(player, msg("help7", player.UserIDString));
                SendReply(player, msg("help8", player.UserIDString));
                return;
            }
            switch (args[0].ToLower()) {
                case "onplayer" : if (args.Length == 2) {
                    if (StartOnPlayer(args[1], configData.z_IntensitySettings.Settings_Optimal, "Admin on Player")) SendReply(player, string.Format(msg("calledOn", player.UserIDString), args[1]));
                    else SendReply(player, msg("noPlayer", player.UserIDString));
                }
                else {
                    StartRainOfFire(player.transform.position, configData.z_IntensitySettings.Settings_Optimal, "Admin on Position");
                    SendReply(player, msg("onPos", player.UserIDString));
                }
                break;
                case "onplayer_extreme" : if (args.Length == 2) {
                    if (StartOnPlayer(args[1], configData.z_IntensitySettings.Settings_Extreme, "Admin on Player")) SendReply(player, msg("Extreme", player.UserIDString) + string.Format(msg("calledOn", player.UserIDString), args[1]));
                    else SendReply(player, msg("noPlayer", player.UserIDString));
                }
                else {
                    StartRainOfFire(player.transform.position, configData.z_IntensitySettings.Settings_Extreme, "Admin on Position");
                    SendReply(player, msg("Extreme", player.UserIDString) + msg("onPos", player.UserIDString));
                }
                break;
                case "onplayer_mild" : if (args.Length == 2) {
                    if (StartOnPlayer(args[1], configData.z_IntensitySettings.Settings_Mild, "Admin on Player")) SendReply(player, msg("Mild", player.UserIDString) + string.Format(msg("calledOn", player.UserIDString), args[1]));
                    else SendReply(player, msg("noPlayer", player.UserIDString));
                }
                else {
                    StartRainOfFire(player.transform.position, configData.z_IntensitySettings.Settings_Mild, "Admin on Position");
                    SendReply(player, msg("Mild", player.UserIDString) + msg("onPos", player.UserIDString));
                }
                break;
                case "barrage" : StartBarrage(player.eyes.position + player.eyes.HeadForward() * 1f, player.eyes.HeadForward());
                break;
                case "random" : StartRandomOnMap();
                SendReply(player, msg("randomCall", player.UserIDString));
                break;
                case "intervals" : if (args.Length > 1) {
                    int newIntervals;
                    bool isValid;
                    isValid = int.TryParse(args[1], out newIntervals);
                    if (isValid) {
                        if (newIntervals >= 4 || newIntervals == 0) {
                            SetIntervals(newIntervals);
                            SendReply(player, string.Format(msg("interSet", player.UserIDString), newIntervals));
                            StopTimer();
                            StartEventTimer();
                        }
                        else {
                            SendReply(player, msg("smallInter", player.UserIDString));
                        }
                    }
                    else {
                        SendReply(player, string.Format(msg("invalidParam", player.UserIDString), args[1]));
                    }
                }
                break;
                case "droprate" : if (args.Length > 1) {
                    float newDropMultiplier;
                    bool isValid;
                    isValid = float.TryParse(args[1], out newDropMultiplier);
                    if (isValid) {
                        SetDropRate(newDropMultiplier);
                        SendReply(player, msg("dropMulti", player.UserIDString) + newDropMultiplier);
                    }
                    else {
                        SendReply(player, string.Format(msg("invalidParam", player.UserIDString), args[1]));
                    }
                }
                break;
                case "damagescale" : if (args.Length > 1) {
                    float newDamageMultiplier;
                    bool isValid;
                    isValid = float.TryParse(args[1], out newDamageMultiplier);
                    if (isValid) {
                        SetDamageMult(newDamageMultiplier);
                        SendReply(player, msg("damageMulti", player.UserIDString) + newDamageMultiplier);
                    }
                    else {
                        SendReply(player, string.Format(msg("invalidParam", player.UserIDString), args[1]));
                    }
                }
                break;
                case "togglemsg" : if (configData.Options.NotifyEvent) {
                    SetNotifyEvent(false);
                    SendReply(player, msg("notifDeAct", player.UserIDString));
                }
                else {
                    SetNotifyEvent(true);
                    SendReply(player, msg("notifAct", player.UserIDString));
                }
                break;
                default : SendReply(player, string.Format(msg("unknown", player.UserIDString), args[0]));
                break;
            }
        }
        [ConsoleCommand("cb.random")]
        private void ccmdEventRandom(ConsoleSystem.Arg arg) {
            if (!arg.IsAdmin) return;
            try {
                if (configData == null) {
                    Puts("Error: Plugin configuration not loaded.Try reloading the plugin or wait a moment after server startup.");
                    return;
                }
                StartRandomOnMap();
                Puts("Random event started");
            }
            catch (System.Exception ex) {
                Puts($"Error starting random event: {ex.Message}");
            }
        }
        [ConsoleCommand("cb.onposition")]
        private void ccmdEventOnPosition(ConsoleSystem.Arg arg) {
            if (!arg.IsAdmin) return;
            if (configData == null) {
                Puts("Error: Plugin configuration not loaded.Try reloading the plugin or wait a moment after server startup.");
                return;
            }
            float x, z;
            if (arg.Args.Length == 2 && float.TryParse(arg.Args[0], out x) && float.TryParse(arg.Args[1], out z)) {
                try {
                    var position = new Vector3(x, 0, z);
                    StartRainOfFire(GetGroundPosition(position), configData.z_IntensitySettings.Settings_Optimal, "Console Command");
                    Puts($"Random event started on position {x}, {position.y}, {z}");
                }
                catch (System.Exception ex) {
                    Puts($"Error starting event at position: {ex.Message}");
                }
            }
            else Puts("Usage: cb.onposition x z");
        }
#endregion
#region Helpers
        private BasePlayer GetPlayerByName(string name) {
            string currentName;
            string lastName;
            BasePlayer foundPlayer = null;
            name = name.ToLower();
            foreach (BasePlayer player in BasePlayer.activePlayerList) {
                currentName = player.displayName.ToLower();
                if (currentName.Contains(name)) {
                    if (foundPlayer != null) {
                        lastName = foundPlayer.displayName;
                        if (currentName.Replace(name, "").Length < lastName.Replace(name, "").Length) {
                            foundPlayer = player;
                        }
                    }
                    foundPlayer = player;
                }
            }
            return foundPlayer;
        }
        private static int RandomRange(int min, int max) => UnityEngine.Random.Range(min, max);
        private Vector3 GetGroundPosition(Vector3 sourcePos) {
            RaycastHit hitInfo;
            if (Physics.Raycast(sourcePos, Vector3.down, out hitInfo, LayerMask.GetMask("Terrain", "World", "Construction"))) {
                sourcePos.y = hitInfo.point.y;
            }
            sourcePos.y = Mathf.Max(sourcePos.y, TerrainMeta.HeightMap.GetHeight(sourcePos));
            return sourcePos;
        }
        private string GetGridReference(Vector3 position) {
            // Rust map grid system: center is 0,0
            // Grid letters go A-Z from west to east, numbers 0-25+ from south to north
            float mapSize = TerrainMeta.Size.x;
            float halfMap = mapSize / 2f;
            // Convert world coordinates to grid coordinates
            float gridX = (position.x + halfMap) / (mapSize / 26f);
            float gridZ = (position.z + halfMap) / (mapSize / 26f);
            // Get grid letter (A-Z)
            char gridLetter = (char)('A' + Mathf.Clamp((int)gridX, 0, 25));
            // Get grid number (0-25+)
            int gridNumber = Mathf.Clamp((int)gridZ, 0, 25);
            return $"{gridLetter}{gridNumber}";
        }
#endregion
#region Classes
        private class ItemCarrier : MonoBehaviour {
            private ItemDrop[] carriedItems = null;
            private float multiplier;
            public void SetCarriedItems(ItemDrop[] carriedItems) => this.carriedItems = carriedItems;
            public void SetDropMultiplier(float multiplier) => this.multiplier = multiplier;
            private void OnDestroy() {
                if (carriedItems == null) return;
                int amount;
                for (int i = 0; i < carriedItems.Length; i++) {
                    if ((amount = (int)(RandomRange(carriedItems[i].Minimum, carriedItems[i].Maximum) * multiplier)) > 0) ItemManager.CreateByName(carriedItems[i].Shortname, amount).Drop(gameObject.transform.position, Vector3.up);
                }
            }
        }
        private class ItemDrop {
            public string Shortname {
                get;
                set;
            }
            public int Minimum {
                get;
                set;
            }
            public int Maximum {
                get;
                set;
            }
        }
#endregion
#region Config
        private ConfigData configData;
        class ConfigData {
            public BarrageOptions BarrageSettings {
                get;
                set;
            }
            public DamageOptions DamageControl {
                get;
                set;
            }
            public ConfigOptions Options {
                get;
                set;
            }
            public IntensityOptions z_IntensitySettings {
                get;
                set;
            }
            public class DamageOptions {
                public float DamageMultiplier {
                    get;
                    set;
                }
            }
            public class BarrageOptions {
                public int NumberOfRockets {
                    get;
                    set;
                }
                public float RocketDelay {
                    get;
                    set;
                }
                public float RocketSpread {
                    get;
                    set;
                }
            }
            public class Drops {
                public bool EnableItemDrop {
                    get;
                    set;
                }
                public ItemDrop[] ItemsToDrop {
                    get;
                    set;
                }
            }
            public class ConfigOptions {
                public bool EnableAutomaticEvents {
                    get;
                    set;
                }
                public Timers EventTimers {
                    get;
                    set;
                }
                public float GlobalDropMultiplier {
                    get;
                    set;
                }
                public bool NotifyEvent {
                    get;
                    set;
                }
                public int MinimumPlayerCount {
                    get;
                    set;
                }
                public PerformanceSettings PerformanceMonitoring {
                    get;
                    set;
                }
                public WarningSettings WarningCountdown {
                    get;
                    set;
                }
                public EffectsSettings VisualEffects {
                    get;
                    set;
                }
                public MapMarkerSettings MapMarkers {
                    get;
                    set;
                }
            }
            public class PerformanceSettings {
                public bool EnableFPSCheck {
                    get;
                    set;
                }
                public float MinimumFPS {
                    get;
                    set;
                }
            }
            public class WarningSettings {
                public bool EnableWarning {
                    get;
                    set;
                }
                public float CountdownSeconds {
                    get;
                    set;
                }
            }
            public class EffectsSettings {
                public bool EnableScreenShake {
                    get;
                    set;
                }
                public bool EnableParticleTrails {
                    get;
                    set;
                }
            }
            public class MapMarkerSettings {
                public bool EnableMapMarkers {
                    get;
                    set;
                }
            }
            public class Timers {
                public int EventInterval {
                    get;
                    set;
                }
                public bool UseRandomTimer {
                    get;
                    set;
                }
                public int RandomTimerMin {
                    get;
                    set;
                }
                public int RandomTimerMax {
                    get;
                    set;
                }
            }
            public class Settings {
                public int FireRocketChance {
                    get;
                    set;
                }
                public float Radius {
                    get;
                    set;
                }
                public int RocketAmount {
                    get;
                    set;
                }
                public int Duration {
                    get;
                    set;
                }
                public Drops ItemDropControl {
                    get;
                    set;
                }
            }
            public class IntensityOptions {
                public Settings Settings_Mild {
                    get;
                    set;
                }
                public Settings Settings_Optimal {
                    get;
                    set;
                }
                public Settings Settings_Extreme {
                    get;
                    set;
                }
            }
        }
        private void LoadVariables() {
            LoadConfigVariables();
            ValidateConfig();
            SaveConfig();
        }
        private void ValidateConfig() {
            bool configChanged = false;
            Puts("========== CONFIG VALIDATION ==========");
            // Validate and fix null config sections
            if (configData == null) {
                Puts("Config is null - creating default config");
                LoadDefaultConfig();
                return;
            }
            // Validate BarrageSettings
            if (configData.BarrageSettings == null) {
                Puts("BarrageSettings is null - creating defaults");
                configData.BarrageSettings = new ConfigData.BarrageOptions();
                configChanged = true;
            }
            if (configData.BarrageSettings.NumberOfRockets <= 0) {
                Puts($"Invalid NumberOfRockets ({configData.BarrageSettings.NumberOfRockets}) - setting to 20");
                configData.BarrageSettings.NumberOfRockets = 20;
                configChanged = true;
            }
            if (configData.BarrageSettings.RocketDelay <= 0) {
                Puts($"Invalid RocketDelay ({configData.BarrageSettings.RocketDelay}) - setting to 0.33");
                configData.BarrageSettings.RocketDelay = 0.33f;
                configChanged = true;
            }
            if (configData.BarrageSettings.RocketSpread <= 0) {
                Puts($"Invalid RocketSpread ({configData.BarrageSettings.RocketSpread}) - setting to 16");
                configData.BarrageSettings.RocketSpread = 16f;
                configChanged = true;
            }
            // Validate DamageControl
            if (configData.DamageControl == null) {
                Puts("DamageControl is null - creating defaults");
                configData.DamageControl = new ConfigData.DamageOptions();
                configChanged = true;
            }
            if (configData.DamageControl.DamageMultiplier < 0) {
                Puts($"Invalid DamageMultiplier ({configData.DamageControl.DamageMultiplier}) - setting to 0.2");
                configData.DamageControl.DamageMultiplier = 0.2f;
                configChanged = true;
            }
            // Validate Options
            if (configData.Options == null) {
                Puts("Options is null - creating defaults");
                configData.Options = new ConfigData.ConfigOptions();
                configChanged = true;
            }
            // Validate EventTimers
            if (configData.Options.EventTimers == null) {
                Puts("EventTimers is null - creating defaults");
                configData.Options.EventTimers = new ConfigData.Timers();
                configChanged = true;
            }
            if (configData.Options.EventTimers.EventInterval <= 0) {
                Puts($"Invalid EventInterval ({configData.Options.EventTimers.EventInterval}) - setting to 30");
                configData.Options.EventTimers.EventInterval = 30;
                configChanged = true;
            }
            if (configData.Options.EventTimers.RandomTimerMin <= 0) {
                Puts($"Invalid RandomTimerMin ({configData.Options.EventTimers.RandomTimerMin}) - setting to 15");
                configData.Options.EventTimers.RandomTimerMin = 15;
                configChanged = true;
            }
            if (configData.Options.EventTimers.RandomTimerMax <= configData.Options.EventTimers.RandomTimerMin) {
                Puts($"Invalid RandomTimerMax ({configData.Options.EventTimers.RandomTimerMax}) - setting to 45");
                configData.Options.EventTimers.RandomTimerMax = 45;
                configChanged = true;
            }
            if (configData.Options.GlobalDropMultiplier < 0) {
                Puts($"Invalid GlobalDropMultiplier ({configData.Options.GlobalDropMultiplier}) - setting to 1.0");
                configData.Options.GlobalDropMultiplier = 1.0f;
                configChanged = true;
            }
            if (configData.Options.MinimumPlayerCount < 0) {
                Puts($"Invalid MinimumPlayerCount ({configData.Options.MinimumPlayerCount}) - setting to 2");
                configData.Options.MinimumPlayerCount = 2;
                configChanged = true;
            }
            // Validate PerformanceMonitoring
            if (configData.Options.PerformanceMonitoring == null) {
                Puts("PerformanceMonitoring is null - creating defaults");
                configData.Options.PerformanceMonitoring = new ConfigData.PerformanceSettings();
                configChanged = true;
            }
            if (configData.Options.PerformanceMonitoring.MinimumFPS <= 0) {
                Puts($"Invalid MinimumFPS ({configData.Options.PerformanceMonitoring.MinimumFPS}) - setting to 40");
                configData.Options.PerformanceMonitoring.MinimumFPS = 40f;
                configChanged = true;
            }
            // Validate WarningCountdown
            if (configData.Options.WarningCountdown == null) {
                Puts("WarningCountdown is null - creating defaults");
                configData.Options.WarningCountdown = new ConfigData.WarningSettings();
                configChanged = true;
            }
            if (configData.Options.WarningCountdown.CountdownSeconds < 0) {
                Puts($"Invalid CountdownSeconds ({configData.Options.WarningCountdown.CountdownSeconds}) - setting to 30");
                configData.Options.WarningCountdown.CountdownSeconds = 30f;
                configChanged = true;
            }
            // Validate VisualEffects
            if (configData.Options.VisualEffects == null) {
                Puts("VisualEffects is null - creating defaults");
                configData.Options.VisualEffects = new ConfigData.EffectsSettings();
                configChanged = true;
            }
            // Validate MapMarkers
            if (configData.Options.MapMarkers == null) {
                Puts("MapMarkers is null - creating defaults");
                configData.Options.MapMarkers = new ConfigData.MapMarkerSettings();
                configChanged = true;
            }
            // Validate IntensitySettings
            if (configData.z_IntensitySettings == null) {
                Puts("IntensitySettings is null - creating defaults");
                configData.z_IntensitySettings = new ConfigData.IntensityOptions();
                configChanged = true;
            }
            // Validate Mild Settings
            if (configData.z_IntensitySettings.Settings_Mild == null) {
                Puts("Settings_Mild is null - creating defaults");
                configData.z_IntensitySettings.Settings_Mild = CreateDefaultMildSettings();
                configChanged = true;
            }
            else {
                configChanged |= ValidateSettings(configData.z_IntensitySettings.Settings_Mild, "Mild");
            }
            // Validate Optimal Settings
            if (configData.z_IntensitySettings.Settings_Optimal == null) {
                Puts("Settings_Optimal is null - creating defaults");
                configData.z_IntensitySettings.Settings_Optimal = CreateDefaultOptimalSettings();
                configChanged = true;
            }
            else {
                configChanged |= ValidateSettings(configData.z_IntensitySettings.Settings_Optimal, "Optimal");
            }
            // Validate Extreme Settings
            if (configData.z_IntensitySettings.Settings_Extreme == null) {
                Puts("Settings_Extreme is null - creating defaults");
                configData.z_IntensitySettings.Settings_Extreme = CreateDefaultExtremeSettings();
                configChanged = true;
            }
            else {
                configChanged |= ValidateSettings(configData.z_IntensitySettings.Settings_Extreme, "Extreme");
            }
            if (configChanged) {
                Puts("Config validation completed - fixed invalid values");
                SaveConfig(configData);
            }
            else {
                Puts("Config validation completed - no issues found");
            }
            Puts("======================================");
        }
        private bool ValidateSettings(ConfigData.Settings settings, string settingName) {
            bool changed = false;
            if (settings.FireRocketChance <= 0) {
                Puts($"Invalid FireRocketChance in {settingName} ({settings.FireRocketChance}) - setting to 20");
                settings.FireRocketChance = 20;
                changed = true;
            }
            if (settings.Radius <= 0) {
                Puts($"Invalid Radius in {settingName} ({settings.Radius}) - setting to 300");
                settings.Radius = 300f;
                changed = true;
            }
            if (settings.RocketAmount <= 0) {
                Puts($"Invalid RocketAmount in {settingName} ({settings.RocketAmount}) - setting to 45");
                settings.RocketAmount = 45;
                changed = true;
            }
            if (settings.Duration <= 0) {
                Puts($"Invalid Duration in {settingName} ({settings.Duration}) - setting to 120")
// ... [Code preview truncated due to length. Full source in attached file] ...

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