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

FREE DronePatrol : 1.0.24 1.0.24

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
#region License (GPL v2)
/*
    Drone Patrol - Spawn server drones and allow for player spawn
    Copyright (c)2021 RFC1920 <desolationoutpostpve@gmail.com>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License v2.0.This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
    GNU General Public License for more details.You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.Optionally you can also view the license at <http://www.gnu.org/licenses/>.*/
#endregion
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("DronePatrol", "RFC1920", "1.0.24")]
    [Description("Create server drones that fly and roam, and allow users to spawn a drone of their own.")]
    internal class DronePatrol : RustPlugin
    {
        #region vars
        [PluginReference]
        private readonly Plugin RoadFinder, Friends, Clans, Chute, GridAPI, Economics, ServerRewards, BankSystem;

        public GameObject obj;
        public Dictionary<string, Road> roads = new();
        public List<string> monNames = new();
        public SortedDictionary<string, Vector3> monPos = new();
        public SortedDictionary<string, Vector3> monSize = new();
        private Dictionary<ulong, DroneNav> pguis = new();

        public static Timer checkTimer;
        public static string droneprefab = "assets/prefabs/deployable/drone/drone.deployed.prefab";
        private ConfigData configData;

        public static DronePatrol Instance;
        private const string permDriver = "dronepatrol.use";
        private const string permAdmin = "dronepatrol.admin";
        private const string DRONEGUI = "dronepatrol.hud";

        public static Dictionary<string, uint> drones = new();
        public static bool initdone;

        public class Road
        {
            public List<Vector3> points = new();
            public float width;
            public float offset;
            public int topo;
        }
        #endregion

        #region Message
        private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
        private void Message(IPlayer player, string key, params object[] args) => player.Reply(Lang(key, player.Id, args));
        #endregion

        #region init
        private void OnServerInitialized()
        {
            LoadConfigVariables();
            Instance = this;

            AddCovalenceCommand("drone", "CmdSpawnDrone");
            AddCovalenceCommand("drones", "CmdDroneStatus");
            AddCovalenceCommand("md", "CmdSpawnMonumentDrone");
            AddCovalenceCommand("rd", "CmdSpawnRoadDrone");
            AddCovalenceCommand("fd", "CmdSpawnSpyDrone");
            AddCovalenceCommand("ringd", "CmdSpawnRingDrone");
            permission.RegisterPermission(permDriver, this);
            permission.RegisterPermission(permAdmin, this);

            if (configData.Options.SetMaxControlRange)
            {
                float maxControlRange = configData.Options?.maxControlRange > 0 ? configData.Options.maxControlRange : 5000;
                ConsoleSystem.Run(ConsoleSystem.Option.Server.FromServer(), $"drone.maxControlRange {maxControlRange}");
            }

            LoadData();

            foreach (ComputerStation station in UnityEngine.Object.FindObjectsOfType<ComputerStation>())
            {
                foreach (string drone in drones.Keys)
                {
                    if (station.controlBookmarks.Contains(drone)) station.controlBookmarks.Remove(drone);
                }
            }

            FindMonuments();
            CheckDrones(true);

            object roads = RoadFinder?.CallHook("GetRoads");
            if (roads != null)
            {
                string json = JsonConvert.SerializeObject(roads);
                this.roads = JsonConvert.DeserializeObject<Dictionary<string, Road>>(json);
                NextTick(() =>
                {
                    SpawnRingDrone();
                    SpawnRoadDrone();
                });
            }

            NextTick(() => SpawnMonumentDrone());

            initdone = true;
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["notauthorized"] = "You don't have permission to use this command.",
                ["mdstatus"] = "{0} @ {1}\n  Current target: {2} {3} (size {4}m)",
                ["rdstatus"] = "{0} @ {1}\n  Current target: {2} {3}",
                ["ringstatus"] = "{0} @ {1}",
                ["drone"] = "Drone",
                ["nosuchplayer"] = "Could not find player named {0}",
                ["spydrone"] = "Drone {0} sent to spy on {1}",
                ["spydronekilled"] = "Drone {0} has been killed",
                ["nosuchspydrone"] = "Could not find spy drone named {0}",
                ["boughtdrone"] = "Drone purchased for {0} points.",
                ["droneprice"] = "Drone must be purchased for {0} points.",
                ["helptext"] = "To spawn a drone, type /drone NAM.EOFDRONE",
                ["heading"] = "Drone headed to {0}",
                ["nextpoint"] = "next point."
            }, this);
        }

        private void CheckDrones(bool startup = false)
        {
            if (startup)
            {
                DoLog("Checking drones");
                Drone[] allDrones = UnityEngine.Object.FindObjectsOfType<Drone>();
                if (allDrones != null)
                {
                    DoLog("Searching for drones with NONE as name");
                    foreach (Drone drone in allDrones)
                    {
                        if (drone?.rcIdentifier == "NONE" && !drone.IsDestroyed)
                        {
                            UnityEngine.Object.Destroy(drone.gameObject);
                            RemoveDroneFromCS(drone?.rcIdentifier);
                        }
                    }
                }

                foreach (KeyValuePair<string, uint> d in new Dictionary<string, uint>(drones))
                {
                    Drone drone = BaseNetworkable.serverEntities.Find(new NetworkableId(d.Value)) as Drone;
                    if (drone != null)
                    {
                        DoLog($"Killing spawned drone {d.Key}({d.Value})");
                        drone?.Kill();
                        UnityEngine.Object.Destroy(drone?.gameObject);
                        RemoveDroneFromCS(drone?.rcIdentifier);
                        drones.Remove(drone?.rcIdentifier);
                    }
                    if (!configData.Drones["monument"].name.Equals(d.Key) && !configData.Drones["ring"].name.Equals(d.Key) && !configData.Drones["road"].name.Equals(d.Key))
                    {
                        try
                        {
                            DoLog($"Killing spawned drone {d.Key})");
                            drone?.Kill();
                            UnityEngine.Object.Destroy(drone?.gameObject);
                        }
                        catch { }
                        finally
                        {
                            RemoveDroneFromCS(drone?.rcIdentifier);
                            drones.Remove(drone?.rcIdentifier);
                        }
                    }
                }

                SaveData();
            }

            // Missing network group
            BaseEntity.saveList.RemoveWhere(p => !p);
            BaseEntity.saveList.RemoveWhere(p => p == null);

            // Broken/dead drones
            DoLog("Checking configured drones");
            foreach (KeyValuePair<string, uint> d in new Dictionary<string, uint>(drones))
            {
                BaseEntity drone = BaseNetworkable.serverEntities.Find(new NetworkableId(d.Value)) as BaseEntity;
                //(drone as BaseCombatEntity).diesAtZeroHealth = true;
                DoLog($"--Checking {d.Key}({d.Value})");
                if (drone == null) continue;
                if (drone.IsDestroyed || drone.IsBroken() || !drone.HasFlag(BaseEntity.Flags.Reserved2))
                {
                    DoLog($"--Respawning {d.Key}");
                    drone?.Kill();
                    UnityEngine.Object.Destroy(drone.gameObject);
                    drones.Remove(d.Key);
                    SaveData();

                    if (configData.Drones["monument"].name.Equals(d.Key))
                    {
                        SpawnMonumentDrone();
                    }
                    else if (configData.Drones["ring"].name.Equals(d.Key))
                    {
                        SpawnRingDrone();
                    }
                    else if (configData.Drones["road"].name.Equals(d.Key))
                    {
                        SpawnRoadDrone();
                    }
                }
            }
            checkTimer = timer.Once(30, () => CheckDrones());
        }

        private void Unload()
        {
            // KILL ALL DRONES OF ANY ORIGIN
            //foreach (Drone d in UnityEngine.Object.FindObjectsOfType<Drone>())
            //{
            //    UnityEngine.Object.Destroy(d.gameObject);
            //}
            foreach (DroneNav d in UnityEngine.Object.FindObjectsOfType<DroneNav>())
            {
                UnityEngine.Object.Destroy(d?.gameObject);
            }
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                CuiHelper.DestroyUi(player, DRONEGUI);
            }
        }

        private object CanPickupEntity(BasePlayer player, BaseCombatEntity drone)
        {
            if (player == null || drone == null) return null;

            DroneNav dnav = drone.gameObject.GetComponentInParent<DroneNav>();
            if (dnav != null)
            {
                if (dnav.ownerid == 0 && !player.IsAdmin)
                {
                    return true;
                }
                if (dnav.ownerid != player.userID && !IsFriend(player.userID, dnav.ownerid))
                {
                    return true;
                }
            }
            return null;
        }

        private void OnEntitySpawned(Drone drone)
        {
            if (!initdone) return;
            if (!configData.Options.setPlayerDroneInCS) return;
            if (drone == null) return;

            ComputerStation[] stations = UnityEngine.Object.FindObjectsOfType<ComputerStation>();
            if (stations.Length == 0) return;

            foreach (ComputerStation station in stations)
            {
                if (station.OwnerID != drone.OwnerID && !IsFriend(station.OwnerID, drone.OwnerID)) continue;

                if (station.controlBookmarks.Contains(drone.rcIdentifier))
                {
                    station.controlBookmarks.Remove(drone?.rcIdentifier);
                }
                station.controlBookmarks.Add(drone.rcIdentifier);
            }
        }

        private void OnEntitySpawned(ComputerStation station)
        {
            if (!initdone) return;
            if (!configData.Options.setServerDroneInAllCS) return;
            if (station == null) return;

            foreach (string drone in new List<string>() { "MonumentDrone", "RingDrone", "RoadDrone" })
            {
                if (drone == null) return;
                if (station.controlBookmarks.Contains(drone))
                {
                    station.controlBookmarks.Remove(drone);
                }
                if (drones.ContainsKey(drone))
                {
                    station.controlBookmarks.Add(drone);
                }
            }
        }

        private void OnEntityDeath(Drone drone, HitInfo info)
        {
            CheckAndRespawnDrones(drone);
        }

        //private void OnEntityKill(Drone drone)
        //{
        //    CheckAndRespawnDrones(drone);
        //}

        private void CheckAndRespawnDrones(Drone drone)
        {
            DroneNav dnav = drone.gameObject.GetComponentInParent<DroneNav>();
            if (dnav != null)
            {
                string oldName = dnav.drone.rcIdentifier;
                DoLog($"Drone {oldName} died");
                RemoveDroneFromCS(oldName);
                UnityEngine.Object.Destroy(dnav.gameObject);

                foreach (KeyValuePair<string, uint> item in drones.Where(kvp => kvp.Value == drone.net.ID.Value).ToList())
                {
                    drones.Remove(item.Key);
                }

                foreach (KeyValuePair<string, DroneInfo> item in configData.Drones.Where(kvp => kvp.Value.name == oldName).ToList())
                {
                    if (item.Value.spawn)
                    {
                        switch (item.Key)
                        {
                            case "monument":
                                SpawnMonumentDrone();
                                break;
                            case "ring":
                                SpawnRingDrone();
                                break;
                            case "road":
                                SpawnRoadDrone();
                                break;
                        }
                    }
                }
            }
        }
        #endregion

        #region Main
        private void CmdDroneStatus(IPlayer iplayer, string command, string[] args)
        {
            if (!iplayer.IsAdmin) return;

            string message = "Drone Status:\n";
            if (args.Length > 0)
            {
                string realName = args[0];
                Drone realDrone = RemoteControlEntity.FindByID(realName) as Drone;
                if (realDrone != null)
                {
                    string[] gc = (string[])GridAPI.CallHook("GetGrid", realDrone.transform.position);
                    string curr = realDrone.transform.position.ToString() + "(" + string.Concat(gc) + ")";
                    message += $"{realName} ({realDrone.net.ID}):\n\tspawned: {realDrone.isSpawned}\n\tbroken: {realDrone.IsBroken()}"
                        + $"\n\tactive: {realDrone.isActiveAndEnabled}\n\tlocation: {curr}\n";
                    Message(iplayer, message);
                }
                return;
            }
            foreach (KeyValuePair<string, DroneInfo> drone in configData.Drones)
            {
                string realName = "";
                foreach (KeyValuePair<string, uint> d in drones)
                {
                    if (d.Key.StartsWith(drone.Value.name))
                    {
                        realName = d.Key;
                    }
                }
                if (realName?.Length == 0) continue;
                BaseEntity realDrone = BaseNetworkable.serverEntities.Find(new NetworkableId(drones[realName])) as BaseEntity;
                if (realDrone == null) continue;

                string[] gc = (string[])GridAPI.CallHook("GetGrid", realDrone.transform.position);
                string curr = realDrone.transform.position.ToString() + "(" + string.Concat(gc) + ")";
                message += $"{realName} ({realDrone.net.ID}):\n\tspawned: {realDrone.isSpawned}\n\tbroken: {realDrone.IsBroken()}"
                    + $"\n\tactive: {realDrone.isActiveAndEnabled}\n\tlocation: {curr}\n";
            }
            Message(iplayer, message);
        }

        private void CmdSpawnDrone(IPlayer iplayer, string command, string[] args)
        {
            if (!iplayer.HasPermission(permDriver))
            {
                Message(iplayer, "notauthorized");
                return;
            }

            if (args.Length == 0)
            {
                Message(iplayer, "helptext");
                return;
            }
            if (args.Length == 2)
            {
                if (args[1] == "kill")
                {
                    foreach (Drone d in UnityEngine.Object.FindObjectsOfType<Drone>())
                    {
                        if (d != null && d.rcIdentifier == args[0])
                        {
                            DoLog($"Killing {d.rcIdentifier}");
                            RemoveDroneFromCS(d.rcIdentifier);
                            UnityEngine.Object.Destroy(d.gameObject);
                        }
                    }
                }
                return;
            }

            string droneName = Lang("drone");
            if (args[0] != null) droneName = args[0];

            BasePlayer player = iplayer.Object as BasePlayer;
            if (player == null) return;

            if (configData.Options.useEconomics || configData.Options.useServerRewards)
            {
                if (CheckEconomy(player, configData.Options.droneCost))
                {
                    CheckEconomy(player, configData.Options.droneCost, true);
                    Message(iplayer, "boughtdrone", configData.Options.droneCost.ToString());
                }
                else
                {
                    Message(iplayer, "droneprice", configData.Options.droneCost.ToString());
                    return;
                }
            }

            Vector3 target = player.transform.position;
            target.y = TerrainMeta.HeightMap.GetHeight(player.transform.position) + configData.Options.minHeight;

            Drone drone = GameManager.server.CreateEntity(droneprefab, target, player.transform.rotation) as Drone;
            drone.OwnerID = player.userID;

            int i = 1;
            string newName = droneName;
            while (RemoteControlEntity.IDInUse(newName))
            {
                newName = droneName + i.ToString();
                i++;
                if (i > 10) break;
            }
            drone?.UpdateIdentifier(newName, true);
            drone._maxHealth = 1000;
            drone.SetHealth(1000);
            drone.Spawn();
            drone.SendNetworkUpdateImmediate();
        }

        private void CmdSpawnSpyDrone(IPlayer iplayer, string command, string[] args)
        {
            if (!iplayer.HasPermission(permAdmin))
            {
                Message(iplayer, "notauthorized");
                return;
            }
            //string debug = string.Join(",", args); Puts($"{debug}");
            if (args.Length > 0)
            {
                if (args.Length > 1)
                {
                    if (args[1] == "kill")
                    {
                        IRemoteControllable tokillir = RemoteControlEntity.FindByID($"SPY{args[0].ToUpper()}");
                        if (tokillir != null)
                        {
                            string tkid = tokillir.GetIdentifier();
                            Drone tokill = tokillir as Drone;
                            tokill.Kill();
                            UnityEngine.Object.Destroy(tokill);
                            Message(iplayer, "spydronekilled", tkid);
                            return;
                        }
                        Message(iplayer, "nosuchspydrone", args[0].ToUpper());
                        return;
                    }
                }
                else if (args[0] == "list")
                {
                    Drone[] dnav = UnityEngine.Object.FindObjectsOfType<Drone>();
                    Dictionary<string, DroneInfo>.KeyCollection sdrones = configData.Drones.Keys;
                    foreach (Drone d in dnav)
                    {
                        if (d?.rcIdentifier.Contains("SPY") == true)
                        {
                            Message(iplayer, d.rcIdentifier);
                        }
                    }
                    return;
                }

                BasePlayer targetPlayer = FindPlayerByName(args[0]);
                if (targetPlayer == null)
                {
                    Message(iplayer, "nosuchplayer", args[0]);
                    return;
                }

                Vector3 target = targetPlayer.transform.position;
                target.y = TerrainMeta.HeightMap.GetHeight(targetPlayer.transform.position) + configData.Options.minHeight;

                Drone drone = GameManager.server.CreateEntity(droneprefab, target, targetPlayer.transform.rotation) as Drone;
                DroneNav obj = drone.gameObject.AddComponent<DroneNav>();

                BasePlayer player = iplayer.Object as BasePlayer;
                drone.OwnerID = player.userID;
                obj.ownerid = player.userID;
                obj.SetType(DroneType.Spy);
                obj.SetPlayerTarget(targetPlayer);
                obj.enabled = true;

                string plName = targetPlayer.displayName ?? targetPlayer.UserIDString;
                string droneName = $"SPY{plName}";

                int i = 1;
                string newName = droneName;
                while (RemoteControlEntity.IDInUse(newName))
                {
                    newName = droneName + i.ToString();
                    i++;
                    if (i > 10) break;
                }
                drone?.UpdateIdentifier($"{newName}", true);
                drone._maxHealth = 1000;
                drone.SetHealth(1000);
                drone.Spawn();
                drone.SendNetworkUpdateImmediate();
                SetDroneInCS(droneName);
                Message(iplayer, "spydrone", newName, plName);
            }
        }

        private void CmdSpawnMonumentDrone(IPlayer iplayer, string command, string[] args)
        {
            if (!iplayer.HasPermission(permAdmin))
            {
                Message(iplayer, "notauthorized");
                return;
            }
            if (args.Length > 0)
            {
                BaseEntity dr = BaseNetworkable.serverEntities.Find(new NetworkableId(drones[configData.Drones["monument"].name])) as BaseEntity;
                if (args[0] == "kill")
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        UnityEngine.Object.Destroy(nav.gameObject);
                    }
                }
                else if (args[0] == "status")
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        string curr;
                        string tgt;
                        if (GridAPI != null)
                        {
                            string[] gc = (string[])GridAPI.CallHook("GetGrid", nav.current);
                            curr = nav.current.ToString() + "(" + string.Concat(gc) + ")";
                            string[] gt = (string[])GridAPI.CallHook("GetGrid", nav.target);
                            tgt = nav.target.ToString() + "(" + string.Concat(gt) + ")";
                        }
                        else
                        {
                            curr = nav.current.ToString();
                            tgt = nav.target.ToString();
                        }
                        Message(iplayer, "mdstatus", nav.drone.rcIdentifier, curr, nav.currentMonument, tgt, nav.currentMonSize);
                    }
                    return;
                }
                else if (args[0] == "list")
                {
                    foreach (string key in monPos.Keys)
                    {
                        Message(iplayer, key);
                    }
                    return;
                }
                string nextMon = string.Join(" ", args);
                if (monPos.ContainsKey(nextMon))
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        nav.currentMonument = nextMon;
                        OnDroneNavChange(nav, nextMon);
                    }
                }
                return;
            }
            BasePlayer player = iplayer.Object as BasePlayer;

            Vector3 target = player.transform.position;
            target.y = TerrainMeta.HeightMap.GetHeight(player.transform.position) + configData.Options.minHeight;

            Drone drone = GameManager.server.CreateEntity(droneprefab, target, player.transform.rotation) as Drone;
            DroneNav obj = drone.gameObject.AddComponent<DroneNav>();
            obj.ownerid = player.userID;
            obj.type = DroneType.MonAll;
            drone._maxHealth = 1000;
            drone.SetHealth(1000);
            drone.Spawn();
            Message(iplayer, "Spawned Monument drone");
        }

        private void CmdSpawnRoadDrone(IPlayer iplayer, string command, string[] args)
        {
            if (!iplayer.HasPermission(permAdmin))
            {
                Message(iplayer, "notauthorized");
                return;
            }
            if (args.Length > 0)
            {
                BaseEntity dr = BaseNetworkable.serverEntities.Find(new NetworkableId(drones[configData.Drones["road"].name])) as BaseEntity;
                if (args[0] == "kill")
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        UnityEngine.Object.Destroy(nav.drone.gameObject);
                    }
                }
                else if (args[0] == "status")
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        string curr = nav.current.ToString();
                        string tgt = nav.target.ToString();
                        if (GridAPI != null)
                        {
                            string[] gc = (string[])GridAPI.CallHook("GetGrid", nav.current);
                            curr += "(" + string.Concat(gc) + ")";
                            string[] gt = (string[])GridAPI.CallHook("GetGrid", nav.target);
                            tgt += "(" + string.Concat(gt) + ")";
                        }

                        Message(iplayer, "rdstatus", nav.drone.rcIdentifier, curr, $"{nav.currentRoadName} ", tgt);
                    }
                    return;
                }
                else if (args[0] == "list")
                {
                    foreach (string key in roads.Keys)
                    {
                        Message(iplayer, key);
                    }
                    return;
                }
                if (roads.ContainsKey(args[0]))
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        nav.currentRoad = roads[args[0]];
                        OnDroneNavChange(nav, Instance.configData.Drones["road"].name);
                    }
                }
                return;
            }
            BasePlayer player = iplayer.Object as BasePlayer;
            Vector3 target = player.transform.position;
            target.y = TerrainMeta.HeightMap.GetHeight(player.transform.position) + configData.Options.minHeight;

            Drone drone = GameManager.server.CreateEntity(droneprefab, target, player.transform.rotation) as Drone;
            DroneNav obj = drone.gameObject.AddComponent<DroneNav>();
            obj.ownerid = player.userID;
            drone._maxHealth = 1000;
            drone.SetHealth(1000);
            drone.Spawn();
            string road = configData.Drones["road"].start;
            DoLog($"CmdSpawnRoadDrone: Moving to start of {road}...");
            obj.SetRoad(road);
        }

        private void CmdSpawnRingDrone(IPlayer iplayer, string command, string[] args)
        {
            if (!iplayer.HasPermission(permAdmin))
            {
                Message(iplayer, "notauthorized");
                return;
            }
            if (args.Length > 0)
            {
                BaseEntity dr = BaseNetworkable.serverEntities.Find(new NetworkableId(drones[configData.Drones["road"].name])) as BaseEntity;
                if (args[0] == "kill")
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        UnityEngine.Object.Destroy(nav.drone.gameObject);
                    }
                }
                else if (args[0] == "status")
                {
                    DroneNav nav = dr.GetComponent<DroneNav>();
                    if (nav != null)
                    {
                        string curr;
                        if (GridAPI != null)
                        {
                            string[] gc = (string[])GridAPI.CallHook("GetGrid", nav.current);
                            curr = nav.current.ToString() + "(" + string.Concat(gc) + ")";
                        }
                        else
                        {
                            curr = nav.current.ToString();
                        }
                        Message(iplayer, "ringstatus", nav.drone.rcIdentifier, curr);
                    }
                }
                return;
            }
            BasePlayer player = iplayer.Object as BasePlayer;
            Vector3 target = player.transform.position;
            target.y = TerrainMeta.HeightMap.GetHeight(player.transform.position) + configData.Options.minHeight;

            Drone drone = GameManager.server.CreateEntity(droneprefab, target, player.transform.rotation) as Drone;
            DroneNav obj = drone.gameObject.AddComponent<DroneNav>();
            obj.ownerid = player.userID;
            drone._maxHealth = 1000;
            drone.SetHealth(1000);
            drone.Spawn();
            string road = configData.Drones["ring"].start;
            DoLog($"CmdSpawnRingDrone: Moving to start of {road}...");
            obj.SetRoad(road);
        }

        private void OnPlayerInput(BasePlayer player, InputState input)
        {
            if (player == null || input == null) return;
            //if (input.current.buttons > 1)
            //    Puts($"OnPlayerInput: {input.current.buttons}");

            if (input.current.buttons == configData.Options.ActivationCode && Chute != null && pguis.ContainsKey(player.userID))
            {
                ComputerStation station = player.GetMounted() as ComputerStation;
                Drone drone = station.currentlyControllingEnt.Get(true).GetComponent<Drone>();
                if (drone != null)
                {
                    Vector3 newPos = new(drone.transform.position.x, drone.transform.position.y + 10f, drone.transform.position.z);
                    station.StopControl(player);
                    station.DismountPlayer(player, true);
                    station.SendNetworkUpdateImmediate();

                    pguis.Remove(player.userID);
                    Teleport(player, newPos);
                    Chute?.CallHook("ExternalAddPlayerChute", player, null);
                    if (drone.OwnerID == player.userID)
                    {
                        DoLog("Killing player drone.");
                        UnityEngine.Object.Destroy(drone.gameObject);
                    }
                }
            }
        }

        public void Teleport(BasePlayer player, Vector3 position)
        {
            if (player.net?.connection != null) player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, true);

            player.SetParent(null, true, true);
            player.EnsureDismounted();
            player.Teleport(position);
            player.UpdateNetworkGroup();
            player.SendNetworkUpdateImmediate();

            if (player.net?.connection != null) player.ClientRPC(RpcTarget.Player("StartLoading", player));
        }

        private object OnBookmarkAdd(ComputerStation computerStation, BasePlayer player, string bookmarkName)
        {
            DoLog($"Player {player.UserIDString} added bookmark {bookmarkName}");
            return null;
        }

        private object OnBookmarkControl(ComputerStation station, BasePlayer player, string bookmarkName, IRemoteControllable remoteControllable)
        {
            if (player == null) return null;
            Drone drone = remoteControllable as Drone;
            if (drone != null)
            {
                //CameraViewerId viewerId = drone.ControllingViewerId.Value;
                //drone.StopControl(viewerId);
                //drone.InitializeControl(new CameraViewerId(player.userID, 0));

                DroneNav obj = drone.gameObject.GetComponent<DroneNav>();
                if (obj != null)
                {
                    DoLog("Found DroneNav component");
                    obj.player = player;
                    if (!string.IsNullOrEmpty(drone?.rcIdentifier))
                    {
                        DoLog($"Player {player?.UserIDString} now controlling drone {drone?.rcIdentifier}, owned by {drone?.OwnerID}");
                    }

                    if (obj?.currentRoad != null)
                    {
                        string roadname = string.IsNullOrEmpty(obj?.currentRoadName) ? Lang("nexpoint") : obj?.currentRoadName;
                        DroneGUI(player, obj, Lang("heading", roadname, roadname));
                    }
                    else if (obj.currentMonument?.Length > 0)
                    {
                        DroneGUI(player, obj, Lang("heading", obj.currentMonument, obj.currentMonument));
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(drone.rcIdentifier))
                    {
                        DroneGUI(player, null, $"{player?.displayName}'s {Lang("drone")}, {drone.rcIdentifier}.");
                    }
                    else
                    {
                        DroneGUI(player, null, player?.displayName + "'s " + Lang("drone"));
                    }
                }
            }
            return null;
        }

        private object OnBookmarkControlEnd(ComputerStation computerStation, BasePlayer player, BaseEntity controlledEntity)
        {
            CuiHelper.DestroyUi(player, DRONEGUI);
            pguis.Remove(player.userID);
            return null;
        }

        private void DroneGUI(BasePlayer player, DroneNav drone, string target = null, string monName = "UNKNOWN")
        {
            if (player == null) return;

            pguis.Remove(player.userID);
            CuiHelper.DestroyUi(player, DRONEGUI);
            if (drone != null) pguis.Add(player.userID, drone);

            CuiElementContainer container = UI.Container(DRONEGUI, UI.Color("FFF5E1", 0.16f), "0.4 0.95", "0.6 0.99", false, "Overlay");
            string uicolor = "#ffff33";
            if (target == null)
            {
                target = Lang("drone");
                uicolor = "#dddddd";
            }
            string label = target;
            UI.Label(ref container, DRONEGUI, UI.Color(uicolor, 1f), label, 12, "0 0", "1 1");

            if (monPos.ContainsKey(monName))
            {
                Vector3 point = monPos[monName];
                player.SendConsoleCommand("ddraw.text", 90, Color.green, point, $"<size=20>{monName}</size>");
            }
            CuiHelper.AddUi(player, container);
        }
        #endregion

        #region our_hooks
        private object OnDroneNavChange(DroneNav drone, string newdirection)
        {
            foreach (KeyValuePair<ulong, DroneNav> pgui in new Dictionary<ulong, DroneNav>(pguis))
            {
                if (pgui.Value == drone)
                {
                    BasePlayer pl = BasePlayer.FindByID(pgui.Key);
                    DroneGUI(pl, drone, Lang("heading", null, newdirection), newdirection);
                }
            }
            return null;
        }

        private object OnDroneNavArrived(BasePlayer player, DroneNav drone, string newdirection)
        {
            foreach (KeyValuePair<ulong, DroneNav> pgui in new Dictionary<ulong, DroneNav>(pguis))
            {
                if (pgui.Key == player.userID && pgui.Value == drone)
                {
                    DroneGUI(player, drone, Lang("arrived", null, newdirection), newdirection);
                }
            }
            return null;
        }
        #endregion

        #region config
        protected override void LoadDefaultConfig()
        {
            Puts("Creating new config file.");
            ConfigData config = new()
            {
                Options = new Options()
                {
                    minHeight = 40,
                    ActivationCode = 2112,
                    debug = false,
                    setServerDroneInAllCS = true,
                    setPlayerDroneInCS = true,
                    playerDronesImmortal = false,
                    useClans = false,
                    useFriends = false,
                    useTeams = false,
                    DisplayMapMarkersOnServerDrones = true,
                    SetMaxControlRange = true,
                    maxControlRange = 5000
                },
                Drones = new Dictionary<string, DroneInfo>(),
                Version = Version
            };
            config.Drones.Add("monument", new DroneInfo()
            {
                name = "MonumentDrone",
                start = "Airfield",
                spawn = true
            });
            config.Drones.Add("ring", new DroneInfo()
            {
                name = "RingDrone",
                start = "Road 0",
                spawn = true
            });
            config.Drones.Add("road", new DroneInfo()
            {
                name = "RoadDrone",
                start = "Road 1",
                spawn = false
            });

            SaveConfig(config);
        }

        private void LoadConfigVariables()
        {
            configData = Config.ReadObject<ConfigData>();

            if (configData.Options.maxControlRange == 0) configData.Options.maxControlRange = 5000;

            configData.Version = Version;
            SaveConfig(configData);
        }

        private void SaveConfig(ConfigData config)
        {
            Config.WriteObject(config, true);
        }

        public class ConfigData
        {
            public Options Options = new();
            public Dictionary<string, DroneInfo> Drones;
            public VersionNumber Version;
        }

        public class Options
        {
            public bool debug;
            public bool debugMovement;
            public float minHeight;
            public int ActivationCode;
            public bool setServerDroneInAllCS;
            public bool setPlayerDroneInCS;
            public bool playerDronesImmortal;
            public bool useFriends;
            public bool useClans;
            public bool useTeams;
            public bool useEconomics;
            public bool useServerRewards;
            public bool useBankSystem;
            public double droneCost;
            public bool DisplayMapMarkersOnServerDrones;
            public bool SetMaxControlRange;
            public float maxControlRange;
        }

        private void SaveData()
        {
            // Save the data file as we add/remove minicopters.Interface.GetMod().DataFileSystem.WriteObject(Name, drones);
        }

        private void LoadData()
        {
            drones = Interface.GetMod().DataFileSystem.ReadObject<Dictionary<string, uint>>(Name);
            if (drones == null)
            {
                drones = new Dictionary<string, uint>();
                SaveData();
            }
        }
        #endregion

        #region classes
        internal class DroneInfo
        {
            public string name;
            public bool spawn;
            public string start;
        }

        internal enum DroneType
        {
            None = 0,
            User = 1,
            Road = 2,
            Ring = 4,
            MonSingle = 8,
            MonAll = 16,
            Spy = 32
        }

        private class DroneNav : MonoBehaviour
        {
            public DroneType type;

            public Drone drone;
            public BasePlayer player;
            public ulong controllingUserId;
            public BasePlayer targetPlayer;
            public int buildingMask = LayerMask.GetMask("Construction", "Prevent Building", "Deployed", "World", "Terrain", "Tree", "Invisible", "Default");
            public int groundMask = LayerMask.GetMask("Construction", "Terrain", "World", "Water");
            public int terrainMask = LayerMask.GetMask("Terrain");

            public uint droneid;
            public ulong ownerid;
            public InputState input;

            public Road currentRoad;
            public string droneName;
            public string currentRoadName;
            public string currentMonument;
            public float currentMonSize;
            public Vector3 current;
            public Quaternion rotation;
            public Vector3 direction;
            public Vector3 target = Vector3.zero;
            public Vector3 last = Vector3.zero;
            public GameObject slop = new();

            public Stopwatch stuckTimer;

            public int whichPoint;
            public int totalPoints;

            public bool grounded = true;
            public bool started;
            public bool ending;
            public int markerdelay;
            public MapMarkerGenericRadius marker;

            private void Awake()
            {
                Instance.DoLog("Awake()");
                drone = GetComponent<Drone>();
                stuckTimer = new Stopwatch();
                stuckTimer.Stop();
                enabled = false;
            }

            private void OnDestroy()
            {
                if (drone?.IsDestroyed == false)
                {
                    Destroy(drone?.gameObject); drone?.Kill();
                }
                if (marker?.IsDestroyed == false)
                {
                    Destroy(marker?.gameObject); marker?.Kill();
                }
            }

            private void Start()
            {
                droneid = (uint)drone.net.ID.Value;
            }

            public void SetPlayerTarget(BasePlayer pl)
            {
                if (type != DroneType.Spy) return;
                targetPlayer = pl;
            }

            public string SetName(string name)
            {
                Instance.DoLog($"Trying to set drone '{drone.rcIdentifier}' name to '{name}'");
                int i = 1;
                string newName = name;
                while (RemoteControlEntity.IDInUse(newName))
                {
                    newName = name + i.ToString();
                    i++;
                    if (i > 10) break;
                }
                (drone as IRemoteControllable).UpdateIdentifier(newName, true);
                Instance.DoLog($"Set name to '{newName}'");
                droneName = newName;
                return newName;
            }

            public void SetType(DroneType type)
            {
                Instance.DoLog($"Set drone {drone.rcIdentifier} type to {type}");
                this.type = type;
            }

            public void SetRoad(string road, bool isringroad = false)
            {
                if (type == DroneType.None)
                {
                    if (isringroad)
                    {
                        SetType(DroneType.Ring);
                    }
                    else
                    {
                        SetType(DroneType.Road);
                    }
                }
                currentRoad = Instance.roads[road];
                currentRoadName = road;
                MinimizeRoadPoints();

                target = currentRoad.points[0];
                target.y += 10f;
                totalPoints = currentRoad.points.Count - 1;
            }

            private void MinimizeRoadPoints()
            {
                // Cut down on the jerkiness - we don't need no stinkin points!
                int cnt = currentRoad.points.Count;
                Instance.DoLog($"{drone.rcIdentifier} road points {cnt}");
                List<Vector3> newpts = new();

                int skip;
                if (cnt > 500) skip = 8;
                else if (cnt > 250) skip = 6;
                else if (cnt > 100) skip = 4;
                else if (cnt > 30) skip = 3;
                else if (cnt > 15) skip = 2;
                else return;

                int i = 0;
                foreach (Vector3 pts in currentRoad.points)
                {
                    if (i > skip)
                    {
                        newpts.Add(pts);
                        i = 0;
                    }
                    i++;
                }
                newpts.Add(currentRoad.points.Last());
                currentRoad.points = newpts;
                Instance.DoLog($"{drone.rcIdentifier} road points changed to {newpts.Count}");
            }

            private void UpdateMarker()
            {
                if (!Instance.configData.Options.DisplayMapMarkersOnServerDrones) return;
                if (type != DroneType.Road && type != DroneType.Ring && type != DroneType.MonAll && type != DroneType.MonSingle) return;
                markerdelay++;
                if (markerdelay > 50)
                {
                    markerdelay = 0;
                    if (marker != null)
                    {
                        marker.transform.position = drone.transform.position;
                        marker.SendUpdate();
                        marker.SendNetworkUpdateImmediate();
                        return;
                    }

                    Instance.DoLog($"Creating mapmarker for {droneName} at {drone.transform.position}");
                    marker = GameManager.server.CreateEntity("assets/prefabs/tools/map/genericradiusmarker.prefab", drone.transform.position) as MapMarkerGenericRadius;
                    if (marker != null)
                    {
                        marker.alpha = 0.8f;
                        marker.color1 = Color.black;
                        marker.color2 = Color.gray;
                        marker.name = droneName;
                        marker.radius = 0.15f;
                        marker.Spawn();
                        marker.SendUpdate();
                        marker.SendNetworkUpdateImmediate();
                    }
                }
            }

            private void Update()
            {
                drone._maxHealth = 1000;
                drone.SetHealth(1000);
                // You might be tempted to switch to FixedUpdate, but then the viewing player will take over flight...if (!enabled || drone.IsDead() || !drone.isSpawned)
                {
                    return;
                }

                switch (type)
                {
                    case DroneType.Ring:
                        if (currentRoad == null) return;
                        MoveToRoadPoint();
                        grounded = false;
                        break
// ... [Code preview truncated due to length. Full source in attached file] ...

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