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

FREE MeteorEvent : 2.0.9 2.0.9

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;
using VLB;
using Network;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System.Linq;
using Facepunch;
#if CARBON
using Carbon;
using Carbon.Plugins;
using Carbon.Components;
#else
using Oxide.Ext.CarbonAliases;
using System.Reflection;
#endif
namespace Oxide.Plugins {
    [Info("MeteorEvent", "ThePitereq", "2.0.9")]
#if CARBON
    public class MeteorEvent : CarbonPlugin
#else
    public class MeteorEvent : RustPlugin
#endif
    {
        [PluginReference]
        private readonly Plugin Economics, ServerRewards, BankSystem, ShoppyStock;
        private static string webhookEmbed, webhookText;
        private static readonly HashSet<SphereEntity> meteors = new HashSet<SphereEntity>();
        private static readonly HashSet<SphereEntity> fallingMeteors = new HashSet<SphereEntity>();
        private static readonly Dictionary<ulong, string> cachedSelectedEvent = new Dictionary<ulong, string>();
        private static readonly Dictionary<ulong, Dictionary<string, int>> cooldowns = new Dictionary<ulong, Dictionary<string, int>>();
        private static string cachedJson = "";
        private static Timer cooldownTimer;
        private static bool checkExplosives = true;
#if !CARBON
        public static CUI.Handler CuiHandler {
            get;
            private set;
        }
#endif
        private void OnServerInitialized() {
            LoadConfig();
            LoadMessages();
            ValidateHookRequirement();
            RegisterCommandsAndPermissions();
            StartEventTimers();
            InitializeWebhooks();
            GenerateStaticJson();
        }
        private void Unload() {
            ClearMeteors();
            using CUI cui = new CUI(CuiHandler);
            foreach (var player in BasePlayer.activePlayerList) {
                cui.Destroy("MeteorEventUI_corePanel", player);
                cui.Destroy("MeteorEventUI_updateModule", player);
            }
        }
        private void RegisterCommandsAndPermissions() {
            cmd.AddConsoleCommand("msadmin", this, nameof(MeteorEventUserConsoleCommand));
#if CARBON
            foreach (var command in config.commands) cmd.AddCovalenceCommand(command, this, nameof(MeteorEventCommand));
            cmd.AddConsoleCommand(Community.Protect("UI_MeteorEvent"), this, nameof(MeteorEventConsoleCommand), @protected : true);
#else
            foreach (var command in config.commands) cmd.AddChatCommand(command, this, nameof(MeteorEventCommand));
            cmd.AddConsoleCommand("UI_MeteorEvent", this, nameof(MeteorEventConsoleCommand));
#endif
            if (config.commandPermission) permission.RegisterPermission($"meteorevent.use", this);
            permission.RegisterPermission($"meteorevent.admin", this);
            foreach (var profile in config.profiles) if (profile.Value.purchaseConfig.requirePerm) permission.RegisterPermission($"meteorevent.purchase.{profile.Key}", this);
        }
        private void ValidateHookRequirement() {
            bool lockLargeMeteorHooks = true;
            bool lockExplosiveHooks = true;
            foreach (var profile in config.meteorPrefabs.Values) {
                if (profile.bigMeteors.bigMeteorChance > 0) {
                    lockLargeMeteorHooks = false;
                    foreach (var explosive in profile.bigMeteors.explosiveConfig.Keys) {
                        if (explosive == "ammo.rifle.explosive") {
                            lockExplosiveHooks = false;
                            break;
                        }
                    }
                    if (!lockExplosiveHooks) break;
                }
            }
            if (lockLargeMeteorHooks) {
                Unsubscribe(nameof(OnExplosiveThrown));
                Unsubscribe(nameof(OnRocketLaunched));
            }
            if (lockExplosiveHooks) Unsubscribe(nameof(OnWeaponFired));
            checkExplosives = !lockLargeMeteorHooks;
        }
        private void StartEventTimers() {
            foreach (var configTimer in config.timedEvents.Keys) RunTimedEvent(configTimer);
        }
        private static void InitializeWebhooks() {
            webhookEmbed = JsonConvert.SerializeObject(new {
                embeds = new[] {
                    new {
                        title = "{title}", color = -5, fields = new[] {
                            new {
                                name = "{message}", value = "", inline = true
                            }
                        }
                    }
                }
                ,
            }
            , Formatting.None);
            webhookText = JsonConvert.SerializeObject(new {
                content = "{message}"
            }
            , Formatting.None);
        }
        private void GenerateStaticJson() {
            using CUI cui = new CUI(CuiHandler);
            CuiElementContainer corePanel = cui.CreateContainer("MeteorEventUI_corePanel", BetterColors.Transparent, 0, 1, 0, 1, 0, 0, 0, 0, 0f, 0f, true, true, CUI.ClientPanels.HudMenu, null);
            //Background Blur
            cui.CreatePanel(corePanel, "MeteorEventUI_corePanel", BetterColors.BlackTransparent10, "assets/content/ui/uibackgroundblur.mat", 0, 1, 0, 1, 0, 0, 0, 0, true, 0f, 0f, false, false, null, null, false, "MeteorEventUI_UiBlur0", null, false);
            //Background Darker
            cui.CreatePanel(corePanel, "MeteorEventUI_corePanel", BetterColors.CraftingRadialBackground, "assets/content/ui/namefontmaterial.mat", 0, 1, 0, 1, 0, 0, 0, 0, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_UiPanel1", null, false);
            //Middle Anchor
            cui.CreatePanel(corePanel, "MeteorEventUI_corePanel", BetterColors.Transparent, "assets/content/ui/namefontmaterial.mat", 0.5f, 0.5f, 0.5f, 0.5f, 0, 0, 0, 0, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_middleAnchor", null, false);
            //Main Background
            cui.CreatePanel(corePanel, "MeteorEventUI_middleAnchor", BetterColors.RadioUiBackground, "assets/content/ui/namefontmaterial.mat", 0f, 0f, 0f, 0f, -227, 209, -108, 120, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_mainBackground", null, false);
            //Top Panel
            cui.CreatePanel(corePanel, "MeteorEventUI_mainBackground", BetterColors.LightGrayTransparent3_9, "assets/content/ui/namefontmaterial.mat", 0f, 0f, 0f, 0f, 0, 436, 202, 228, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_topPanel", null, false);
            //Close Button
            cui.CreateProtectedButton(corePanel, "MeteorEventUI_topPanel", BetterColors.RedBackground, BetterColors.RedText, " ✖", 12, "assets/content/ui/namefontmaterial.mat", 0f, 0f, 0f, 0f, 414, 432, 4, 22, "UI_MeteorEvent close", TextAnchor.MiddleLeft, CUI.Handler.FontTypes.RobotoCondensedBold, 0f, 0f, false, false, null, null, false, "MeteorEventUI_closeButton", null, false);
            //Right Panel
            cui.CreatePanel(corePanel, "MeteorEventUI_mainBackground", BetterColors.BlackTransparent20, "assets/content/ui/namefontmaterial.mat", 0f, 0f, 0f, 0f, 132, 436, 0, 202, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_rightPanel", null, false);
            //Cooldown Panel
            cui.CreatePanel(corePanel, "MeteorEventUI_rightPanel", BetterColors.LightGrayTransparent3_9, "assets/content/ui/namefontmaterial.mat", 0f, 0f, 0f, 0f, 265, 300, 182, 198, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_cooldownPanel", null, false);
            //Cooldown Icon
            cui.CreateSimpleImage(corePanel, "MeteorEventUI_cooldownPanel", "", "assets/icons/stopwatch.png", BetterColors.LightGrayTransparent73, null, 0f, 0f, 0f, 0f, 2, 14, 2, 14, 0f, 0f, false, false, null, null, false, "MeteorEventUI_UiImage4", null, false);
            //Meteor Amount Panel
            cui.CreatePanel(corePanel, "MeteorEventUI_rightPanel", BetterColors.LightGrayTransparent3_9, "assets/content/ui/namefontmaterial.mat", 0f, 0f, 0f, 0f, 265, 300, 164, 180, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_meteorAmountPanel", null, false);
            //Meteor Amount Icon
            cui.CreateSimpleImage(corePanel, "MeteorEventUI_meteorAmountPanel", "", "assets/content/ui/map/icon-map_rock.png", BetterColors.LightGrayTransparent73, null, 0f, 0f, 0f, 0f, 0, 16, 0, 16, 0f, 0f, false, false, null, null, false, "MeteorEventUI_UiImage5", null, false);
            //Bottom Panel
            cui.CreatePanel(corePanel, "MeteorEventUI_rightPanel", BetterColors.LightGrayTransparent8, "assets/content/ui/namefontmaterial.mat", 0f, 0f, 0f, 0f, 0, 304, 0, 28, false, 0f, 0f, false, false, null, null, false, "MeteorEventUI_bottomPanel", null, false);
            //Info Icon
            cui.CreateSimpleImage(corePanel, "MeteorEventUI_bottomPanel", "", "assets/icons/info.png", BetterColors.LightGrayTransparent73, null, 0f, 0f, 0f, 0f, 6, 22, 6, 22, 0f, 0f, false, false, null, null, false, "MeteorEventUI_UiImage7", null, false);
            cachedJson = CuiHelper.ToJson(corePanel);
        }
        private void CheckCooldownTimer() {
            int cooldownCount = cooldowns.Count;
            if (cooldownCount > 0 && cooldownTimer == null) {
                cooldownTimer = timer.Every(1f, () => RunCooldownTimer());
            }
            else if (cooldownCount == 0 && cooldownTimer != null) {
                cooldownTimer.Destroy();
                cooldownTimer = null;
            }
        }
        private static void RunCooldownTimer() {
            foreach (var user in cooldowns.ToList()) {
                foreach (var profile in user.Value.ToList()) {
                    cooldowns[user.Key][profile.Key]--;
                    if (cooldowns[user.Key][profile.Key] <= 0) {
                        cooldowns[user.Key].Remove(profile.Key);
                        if (cooldowns[user.Key].Count == 0) cooldowns.Remove(user.Key);
                    }
                }
            }
        }
        private static void ClearMeteors() {
            var meteorsCopy = new List<BaseEntity>(meteors);
            foreach (var meteor in meteorsCopy) {
                if (meteor == null || meteor.IsDestroyed) continue;
                MeteorController controller = meteor.GetComponent<MeteorController>();
                if (controller == null) continue;
                controller.KillMeteor();
            }
            var fallingMeteorsCopy = new List<BaseEntity>(fallingMeteors);
            foreach (var meteor in fallingMeteorsCopy) {
                if (meteor == null || meteor.IsDestroyed) continue;
                FallingMeteorController controller = meteor.GetComponent<FallingMeteorController>();
                controller.DestroyFallingMeteor(false);
            }
            meteors.Clear();
            fallingMeteors.Clear();
            if (config.enableHooks) Interface.CallHook("OnMeteorsKilled");
        }
        private void MeteorEventCommand(BasePlayer player, string command, string[] args) {
            if (config.commandPermission && !permission.UserHasPermission(player.UserIDString, "meteorevent.use")) {
                SendReply(player, Lang("NoPermission", player.UserIDString));
                return;
            }
            if (args.Length == 0) OpenMeteorEventUI(player);
            else if (args.Length < 3) {
                if (!permission.UserHasPermission(player.UserIDString, "meteorevent.admin")) {
                    OpenMeteorEventUI(player);
                    return;
                }
                SendReply(player, Lang("CommandHelp", player.UserIDString, command));
            }
            else if (args[0].ToLower() == "direct") {
                if (!permission.UserHasPermission(player.UserIDString, "meteorevent.admin")) {
                    OpenMeteorEventUI(player);
                    return;
                }
                string profile = args[1];
                if (!config.profiles.ContainsKey(profile)) {
                    SendReply(player, Lang("NoProfileFound", player.UserIDString, profile));
                    return;
                }
                BasePlayer directPlayer = BasePlayer.FindAwakeOrSleeping(args[2]);
                if (directPlayer == null) {
                    SendReply(player, Lang("NoPlayerFound", player.UserIDString, args[2]));
                    return;
                }
                int meteorAmount = 1;
                if (args.Length > 3) int.TryParse(args[2], out meteorAmount);
                SendReply(player, Lang("CallingDirectOnPlayer", player.UserIDString, profile, directPlayer.displayName, meteorAmount));
                RunMeteorShower(profile, meteorAmount, true, directPlayer);
            }
        }
        private void MeteorEventConsoleCommand(ConsoleSystem.Arg arg) {
            BasePlayer player = arg.Player();
            if (config.enableLogs) Puts($"Player {player.displayName} ({player.UserIDString}) ran MeteorEventUI sub-command: {arg.FullString}");
            using CUI cui = new CUI(CuiHandler);
            switch (arg.Args[0]) {
                case "close" : cui.Destroy("MeteorEventUI_corePanel", player);
                cui.Destroy("MeteorEventUI_updateModule", player);
                break;
                case "switch" : string oldCategory = cachedSelectedEvent[player.userID];
                cachedSelectedEvent[player.userID] = arg.Args[1];
                UpdateDisplay(player, oldCategory);
                break;
                case "forceStart" : int meteorCount;
                if (int.TryParse(arg.Args[2], out meteorCount)) {
                    if (meteorCount <= 0) return;
                    cui.Destroy("MeteorEventUI_corePanel", player);
                    cui.Destroy("MeteorEventUI_updateModule", player);
                    RunMeteorShower(arg.Args[1], meteorCount);
                }
                break;
                case "start" : cui.Destroy("MeteorEventUI_corePanel", player);
                cui.Destroy("MeteorEventUI_updateModule", player);
                TryPurchaseEvent(player, arg.Args[1]);
                break;
            }
        }
        private void MeteorEventUserConsoleCommand(ConsoleSystem.Arg arg) {
            if (!arg.IsAdmin) return;
            if (arg.Args == null || arg.Args.Length < 1) {
                SendReply(arg, "Meteor Event Admin Commands:\nmsadmin run <profile> <amount> - Starts meteor event of desired profile with certain amount of meteors.\nmsadmin direct <profile> [amount] [userId] - Starts direct meteor event of desired profile with certain amount of meteors at certain player.\n\nmsadmin kill - Kills all meteors around the map");
                return;
            }
            switch (arg.Args[0]) {
                case "run" : string profile = arg.Args[1];
                if (!config.profiles.ContainsKey(profile)) {
                    SendReply(arg, "[ERROR] Couldn't find meteor event profile!");
                    return;
                }
                int amount;
                if (int.TryParse(arg.Args[2], out amount)) RunMeteorShower(profile, amount);
                else SendReply(arg, "[ERROR] Specify correct amount of meteors!");
                break;
                case "direct" : profile = arg.Args[1];
                if (!config.profiles.ContainsKey(profile)) {
                    SendReply(arg, "[ERROR] Couldn't find meteor event profile!");
                    return;
                }
                amount = 1;
                if (arg.Args.Length > 1) int.TryParse(arg.Args[2], out amount);
                BasePlayer directPlayer = null;
                ulong directId = 0;
                if (arg.Args.Length > 2 && ulong.TryParse(arg.Args[3], out directId)) directPlayer = BasePlayer.FindByID(directId);
                if (directId != 0 && directPlayer == null) {
                    SendReply(arg, "[ERROR] Player not found!");
                    return;
                }
                RunMeteorShower(profile, amount, true, directPlayer);
                break;
                case "kill" : ClearMeteors();
                break;
                default : SendReply(arg, "[ERROR] Invalid format!\nMeteor Event Admin Commands:\nmsadmin run <profile> <amount> - Starts meteor event of desired profile with certain amount of meteors.\nmsadmin direct <profile> [amount] [userId] - Starts direct meteor event of desired profile with certain amount of meteors at certain player.\n\nmsadmin kill - Kills all meteors around the map");
                break;
            }
        }
        private void TryPurchaseEvent(BasePlayer player, string profile) {
            MeteorConfig configValue = config.profiles[profile];
            if (configValue.purchaseConfig.showerCooldown > 0 && cooldowns.ContainsKey(player.userID) && cooldowns[player.userID].ContainsKey(profile)) return;
            bool hasRequiredItem;
            if (configValue.purchaseConfig.requiredShortname == "") hasRequiredItem = HaveCurrency(player, configValue.purchaseConfig.economyPlugin, configValue.purchaseConfig.economyCurrency) >= configValue.purchaseConfig.showerItemAmount;
            else {
                int itemAmount = 0;
                List<Item> playerItems = new List<Item>();
                playerItems.AddRange(player.inventory.containerMain.itemList);
                playerItems.AddRange(player.inventory.containerBelt.itemList);
                playerItems.AddRange(player.inventory.containerWear.itemList);
                foreach (var item in playerItems) {
                    if (item.info.shortname == configValue.purchaseConfig.requiredShortname && item.skin == configValue.purchaseConfig.requiredSkin) {
                        itemAmount += item.amount;
                    }
                }
                hasRequiredItem = itemAmount >= configValue.purchaseConfig.showerItemAmount;
            }
            if (!hasRequiredItem) return;
            if (configValue.purchaseConfig.requiredShortname == "") TakeCurrency(player, configValue.purchaseConfig.showerItemAmount, configValue.purchaseConfig.economyPlugin, configValue.purchaseConfig.economyCurrency);
            else {
                int remainingAmount = configValue.purchaseConfig.showerItemAmount;
                // Collect items from all inventory containers (main, belt, and wear)
                List<Item> playerItems = new List<Item>();
                playerItems.AddRange(player.inventory.containerMain.itemList);
                playerItems.AddRange(player.inventory.containerBelt.itemList);
                playerItems.AddRange(player.inventory.containerWear.itemList);
                // Loop through all items
                foreach (var item in playerItems) {
                    if (item.info.shortname == configValue.purchaseConfig.requiredShortname && item.skin == configValue.purchaseConfig.requiredSkin) {
                        if (item.amount < remainingAmount) {
                            remainingAmount -= item.amount;
                            item.GetHeldEntity()?.Kill();
                            // Kill the held entity (if applicable)
                            item.RemoveFromContainer();
                            // Remove the item from its container
                            item.Remove();
                            // Remove the item entirely
                        }
                        else {
                            item.amount -= remainingAmount;
                            // Reduce item amount by the remaining required amount
                            item.MarkDirty();
                            // Mark the item as dirty to update the inventory
                            break;
                            // Break after deducting the required amount
                        }
                    }
                }
            }
            if (configValue.purchaseConfig.showerCooldown > 0) {
                cooldowns.TryAdd(player.userID, new Dictionary<string, int>());
                cooldowns[player.userID].TryAdd(profile, 0);
                cooldowns[player.userID][profile] = configValue.purchaseConfig.showerCooldown;
                CheckCooldownTimer();
            }
            if (config.enableLogs) Puts($"Player {player.displayName} ({player.UserIDString}) purchased meteor event of profile '{profile}'.");
            SendReply(player, Lang("SuccessfullyPurchasedEvent", player.UserIDString));
            RunMeteorShower(profile, configValue.purchaseConfig.showerMeteorAmount, configValue.purchaseConfig.isDirect, player, configValue.purchaseConfig.allowLarge);
        }
        private object OnMeleeAttack(BasePlayer player, HitInfo info) {
            if (info.HitEntity == null) return null;
            SphereEntity sphere = info.HitEntity.GetParentEntity() as SphereEntity;
            if (sphere == null) return null;
            MeteorController controller = sphere.GetComponent<MeteorController>();
            if (controller == null) return null;
            MeteorPrefabConfig configValue = config.meteorPrefabs[controller.profile];
            string shortname = player.GetActiveItem()?.info?.shortname ?? "";
            if (controller.largeMeteor) {
                if (shortname == "" || !configValue.bigMeteors.explosiveConfig.ContainsKey(shortname)) {
                    SendReply(player, Lang($"WrongToolToGather_{controller.profile}", player.UserIDString));
                    return false;
                }
            }
            if (configValue.toolBlacklist.Contains(shortname)) {
                SendReply(player, Lang("ToolInBlacklist", player.UserIDString));
                return false;
            }
            if (configValue.toolWhitelist.Count > 0 && !configValue.toolWhitelist.Contains(shortname)) {
                SendReply(player, Lang("ToolNotInWhitelist", player.UserIDString));
                return false;
            }
            OreResourceEntity ore = info.HitEntity as OreResourceEntity;
            if (ore != null) InitializeCustomGatherMethod(info, ore);
            else InitializeFullyCustomGatherMethod(player, info, controller, configValue);
            return false;
        }
        private void OnPlayerConnected() => FixMarkerVisibility();
        private void OnExplosiveThrown(BasePlayer player, BaseEntity entity) => entity.OwnerID = player.userID;
        private void OnRocketLaunched(BasePlayer player, BaseEntity entity) => entity.OwnerID = player.userID;
        private void OnEntityKill(TimedExplosive explosive) {
            if (!checkExplosives || explosive.OwnerID == 0) return;
            OreResourceEntity node = explosive.GetParentEntity() as OreResourceEntity;
            if (node == null) {
                if (explosive.GetComponent<ServerProjectile>() == null) return;
                List<OreResourceEntity> nearbyOres = Pool.GetList<OreResourceEntity>();
                Vis.Entities(explosive.transform.position, 1, nearbyOres);
                foreach (var nearbyNode in nearbyOres) {
                    SphereEntity nearbySphere = nearbyNode.GetParentEntity() as SphereEntity;
                    if (nearbySphere == null) continue;
                    MeteorController nearbyController = nearbySphere.GetComponent<MeteorController>();
                    if (nearbyController == null || !nearbyController.largeMeteor) continue;
                    BasePlayer player1 = BasePlayer.FindByID(explosive.OwnerID);
                    if (player1 == null) continue;
                    DamageNode(nearbyNode, nearbyController, player1, explosive.ShortPrefabName);
                }
                Pool.FreeList(ref nearbyOres);
                return;
            }
            SphereEntity sphere = node.GetParentEntity() as SphereEntity;
            if (sphere == null) return;
            MeteorController controller = sphere.GetComponent<MeteorController>();
            if (controller == null || !controller.largeMeteor) return;
            BasePlayer player2 = BasePlayer.FindByID(explosive.OwnerID);
            if (player2 == null) return;
            DamageNode(node, controller, player2, explosive.ShortPrefabName);
        }
        private void OnWeaponFired(BaseProjectile projectile, BasePlayer player) {
            if (projectile.primaryMagazine.ammoType.shortname != "ammo.rifle.explosive") return;
            RaycastHit hit;
            if (Physics.Raycast(player.eyes.HeadRay(), out hit, config.allMeteors.maxDistanceAmmo)) {
                OreResourceEntity hitRock = hit.GetCollider().ToBaseEntity() as OreResourceEntity;
                if (hitRock == null) return;
                SphereEntity sphere = hitRock.GetParentEntity() as SphereEntity;
                if (sphere == null) return;
                MeteorController controller = sphere.GetComponent<MeteorController>();
                if (controller == null || !controller.largeMeteor) return;
                DamageNode(hitRock, controller, player, "ammo.rifle.explosive");
            }
        }
        private void OnEntityKill(OreResourceEntity rock) => CheckForMeteorKill(rock);
        private void CheckForMeteorKill(OreResourceEntity rock) {
            if (rock.transform.position.y < 0) return;
            SphereEntity sphere = rock.GetParentEntity() as SphereEntity;
            if (sphere == null) {
                if (!config.randomDirectEventsEnabled) return;
                RunRandomMeteorEvent(rock);
                return;
            }
            MeteorController controller = sphere.GetComponent<MeteorController>();
            if (controller == null) return;
            controller.KillMeteor();
        }
        private void RunRandomMeteorEvent(OreResourceEntity rock) {
            foreach (var randomEvent in config.randomDirectEvents) {
                if (Core.Random.Range(0f, 100f) > randomEvent.chance) continue;
                int meteorCount = randomEvent.minMeteors == randomEvent.maxMeteors ? randomEvent.minMeteors : Core.Random.Range(randomEvent.minMeteors, randomEvent.maxMeteors + 1);
                List<BasePlayer> nearbyPlayers = Pool.GetList<BasePlayer>();
                Vis.Entities(rock.transform.position, 2.5f, nearbyPlayers);
                if (nearbyPlayers.Count == 0) {
                    Pool.FreeList(ref nearbyPlayers);
                    return;
                }
                RunMeteorShower(randomEvent.profileName, meteorCount, true, nearbyPlayers[0], randomEvent.allowLarge);
                Pool.FreeList(ref nearbyPlayers);
            }
        }
        private static void FixMarkerVisibility() {
            foreach (var meteor in meteors) foreach (var child in meteor.children) if (child is MapMarkerGenericRadius marker) marker.SendUpdate();
        }
        private void OnDispenserBonus(ResourceDispenser dispenser, BasePlayer player, Item item) {
            OreResourceEntity node = dispenser._baseEntity?.GetComponent<OreResourceEntity>();
            if (node == null) return;
            TryGiveBonusItems(node, player, item, true);
        }
        private void OnDispenserGather(ResourceDispenser dispenser, BasePlayer player, Item item) {
            OreResourceEntity node = dispenser._baseEntity?.GetComponent<OreResourceEntity>();
            if (node == null) return;
            TryGiveBonusItems(node, player, item);
        }
        private static void TryGiveBonusItems(OreResourceEntity node, BasePlayer player, Item item, bool finalHit = false) {
            SphereEntity sphere = node.GetParentEntity() as SphereEntity;
            if (sphere == null) return;
            MeteorController controller = sphere.GetComponent<MeteorController>();
            if (controller == null) return;
            MeteorPrefabConfig configValue = config.meteorPrefabs[controller.profile];
            item.amount = (int)Mathf.Round(item.amount * configValue.meteorYieldMultiplier);
            if (configValue.scaleMeteorYield) item.amount = (int)Mathf.Round(item.amount * sphere.lerpRadius);
            foreach (var bonusItem in configValue.additionalOutput) {
                if (bonusItem.lastHitOnly && !finalHit) continue;
                if (bonusItem.requiredAmount > 0 && item.amount < bonusItem.requiredAmount) continue;
                if (Core.Random.Range(0f, 100f) <= bonusItem.chance) {
                    Item bonus = ItemManager.CreateByName(bonusItem.shortname, bonusItem.amount, bonusItem.skinId);
                    if (bonusItem.name != "") bonus.name = bonusItem.name;
                    player.GiveItem(bonus);
                }
            }
        }
        private static void TryGiveCustomBonusItems(BaseEntity entity, BasePlayer player, int damageDealt, bool finalHit = false) {
            SphereEntity sphere = entity.GetParentEntity() as SphereEntity;
            if (sphere == null) return;
            MeteorController controller = sphere.GetComponent<MeteorController>();
            if (controller == null) return;
            MeteorPrefabConfig configValue = config.meteorPrefabs[controller.profile];
            foreach (var bonusItem in configValue.additionalOutput) {
                if (bonusItem.lastHitOnly && !finalHit) continue;
                if (bonusItem.requiredAmount > 0 && damageDealt < bonusItem.requiredAmount) continue;
                if (Core.Random.Range(0f, 100f) <= bonusItem.chance) {
                    Item bonus = ItemManager.CreateByName(bonusItem.shortname, bonusItem.amount, bonusItem.skinId);
                    if (bonusItem.name != "") bonus.name = bonusItem.name;
                    player.GiveItem(bonus);
                }
            }
        }
        private void InitializeFullyCustomGatherMethod(BasePlayer player, HitInfo info, MeteorController controller, MeteorPrefabConfig configValue) {
            BaseCombatEntity entity = info.HitEntity as BaseCombatEntity;
            if (entity == null) {
                Puts($"You've set {info.HitEntity.ShortPrefabName} as meteor, but it isn't an BaseCombatEntity and can't be used as meteor!");
                return;
            }
#if CARBON
            Item tool = info.Weapon?.cachedItem;
#else
            Item tool = info.Weapon.GetCachedItem();
#endif
            if (tool == null) return;
            string itemShortname = configValue.customGather.customGatherTools.ContainsKey(tool.info.shortname) ? tool.info.shortname : "*";
            if (!configValue.customGather.customGatherTools.ContainsKey(itemShortname)) {
                SendReply(player, Lang($"WrongToolToGather_{controller.profile}", player.UserIDString));
                return;
            }
            CustomToolConfig customToolConfig = configValue.customGather.customGatherTools[itemShortname];
            if (customToolConfig.requireSkin && tool.skin != customToolConfig.skin) {
                SendReply(player, Lang($"WrongToolToGather_{controller.profile}", player.UserIDString));
                return;
            }
            float dealtDmg = entity.MaxHealth() / 100f * customToolConfig.damageDealtPercentage;
            entity.health -= dealtDmg;
            entity.SendNetworkUpdate();
            bool lastHit = entity.health <= 0;
            foreach (var resource in configValue.customGather.meteorItems) {
                if (resource.lastHitOnly && !lastHit) continue;
                float percentage = lastHit && resource.lastHitOnly ? 100f : customToolConfig.damageDealtPercentage;
                int resourceAmount = (int)Mathf.Round(resource.amount / 100f * percentage);
                if (resourceAmount == 0) continue;
                Item outputItem = ItemManager.CreateByName(resource.shortname, resourceAmount, resource.skinId);
                if (resource.name != "") outputItem.name = resource.name;
                player.GiveItem(outputItem);
            }
            TryGiveCustomBonusItems(entity, player, Mathf.CeilToInt(dealtDmg), lastHit);
            if (lastHit) {
                entity.Kill(BaseNetworkable.DestroyMode.Gib);
                controller.KillMeteor();
            }
        }
#region Edited RUST Gather Code
#if !CARBON
        private static readonly Dictionary<OreResourceEntity, int> bonusesKilled = new Dictionary<OreResourceEntity, int>();
#endif
        private static void InitializeCustomGatherMethod(HitInfo info, OreResourceEntity ore) {
            if (!info.DidGather && info.gatherScale > 0f) {
                Jackhammer jackhammer = info.Weapon as Jackhammer;
                if (ore._hotSpot || jackhammer) {
                    if (ore._hotSpot == null) ore._hotSpot = ore.SpawnBonusSpot(ore.lastNodeDir);
#if CARBON
                    if ((ore._hotSpot != null && Vector3.Distance(info.HitPositionWorld, ore._hotSpot.transform.position) <= ore._hotSpot.GetComponent<SphereCollider>().radius * 1.5f) || jackhammer != null) {
                        float num = (jackhammer == null) ? 1f : jackhammer.HotspotBonusScale;
                        ore.bonusesKilled++;
                        info.gatherScale = 1f + Mathf.Clamp((float)ore.bonusesKilled * 0.5f, 0f, 2f * num);
                        if (ore._hotSpot != null) {
                            ore._hotSpot.FireFinishEffect();
                            ore.ClientRPC<int, Vector3>(null, "PlayBonusLevelSound", ore.bonusesKilled, ore._hotSpot.transform.position);
                        }
                    }
                    else if (ore.bonusesKilled > 0) {
                        ore.bonusesKilled = 0;
                        Effect.server.Run(ore.bonusFailEffect.resourcePath, ore.transform.position, ore.transform.up, null, false);
                    }
                    if (ore.bonusesKilled > 0) ore.CleanupBonus();
#else
                    bonusesKilled.TryAdd(ore, 0);
                    if ((ore._hotSpot != null && Vector3.Distance(info.HitPositionWorld, ore._hotSpot.transform.position) <= ore._hotSpot.GetComponent<SphereCollider>().radius * 1.5f) || jackhammer != null) {
                        float num = (jackhammer == null) ? 1f : jackhammer.HotspotBonusScale;
                        bonusesKilled[ore]++;
                        info.gatherScale = 1f + Mathf.Clamp((float)bonusesKilled[ore] * 0.5f, 0f, 2f * num);
                        if (ore._hotSpot != null) {
                            ore._hotSpot.FireFinishEffect();
                            ore.ClientRPC<int, Vector3>(null, "PlayBonusLevelSound", bonusesKilled[ore], ore._hotSpot.transform.position);
                        }
                    }
                    else if (bonusesKilled[ore] > 0) {
                        bonusesKilled[ore] = 0;
                        Effect.server.Run(ore.bonusFailEffect.resourcePath, ore.transform.position, ore.transform.up, null, false);
                    }
                    if (bonusesKilled[ore] > 0) ore.CleanupBonus();
#endif
                }
            }
            if (ore._hotSpot == null) ore.DelayedBonusSpawn();
            if (ore.isServer && !ore.IsDestroyed) {
                if (ore.resourceDispenser != null) {
                    if (!ore.resourceDispenser.baseEntity.isServer) return;
                    if (info.DidGather) return;
                    if (ore.resourceDispenser.gatherType == ResourceDispenser.GatherType.UNSET) {
                        Debug.LogWarning("Object :" + ore.resourceDispenser.gameObject.name + ": has unset gathertype!");
                        return;
                    }
                    BaseMelee baseMelee = (info.Weapon == null) ? null : (info.Weapon as BaseMelee);
                    float num;
                    float num2;
                    if (baseMelee != null) {
                        ResourceDispenser.GatherPropertyEntry gatherInfoFromIndex = baseMelee.GetGatherInfoFromIndex(ore.resourceDispenser.gatherType);
                        num = gatherInfoFromIndex.gatherDamage * info.gatherScale;
                        num2 = gatherInfoFromIndex.destroyFraction;
                        if (num == 0f) return;
                        baseMelee.SendPunch(new Vector3(UnityEngine.Random.Range(0.5f, 1f), UnityEngine.Random.Range(-0.25f, -0.5f), 0f) * -30f * (gatherInfoFromIndex.conditionLost / 6f), 0.05f);
                        baseMelee.LoseCondition(gatherInfoFromIndex.conditionLost);
                        if (!baseMelee.IsValid() || baseMelee.IsBroken()) return;
                        info.DidGather = true;
                    }
                    else {
                        num = info.damageTypes.Total();
                        num2 = 0.5f;
                    }
                    float num3 = ore.resourceDispenser.fractionRemaining;
#if CARBON
                    ore.resourceDispenser.GiveResources(info.InitiatorPlayer, num, num2, info.Weapon);
                    ore.resourceDispenser.UpdateFraction();
#else
                    MethodInfo giveResourcesMethod = ore.resourceDispenser.GetType().GetMethod("GiveResources", BindingFlags.NonPublic | BindingFlags.Instance);
                    giveResourcesMethod.Invoke(ore.resourceDispenser, new object[] {
                        info.InitiatorPlayer, num, num2, info.Weapon
                    }
                    );
                    MethodInfo updateFractionMethod = ore.resourceDispenser.GetType().GetMethod("UpdateFraction", BindingFlags.NonPublic | BindingFlags.Instance);
                    updateFractionMethod.Invoke(ore.resourceDispenser, new object[] {
                    }
                    );
#endif
                    float damageAmount;
                    if (ore.resourceDispenser.fractionRemaining <= 0f) {
                        damageAmount = ore.resourceDispenser.baseEntity.MaxHealth();
                        if (info.DidGather && num2 < ore.resourceDispenser.maxDestroyFractionForFinishBonus) ore.resourceDispenser.AssignFinishBonus(info.InitiatorPlayer, 1f - num2, info.Weapon);
                    }
                    else damageAmount = (num3 - ore.resourceDispenser.fractionRemaining) * ore.resourceDispenser.baseEntity.MaxHealth();
                    HitInfo hitInfo = new HitInfo(info.Initiator, ore.resourceDispenser.baseEntity, Rust.DamageType.Generic, damageAmount, ore.resourceDispenser.transform.position) {
                        gatherScale = 0f, PointStart = info.PointStart, PointEnd = info.PointEnd, WeaponPrefab = info.WeaponPrefab, Weapon = info.Weapon
                    }
                    ;
                    ore.resourceDispenser.baseEntity.OnAttacked(hitInfo);
                }
                if (!info.DidGather) {
                    if (ore.baseProtection) ore.baseProtection.Scale(info.damageTypes, 1f);
                    float num = info.damageTypes.Total();
                    ore.health -= num;
                    if (ore.health <= 0f) ore.OnKilled(info);
#if CARBON
                    ore.OnHealthChanged();
#else
                    MethodInfo healthChangeMethod = ore.GetType().GetMethod("OnHealthChanged", BindingFlags.NonPublic | BindingFlags.Instance);
                    healthChangeMethod.Invoke(ore, new object[] {
                    }
                    );
#endif
                }
            }
        }
#endregion
        private static void DamageNode(OreResourceEntity node, MeteorController controller, BasePlayer player, string prefabName) {
            if (node.IsDestroyed) return;
            MeteorPrefabConfig configValue = config.meteorPrefabs[controller.profile];
            if (!configValue.bigMeteors.explosiveConfig.ContainsKey(prefabName)) return;
            float multiplier = configValue.bigMeteors.explosiveConfig[prefabName].resourceMultiplier;
            node.health -= configValue.bigMeteors.explosiveConfig[prefabName].damageDealt;
            node.UpdateNetworkStage();
            foreach (var item in configValue.bigMeteors.output) {
                if (item.lastHitOnly && node.health > 0) continue;
                if (item.chance < 100 && Core.Random.Range(0f, 100f) > item.chance) continue;
                Item createdItem = ItemManager.CreateByName(item.shortname, (int)Mathf.Round(item.amount * multiplier), item.skinId);
                if (item.name != "") createdItem.name = item.name;
                if (configValue.bigMeteors.callHook) Interface.CallHook("OnDispenserGather", node.resourceDispenser, player, createdItem);
                player.GiveItem(createdItem);
            }
            if (node.health <= 0) {
                Effect.server.Run("assets/prefabs/misc/orebonus/effects/ore_finish.prefab", node.transform.position);
                controller.KillMeteor();
            }
        }
        private void RunTimedEvent(string keyName) {
            TimedEventConfig configValue = config.timedEvents[keyName];
            float time = configValue.timerMin == configValue.timerMax ? configValue.timerMin : Core.Random.Range(configValue.timerMin, configValue.timerMax);
            timer.Once(time, () => ExecuteTimedEvent(keyName, configValue));
        }
        private void ExecuteTimedEvent(string keyName, TimedEventConfig configValue) {
            if (configValue.eventChance < 100 && Core.Random.Range(0f, 100f) > configValue.eventChance) {
                if (config.enableLogs) Puts($"Timed event {keyName} has been skipped due to chance not rolled.");
                RunTimedEvent(keyName);
                return;
            }
            if (meteors.Count > config.allMeteors.maxMeteors) {
                if (config.enableLogs) Puts($"Timed event {keyName} has been skipped due to too many meteors on map.");
                RunTimedEvent(keyName);
                return;
            }
            float meteorCount = configValue.meteorCount;
            if (configValue.basedOnOnline) meteorCount *= BasePlayer.activePlayerList.Count;
            if (meteorCount > configValue.maxMeteorCount) meteorCount = configValue.maxMeteorCount;
            if (meteorCount == 0) {
                if (config.enableLogs) Puts("There is not enough players to start meteor event.Skipping event...");
                RunTimedEvent(keyName);
                return;
            }
            int sumWeight = 0;
            foreach (var profile in configValue.spawnProfiles) sumWeight += profile.Value;
            int rolledProfile = Core.Random.Range(0, sumWeight + 1);
            sumWeight = 0;
            foreach (var profile in configValue.spawnProfiles) {
                sumWeight += profile.Value;
                if (sumWeight >= rolledProfile) {
                    int meteorCountInt = (int)Mathf.Round(meteorCount);
                    foreach (var command in configValue.commandsToRun) Server.Command(command.Replace("{meteorCount}", meteorCountInt.ToString()));
                    if (configValue.webhook.enabled) SendWebhook(configValue, meteorCountInt);
                    RunMeteorShower(profile.Key, meteorCountInt, configValue.directPlayer);
                    break;
                }
            }
            RunTimedEvent(keyName);
        }
        private void SendWebhook(TimedEventConfig configValue, int meteorCount) {
            string message = configValue.webhook.embed ? webhookEmbed.Replace("-5", configValue.webhook.color.ToString()).Replace(true.ToString(), configValue.webhook.inline.ToString().ToLower()).Replace("{title}", configValue.webhook.title).Replace("{message}", string.Format(configValue.webhook.message, meteorCount)) : webhookText.Replace("{message}", string.Format(configValue.webhook.message, meteorCount));
            webrequest.Enqueue(configValue.webhook.webhook, message, (i, s) => {
                if (i != 204) PrintWarning($"Cannot send Discord Webhook.Error {i}:\n{s}");
            }
            , this, RequestMethod.POST, new Dictionary<string, string> {
                {
                    "Content-Type", "application/json"
                }
            }
            );
        }
        private void RunMeteorShower(string profile, int meteorCount, bool direct = false, BasePlayer directPlayer = null, bool allowLarge = true) {
            MeteorConfig configValue = config.profiles[profile];
            bool soundPrefab = configValue.soundPrefab != "";
            if (!direct && (soundPrefab || configValue.message)) foreach (var player in BasePlayer.activePlayerList) {
                if (soundPrefab) Effect.server.Run(configValue.soundPrefab, player.eyes.position);
                if (configValue.message) SendReply(player, Lang($"MeteorShowerIncoming_{profile}", player.UserIDString, meteorCount));
            }
            float timeBetween = configValue.maxMeteorShowerLength / meteorCount;
            Vector3 angle = configValue.directFalling;
            Vector3 offset = Vector3.zero;
            if (!direct) {
                int sumWeight = 0;
                foreach (var angleValue in configValue.angleConfig) sumWeight += angleValue.weight;
                int rolledAngle = Core.Random.Range(0, sumWeight + 1);
                sumWeight = 0;
                foreach (var angleValue in configValue.angleConfig) {
                    sumWeight += angleValue.weight;
                    if (sumWeight >= rolledAngle) {
                        angle = angleValue.angle;
                        offset = angleValue.offset;
                        break;
                    }
                }
            }
            int summedMeteorProfileWeight = 0;
            foreach (var meteorProfile in configValue.meteorProfiles) summedMeteorProfileWeight += meteorProfile.Value;
            int counter = 0;
            float worldSize = World.Size / config.allMeteors.meteorSpread;
            if (config.enableLogs) Puts($"Started meteor shower of profile '{profile}' with {meteorCount} meteors.(direct: {direct}, directPlayer: {directPlayer != null})");
            if (config.enableHooks) Interface.CallHook("OnMeteorShowerStart", meteorCount, profile, direct, directPlayer);
            timer.Repeat(configValue.maxMeteorShowerLength / meteorCount, meteorCount, () => {
                Vector3 targetPos;
                if (direct) {
                    if (directPlayer != null) {
                        Vector3 playerPos = directPlayer.transform.position;
                        targetPos = new Vector3(playerPos.x + Core.Random.Range(-configValue.impactRadius, configValue.impactRadius), configValue.spawnHeight, playerPos.z + Core.Random.Range(-configValue.impactRadius, configValue.impactRadius));
                    }
                    else {
                        int playerIndex = counter % BasePlayer.activePlayerList.Count;
                        Vector3 targetPlayerPos = BasePlayer.activePlayerList[playerIndex].transform.position;
                        targetPos = new Vector3(targetPlayerPos.x + Core.Random.Range(-configValue.impactRadius, configValue.impactRadius), configValue.spawnHeight, targetPlayerPos.z + Core.Random.Range(-configValue.impactRadius, configValue.impactRadius));
                    }
                }
                else {
                    float randX = Core.Random.Range(-worldSize, worldSize);
                 
// ... [Code preview truncated due to length. Full source in attached file] ...

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

Другие ресурсы пользователя 15FPS

Сверху