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

FREE RaidNotes : 1.0.21 1.0.21

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;

using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;

using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

using UnityEngine;
using Rust;
using Facepunch;

namespace Oxide.Plugins
{
    [Info ("RaidNotes", "Calytic", "1.0.21", ResourceId = 2117)]
    [Description ("Broadcasts raid activity to chat & more")]
    public class RaidNotes : RustPlugin
    {
        #region Variables

        [PluginReference]
        Plugin Discord, Slack, Clans, LustyMap;

        DynamicConfigFile data;
        public static JsonSerializer SERIALIZER = new JsonSerializer ();
        public static JsonConverter [] CONVERTERS = new JsonConverter [] { new UnityVector3Converter (), new DateTimeConverter () };
        Dictionary<string, bool> _raidableCache = new Dictionary<string, bool> ();
        int blockLayer = UnityEngine.LayerMask.GetMask (new string [] { "Player (Server)" });
        static Dictionary<string, int> reverseItems = new Dictionary<string, int> ();
        static List<string> explosionRadiusPrefabs = new List<string> ();
        Dictionary<Raid, Timer> timers = new Dictionary<Raid, Timer> ();
        Dictionary<string, DateTime> detectionCooldowns = new Dictionary<string, DateTime> ();
        static Regex _htmlRegex = new Regex ("<.*?>", RegexOptions.Compiled);
        Color [] colors = new Color [7] { Color.blue, Color.cyan, Color.gray, Color.green, Color.magenta, Color.red, Color.yellow };

        float raidDuration = 300f;
        float raidDistance = 50f;
        float shoulderHeight = 0.45f;
        bool isNewSave = false;
        float detectionDuration = 60f;
        string slackType = "FancyMessage";
        int logHours = 12;

        bool trackExplosives = true;
        bool checkEntityDamage, checkEntityDeath, announceGlobal, printToLog = true;
        bool announceRaidStart, announceRaidEnd, announceToVictims, announceToSlack, announceToDiscord, announceToLustyMap, announceClan = false;
        string announcePrefixColor = "orange";
        string announceIcon;
        string announceNameColor = "lightblue";
        string announceClanColor = "#00eaff";
        string lustyMapIcon = "special";
        float lustyMapDuration = 10f;
        int detectionDistance = 50;
        float detectionCountdown = 1f;

        private Dictionary<string, object> weaponColors = new Dictionary<string, object> ()
        {
            { "0", "#666333" },
            { "498591726", "#666666" }
        };

        private Dictionary<string, object> gradeColors = new Dictionary<string, object> ()
        {
            { "Wood", "#a68b44" },
            { "Stone", "#a4a4a4" },
            { "Metal", "#9b5050" },
            { "TopTier", "#473131" }
        };

        private float announceDelay, announceRadius = 0f;

        internal int announceMinParticipants, announceMinWeapons, announceMinKills, announceMinDestroyed, announceMinMinutes = 0;

        List<string> prefabs = new List<string> ()
        {
            "door.hinged",
            "door.double.hinged",
            "window.bars",
            "floor.ladder.hatch",
            "floor.frame",
            "wall.frame",
            "shutter"
        };

        Dictionary<long, Raid> raids = new Dictionary<long, Raid> ();

        #endregion

        #region Classes

        public class AttackVector
        {
            public Vector3 start;
            public Vector3 end;
            public int weapon;
            public ulong victim;
            public ulong initiator;

            [JsonConstructor]
            public AttackVector (Vector3 start, Vector3 end, int weapon, ulong victim = 0, ulong initiator = 0)
            {
                this.start = start;
                this.end = end;
                this.weapon = weapon;
                this.victim = victim;
                this.initiator = initiator;
            }
        }

        public class Raid
        {
            public long start = DateTime.Now.ToBinary ();
            public long end = 0;
            public Vector3 firstDamage;
            public Vector3 lastDamage;
            public List<AttackVector> attackVector = new List<AttackVector> ();
            public List<AttackVector> killMap = new List<AttackVector> ();
            public ulong initiator;
            public ulong victim;
            public List<ulong> blockOwners = new List<ulong> ();
            public List<ulong> participants = new List<ulong> ();
            public int lastWeapon;
            public Dictionary<int, int> weapons = new Dictionary<int, int> ();

            public Dictionary<BuildingGrade.Enum, int> blocksDestroyed = new Dictionary<BuildingGrade.Enum, int> ();
            public Dictionary<string, int> entitiesDestroyed = new Dictionary<string, int> ();

            [JsonConstructor]
            public Raid (
                long start,
                long end,
                Vector3 firstDamage,
                Vector3 lastDamage,
                List<AttackVector> attackVector,
                ulong initiator,
                ulong victim,
                List<ulong> blockOwners,
                List<ulong> participants,
                int lastWeapon,
                Dictionary<int, int> weapons,
                List<AttackVector> killMap = null,
                Dictionary<BuildingGrade.Enum, int> blocksDestroyed = null,
                Dictionary<string, int> entitiesDestroyed = null
            )
            {
                this.start = start;
                this.end = end;
                this.firstDamage = firstDamage;
                this.lastDamage = lastDamage;
                this.attackVector = attackVector;
                this.initiator = initiator;
                this.victim = victim;
                this.blockOwners = blockOwners;
                this.participants = participants;
                this.lastWeapon = lastWeapon;
                this.weapons = weapons;
                if (killMap != null) {
                    this.killMap = killMap;
                }

                if (blocksDestroyed != null) {
                    this.blocksDestroyed = blocksDestroyed;
                }

                if (entitiesDestroyed != null) {
                    this.entitiesDestroyed = entitiesDestroyed;
                }
            }

            [JsonIgnore]
            internal AttackVector lastAttackVector = null;

            [JsonIgnore]
            RaidNotes plugin;

            [JsonIgnore]
            public bool Completed {
                get {
                    return end != 0;
                }
            }

            [JsonIgnore]
            public DateTime lastRefresh;

            [JsonIgnore]
            public IPlayer Initiator {
                get {
                    return plugin.covalence.Players.FindPlayerById (initiator.ToString ());
                }
            }

            [JsonIgnore]
            public IPlayer Victim {
                get {
                    return plugin.covalence.Players.FindPlayerById (victim.ToString ());
                }
            }

            [JsonIgnore]
            [JsonConverter (typeof (IsoDateTimeConverter))]
            public DateTime Start {
                get {
                    return DateTime.FromBinary (start);
                }
            }

            [JsonIgnore]
            [JsonConverter (typeof (IsoDateTimeConverter))]
            public DateTime End {
                get {
                    return DateTime.FromBinary (end);
                }
            }

            public Raid (RaidNotes plugin, ulong initiator, ulong victim, Vector3 firstDamage)
            {
                this.plugin = plugin;
                this.initiator = initiator;
                this.victim = victim;
                this.firstDamage = firstDamage;
            }

            [JsonIgnore]
            public double Hours {
                get {
                    if (!Completed) {
                        return 0;
                    }
                    var ts = DateTime.Now - End;
                    return ts.TotalHours;
                }
            }

            public bool HasHours (int hours)
            {
                if (Hours >= hours) {
                    return true;
                }

                return false;
            }

            public void Participate (BasePlayer player)
            {
                var behavior = player.gameObject.AddComponent<RaidBehavior> ();
                behavior.raid = this;
                if (!participants.Contains (player.userID)) {
                    participants.Add (player.userID);
                }
            }

            public bool IsAnnounced ()
            {
                if (participants.Count < plugin.announceMinParticipants)
                    return false;
                if (killMap.Count < plugin.announceMinKills)
                    return false;
                if (weapons.Count < plugin.announceMinWeapons)
                    return false;
                if ((entitiesDestroyed.Count + blocksDestroyed.Count) < plugin.announceMinDestroyed)
                    return false;

                var ts = End - Start;
                if (ts.TotalMinutes < plugin.announceMinMinutes)
                    return false;

                return true;
            }

            internal JObject Vector2JObject (Vector3 vector)
            {
                var obj = new JObject ();
                obj.Add ("x", vector.x);
                obj.Add ("y", vector.y);
                obj.Add ("z", vector.z);

                return obj;
            }

            public override string ToString ()
            {
                return ToJObject ().ToString ();
            }

            internal JObject ToJObject ()
            {
                var obj = new JObject ();

                obj ["start"] = Start.ToString ();
                obj ["end"] = End.ToString ();
                var explosions = new JObject ();
                explosions.Add ("first", Vector2JObject (firstDamage));
                explosions.Add ("last", Vector2JObject (lastDamage));
                obj ["explosions"] = explosions;

                obj ["initiator"] = initiator;
                obj ["victim"] = victim;

                JArray owners = new JArray ();
                foreach (var owner in blockOwners)
                    owners.Add (owner);

                obj ["owners"] = owners;

                JArray participantsData = new JArray ();
                foreach (var participant in participants)
                    participantsData.Add (participant);

                obj ["participants"] = participantsData;


                JObject weaponsData = new JObject ();
                foreach (var kvp in weapons)
                    weaponsData.Add (kvp.Key.ToString (), kvp.Value);

                obj ["weapons"] = weaponsData;

                obj ["attackvector"] = JArray.FromObject (attackVector, SERIALIZER);
                obj ["kills"] = JArray.FromObject (killMap, SERIALIZER);

                return obj;
            }

            internal void OnEnded ()
            {
                end = DateTime.Now.ToBinary ();
                Interface.CallHook ("OnRaidEnded", ToJObject ());
            }

            internal void OnStarted ()
            {
                Interface.CallHook ("OnRaidStarted", ToJObject ());
            }

            internal void Attack (AttackVector vector)
            {
                lastAttackVector = vector;
                attackVector.Add (vector);
            }

            internal void Kill (AttackVector vector)
            {
                killMap.Add (vector);
            }
        }

        public class RaidBehavior : MonoBehaviour
        {
            public BasePlayer player;
            internal Raid raid;


            void Awake ()
            {
                player = GetComponent<BasePlayer> ();
            }

            void OnDestroy ()
            {
                GameObject.Destroy (this);
            }
        }

        public class ExplosiveTracker : MonoBehaviour
        {
            public BaseEntity entity;
            public Vector3 lastValidPosition;

            public BasePlayer thrownBy;
            public Vector3 thrownFrom;

            void Awake ()
            {
                entity = GetComponent<BaseEntity> ();
                lastValidPosition = entity.transform.position;
            }

            void Update ()
            {
                if (Vector3.Distance (entity.transform.position, Vector3.zero) > 3) {
                    lastValidPosition = entity.transform.position;
                }
            }

            void OnDestroy ()
            {
                if (thrownBy == null)
                    return;
                var behavior = thrownBy.GetComponent<RaidBehavior> ();

                if (behavior != null && behavior.raid != null) {
                    int itemid;
                    if (reverseItems.TryGetValue (entity.PrefabName, out itemid))
                        behavior.raid.Attack (new AttackVector (thrownFrom, lastValidPosition, itemid, 0, thrownBy.userID));

                }
                GameObject.Destroy (this);
            }
        }

        enum AnnouncementType
        {
            Start = 1,
            End = 2,
            Slack_Start = 3,
            Slack_End = 4,
            Discord_Start = 5,
            Discord_End = 6
        }

        #endregion

        #region Initialization

        protected override void LoadDefaultConfig ()
        {
            PrintToConsole ("Creating new configuration");
            Config.Clear ();

            Config ["Settings", "trackEntityDamage"] = true;
            Config ["Settings", "trackEntityDeath"] = true;
            Config ["Settings", "trackExplosives"] = true;

            Config ["Raid", "distance"] = 50f;
            Config ["Raid", "duration"] = 300f;
            Config ["Raid", "logUpToHours"] = 3;
            Config ["Raid", "detectionDistance"] = 50;
            Config ["Raid", "detectionDuration"] = 60f;
            Config ["Raid", "detectionCountdownMinutes"] = 1f;

            Config ["AnnounceWhen", "raidEnds"] = false;
            Config ["AnnounceWhen", "raidStarts"] = false;
            Config ["AnnounceWhen", "minParticipants"] = 0;
            Config ["AnnounceWhen", "minWeapons"] = 0;
            Config ["AnnounceWhen", "minKills"] = 0;
            Config ["AnnounceWhen", "minMinutes"] = 0;

            Config ["AnnounceTo", "global"] = false;
            Config ["AnnounceTo", "clan"] = true;
            Config ["AnnounceTo", "victims"] = true;
            Config ["AnnounceTo", "slack"] = false;
            Config ["AnnounceTo", "discord"] = false;
            Config ["AnnounceTo", "lustymap"] = false;
            Config ["AnnounceTo", "log"] = true;

            Config ["Announcements", "icon"] = 0;
            Config ["Announcements", "prefixColor"] = "orange";
            Config ["Announcements", "nameColor"] = "lightblue";
            Config ["Announcements", "clanColor"] = "#00eaff";
            Config ["Announcements", "weaponColors"] = weaponColors;
            Config ["Announcements", "delay"] = 0f;
            Config ["Announcements", "radius"] = 0f;

            Config ["LustyMap", "icon"] = "special";
            Config ["LustyMap", "duration"] = 10f;

            Config ["Slack", "messageType"] = "FancyMessage";
        }

        void LoadMessages ()
        {
            lang.RegisterMessages (new Dictionary<string, string>
                {
                    { "Announce: Prefix", "Raid" },
                    { "Announce: Start", "{initiatorClan} {initiator} ({initiatorClanMates}) is raiding {victimClan} {victim} ({victimClanMates})" },
                    { "Announce: End", "{initiatorClan} {initiator} ({initiatorClanMates}) raided {victimClan} {victim} ({victimClanMates}) using {weaponList} destroying {destroyedList}" },
                    { "Announce: Slack Start", "{initiatorClan} {initiator} ({initiatorClanMates}) is raiding {victimClan} {victim} ({victimClanMates})" },
                    { "Announce: Slack End", "{initiatorClan} {initiator} ({initiatorClanMates}) raided {victimClan} {victim} ({victimClanMates}) with {weaponList} destroying {destroyedList}" },
                    { "Announce: Discord Start", "{initiatorClan} {initiator} ({initiatorClanMates}) is raiding {victimClan} {victim} ({victimClanMates})" },
                    { "Announce: Discord End", "{initiatorClan} {initiator} ({initiatorClanMates}) raided {victimClan} {victim} ({victimClanMates}) with {weaponList} destroying {destroyedList}" },
                    { "Denied: Permission", "You lack permission to do that" },
                    { "Raid: Found", "<size=15>Raid(s) found: {raidCount}</size>" },
                    { "Raid: Started", "Started: <b>{date}</b>" },
                    { "Raid: Ended", "Ended: <b>{date}</b>" },
                    { "Raid: Duration", "Duration: <b>{duration}</b> minutes" },
                    { "Raid: Initiator", "Initiator: <b>{initiatorName}</b> ({initiatorID})" },
                    { "Raid: PlayerList", "{listName}: <b>{list}</b>" },
                    { "Raid: Activity", "Raid" },
                    { "Target: Nothing", "Nothing" },
                    { "Cooldown: Seconds", "You are doing that too often, try again in a {0} seconds(s)." },
                    { "Cooldown: Minutes", "You are doing that too often, try again in a {0} minute(s)." },
                }, this);
        }

        void OnServerInitialized ()
        {
            LoadData ();
            LoadMessages ();

            foreach (JsonConverter converter in CONVERTERS) {
                SERIALIZER.Converters.Add (converter);
            }

            permission.RegisterPermission ("raidnotes.inspect", this);

            raidDistance = GetConfig ("Raid", "distance", 50f);
            raidDuration = GetConfig ("Raid", "duration", 300f);
            logHours = GetConfig ("Raid", "logUpToHours", 3);
            detectionDistance = GetConfig ("Raid", "detectionDistance", 50);
            detectionDuration = GetConfig ("Raid", "detectionDuration", 60f);
            detectionDuration = GetConfig ("Raid", "detectionCountdownMinutes", 1f);

            checkEntityDamage = GetConfig ("Settings", "hookEntityDamage", true);
            checkEntityDeath = GetConfig ("Settings", "hookEntityDeath", true);
            trackExplosives = GetConfig ("Settings", "trackExplosives", true);

            announceGlobal = GetConfig ("AnnounceTo", "global", false);
            announceClan = GetConfig ("AnnounceTo", "clan", true);
            announceToVictims = GetConfig ("AnnounceTo", "victims", true);
            announceToSlack = GetConfig ("AnnounceTo", "slack", false);
            announceToLustyMap = GetConfig ("AnnounceTo", "lustymap", false);
            announceToDiscord = GetConfig ("AnnounceTo", "discord", false);
            printToLog = GetConfig ("AnnounceTo", "log", true);

            announceRaidEnd = GetConfig ("AnnounceWhen", "raidEnds", false);
            announceRaidStart = GetConfig ("AnnounceWhen", "raidStarts", false);
            announceMinParticipants = GetConfig ("AnnounceWhen", "minParticipants", 0);
            announceMinWeapons = GetConfig ("AnnounceWhen", "minWeapons", 0);
            announceMinDestroyed = GetConfig ("AnnounceWhen", "minDestroyed", 0);
            announceMinKills = GetConfig ("AnnounceWhen", "minKills", 0);
            announceMinMinutes = GetConfig ("AnnounceWhen", "minMinutes", 0);

            announceIcon = GetConfig ("Announcements", "icon", "0");
            announcePrefixColor = GetConfig ("Announcements", "prefixColor", "orange");
            announceNameColor = GetConfig ("Announcements", "nameColor", "lightblue");
            announceClanColor = GetConfig ("Announcements", "clanColor", "#00eaff");
            weaponColors = GetConfig ("Announcements", "weaponColors", weaponColors);
            announceDelay = GetConfig ("Announcements", "delay", 0f);
            announceRadius = GetConfig ("Announcements", "radius", 0f);

            lustyMapIcon = GetConfig ("LustyMap", "icon", "special");
            lustyMapDuration = GetConfig ("LustyMap", "duration", 10f);

            slackType = GetConfig ("Slack", "messageType", "FancyMessage");

            if (announceToSlack && !Slack) {
                PrintWarning ("Slack plugin not found, please install http://oxidemod.org/plugins/slack.1952/");
                announceToSlack = false;
            }

            if (announceToDiscord && !Discord) {
                PrintWarning ("Discord plugin not found, please install http://oxidemod.org/plugins/discord.2149/");
                announceToDiscord = false;
            }

            if (announceToLustyMap && !LustyMap) {
                PrintWarning ("LustyMap plugin not found, please install http://oxidemod.org/plugins/lustymap.1333/");
            }

            if (logHours == 0) {
                Unsubscribe (nameof (OnServerSave));
            }

            if (!trackExplosives) {
                Unsubscribe (nameof (OnExplosiveThrown));
                Unsubscribe (nameof (OnRocketLaunched));
            }

            foreach (ItemDefinition def in ItemManager.GetItemDefinitions ()) {
                var modEntity = def.GetComponent<ItemModEntity> ();
                if (modEntity != null && modEntity.entityPrefab != null) {
                    var prefab = modEntity.entityPrefab.Get ();
                    var thrownWeapon = prefab.GetComponent<ThrownWeapon> ();

                    if (thrownWeapon != null && !string.IsNullOrEmpty (thrownWeapon.prefabToThrow.guid) && !reverseItems.ContainsKey (thrownWeapon.prefabToThrow.resourcePath)) {
                        reverseItems.Add (thrownWeapon.prefabToThrow.resourcePath, def.itemid);
                        continue;
                    }
                }

                var baseProjectile = def.GetComponent<ItemModProjectile> ();
                if (baseProjectile != null && !string.IsNullOrEmpty (baseProjectile.projectileObject.guid) && !reverseItems.ContainsKey (baseProjectile.projectileObject.resourcePath)) {
                    if (baseProjectile.projectileObject.resourcePath.Contains ("rocket") && !baseProjectile.projectileObject.resourcePath.Contains ("smoke")) {
                        explosionRadiusPrefabs.Add (baseProjectile.projectileObject.resourcePath);
                        reverseItems.Add (baseProjectile.projectileObject.resourcePath, def.itemid);
                    }
                }
            }

            if (announceClan) {
                if (!plugins.Exists ("Clans")) {
                    announceClan = false;
                    PrintWarning ("Clans plugin not found, please install http://oxidemod.org/plugins/clans.2087/");
                }
            }
        }

        protected void ReloadConfig ()
        {
            Config ["VERSION"] = Version.ToString ();
            ClearData ();
            PrintToConsole ("Upgrading configuration file");
            SaveConfig ();
        }

        void LoadData ()
        {
            if (logHours > 0) {
                data = Interface.Oxide.DataFileSystem.GetFile (nameof (RaidNotes));
                data.Settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                data.Settings.Converters = CONVERTERS;

                raids = data.ReadObject<Dictionary<long, Raid>> ();

                if (isNewSave) {
                    ClearData ();
                    isNewSave = false;
                }
            }

            if (Config ["VERSION"] == null) {
                // FOR COMPATIBILITY WITH INITIAL VERSIONS WITHOUT VERSIONED CONFIG
                ReloadConfig ();
            } else if (GetConfig<string> ("VERSION", "") != Version.ToString ()) {
                // ADDS NEW, IF ANY, CONFIGURATION OPTIONS
                ReloadConfig ();
            }
        }

        void SaveData (bool force = false)
        {
            if (raids.Count > 0 && !force) {
                var toRemove = raids.Where (pair => pair.Value.Hours > logHours).Select (pair => pair.Key).ToList ();

                foreach (var key in toRemove)
                    raids.Remove (key);
            }

            data.WriteObject<Dictionary<long, Raid>> (raids);
        }

        void ClearData ()
        {
            raids.Clear ();
            SaveData ();
        }

        void OnNewSave (string filename)
        {
            isNewSave = true;
        }

        void OnServerSave ()
        {
            SaveData ();
        }

        void Unload ()
        {
            var objects = GameObject.FindObjectsOfType (typeof (RaidBehavior));
            if (objects != null)
                foreach (var gameObj in objects)
                    GameObject.Destroy (gameObj);

            objects = GameObject.FindObjectsOfType (typeof (ExplosiveTracker));
            if (objects != null)
                foreach (var gameObj in objects)
                    GameObject.Destroy (gameObj);

            if (logHours > 0) {
                SaveData (true);
            }
        }

        #endregion

        #region Oxide Hooks

        void OnExplosiveThrown (BasePlayer player, BaseEntity entity)
        {
            if (player == null || entity.net == null)
                return;
            AddTracker (player, entity);
        }

        void OnRocketLaunched (BasePlayer player, BaseEntity entity)
        {
            if (player == null || entity.net == null || !reverseItems.ContainsKey (entity.PrefabName))
                return;

            AddTracker (player, entity);
        }

        List<uint> recentAttacks = new List<uint> ();

        private void OnEntityTakeDamage (BaseCombatEntity entity, HitInfo hitInfo)
        {
            if(entity == null)
                return;
            if (!checkEntityDamage)
                return;
            if (hitInfo == null ||
                hitInfo.Initiator == null ||
                hitInfo.WeaponPrefab == null ||
                !IsEntityRaidable (entity))
                return;

            var prefabName = hitInfo.WeaponPrefab.PrefabName;

            if (explosionRadiusPrefabs.Contains (prefabName) && hitInfo.Initiator.net != null) {
                if (recentAttacks.Contains (hitInfo.Initiator.net.ID)) {
                    return;
                } else {
                    recentAttacks.Add (hitInfo.Initiator.net.ID);
                }

                Interface.Oxide.NextTick (delegate () {
                    if (recentAttacks.Contains (hitInfo.Initiator.net.ID)) {
                        recentAttacks.Remove (hitInfo.Initiator.net.ID);
                    }
                });
            }

            int itemUsed;
            if (!reverseItems.TryGetValue (prefabName, out itemUsed))
                return;

            if(hitInfo.damageTypes != null) {
                var majorityDamageType = hitInfo.damageTypes.GetMajorityDamageType ();
    
                switch (majorityDamageType) {
                case DamageType.Explosion:
                case DamageType.Heat:
                    StructureAttack (entity, hitInfo.Initiator, itemUsed);
                    break;
                }
            }
        }

        private void OnEntityDeath (BaseCombatEntity entity, HitInfo hitInfo)
        {
            if (!checkEntityDeath || hitInfo == null || hitInfo.WeaponPrefab == null || hitInfo.Initiator == null || !(hitInfo.Initiator is BasePlayer))
                return;
            if (IsEntityRaidable (entity)) {
                var majorityDamageType = hitInfo.damageTypes.GetMajorityDamageType ();

                var prefabName = hitInfo.WeaponPrefab.PrefabName;
                int itemUsed;
                if (reverseItems.TryGetValue (prefabName, out itemUsed)) {
                    switch (majorityDamageType) {
                    case DamageType.Explosion:
                    case DamageType.Heat:
                        StructureAttack (entity, hitInfo.Initiator as BasePlayer, itemUsed, true);
                        break;
                    }
                }
            } else if (entity is BasePlayer)
                RegisterKill (entity as BasePlayer, hitInfo.Initiator as BasePlayer);

        }

        #endregion

        #region Commands

        [ConsoleCommand ("raids.wipe")]
        private void ccRaidsWipe (ConsoleSystem.Arg arg)
        {
            if (arg.Connection == null || (arg.Connection != null && arg.Connection.authLevel > 0)) {
                ClearData ();

                SendReply (arg, "Data wiped");
                return;
            }

            SendReply (arg, GetMsg ("Denied: Permission"));
        }

        [ChatCommand ("inspect")]
        private void cmdInspect (BasePlayer player, string command, string [] args)
        {
            var permission = HasPerm (player, "raidnotes.inspect");
            if (permission || (!permission && player.net.connection.authLevel > 0)) {
                if (!CheckCooldown (player))
                    return;
                else
                    PlayerCooldown (player);

                SendRaids (player, args);
                return;
            }

            SendReply (player, GetMsg ("Denied: Permission", player));
        }

        #endregion

        #region Core Methods

        void PlayerCooldown (BasePlayer player)
        {
            if (player.IsAdmin)
                return;

            if (detectionCooldowns.ContainsKey (player.UserIDString))
                detectionCooldowns.Remove (player.UserIDString);

            detectionCooldowns.Add (player.UserIDString, DateTime.Now);
        }

        bool CheckCooldown (BasePlayer player)
        {
            if (detectionCountdown > 0) {
                DateTime startTime;
                if (detectionCooldowns.TryGetValue (player.UserIDString, out startTime)) {
                    var endTime = DateTime.Now;

                    var span = endTime.Subtract (startTime);
                    if (span.TotalMinutes > 0 && span.TotalMinutes < Convert.ToDouble (detectionCountdown)) {
                        var timeleft = System.Math.Round (Convert.ToDouble (detectionCountdown) - span.TotalMinutes, 2);
                        if (timeleft < 1) {
                            var timelefts = System.Math.Round ((Convert.ToDouble (detectionCountdown) * 60) - span.TotalSeconds);
                            SendReply (player, string.Format (GetMsg ("Cooldown: Seconds", player), timelefts.ToString ()));
                        } else
                            SendReply (player, string.Format (GetMsg ("Cooldown: Minutes", player), System.Math.Round (timeleft).ToString ()));

                        return false;
                    } else
                        detectionCooldowns.Remove (player.UserIDString);

                }
            }

            return true;
        }

        void AddTracker (BasePlayer player, BaseEntity entity)
        {
            var tracker = entity.gameObject.AddComponent<ExplosiveTracker> ();
            tracker.thrownBy = player;
            tracker.thrownFrom = player.transform.position;
            tracker.thrownFrom.y += player.GetHeight () * shoulderHeight;
        }

        Vector3 Track (BaseEntity initiator, BaseEntity entity)
        {
            var fromPos = Vector3.zero;
            var tracker = trackExplosives ? initiator.gameObject.GetComponent<ExplosiveTracker> () : null;
            if (tracker != null)
                fromPos = tracker.thrownFrom;
            else
                fromPos = initiator.transform.position;

            return fromPos;
        }

        List<Raid> GetRaids (BasePlayer player, string [] args)
        {
            var defaultDistance = detectionDistance;
            if (args != null && args.Length == 1)
                int.TryParse (args [0], out defaultDistance);

            if (defaultDistance > detectionDistance)
                defaultDistance = detectionDistance;

            return raids.Where (pair => Vector3.Distance (pair.Value.firstDamage, player.transform.position) <= defaultDistance).Select (pair => pair.Value).ToList ();
        }

        void SendRaids (BasePlayer player, string [] args)
        {
            if (player.net.connection == null)
                return;

            var nearbyRaids = GetRaids (player, args);

            if (nearbyRaids.Count > 0) {
                int found = 0;
                var sbs = new List<StringBuilder> ();
                foreach (var raid in nearbyRaids) {
                    var sb = new StringBuilder ();
                    if (SendRaid (player, raid, sb, found)) {
                        found++;
                        sbs.Add (sb);
                    }
                }

                if (found > 0) {
                    SendReply (player, Format (GetMsg ("Raid: Found", player), raidCount => found));
                    foreach (var sb in sbs) {
                        SendReply (player, sb.ToString ());
                    }
                    return;
                }
            }

            SendReply (player, "No raids found");
        }

        public string ToHex (Color c)
        {
            return string.Format ("#{0:X2}{1:X2}{2:X2}", ToByte (c.r), ToByte (c.g), ToByte (c.b));
        }

        private byte ToByte (float f)
        {
            f = Mathf.Clamp01 (f);
            return (byte)(f * 255);
        }

        bool SendRaid (BasePlayer player, Raid raid, StringBuilder sb, int found = 0)
        {
            var uiduration = detectionDuration * 60;
            var admin = false;
            if (player.net.connection.authLevel > 0)
                admin = true;

            var randomColor = colors [UnityEngine.Random.Range (0, colors.Length - 1)];
            var validAttack = false;
            foreach (AttackVector attack in raid.attackVector) {
                if (!admin && attack.victim != player.userID)
                    continue;

                validAttack = true;
                var weapName = string.Empty;
                var def = ItemManager.FindItemDefinition (attack.weapon);
                if (def is ItemDefinition)
                    weapName = def.displayName.english;

                player.SendConsoleCommand ("ddraw.arrow", uiduration, randomColor, attack.start, attack.end, 0.2);

                if (!string.IsNullOrEmpty (weapName))
                    player.SendConsoleCommand ("ddraw.text", uiduration, GetWeaponColor (attack.weapon), attack.start, weapName);
            }

            foreach (AttackVector kill in raid.killMap) {
                if (!admin && kill.victim != player.userID)
                    continue;

                validAttack = true;

                player.SendConsoleCommand ("ddraw.arrow", uiduration, randomColor, kill.start, kill.end, 0.2);
                player.SendConsoleCommand ("ddraw.sphere", uiduration, Color.red, kill.end, 0.5f);

                var victimPlayer = covalence.Players.FindPlayerById (kill.victim.ToString ());
                var initiatorPlayer = covalence.Players.FindPlayerById (kill.initiator.ToString ());

                if (victimPlayer is IPlayer) {
                    player.SendConsoleCommand ("ddraw.text", uiduration, Color.red, kill.end + Vector3.up, victimPlayer.Name);
                }

                if (initiatorPlayer is IPlayer) {
                    player.SendConsoleCommand ("ddraw.text", uiduration, Color.red, kill.start + Vector3.up, initiatorPlayer.Name);
                }
            }

            if (validAttack) {
                player.SendConsoleCommand ("ddraw.arrow", uiduration, Color.green, raid.firstDamage + new Vector3 (0, 5, 0), raid.firstDamage, 0.2);
                if (raid.lastDamage != Vector3.zero) {
                    player.SendConsoleCommand ("ddraw.arrow", uiduration, Color.red, raid.lastDamage + new Vector3 (0, 5, 0), raid.lastDamage, 0.2);
                }
                sb.Append (Format ("<color={color}><size=17>#{count}</size></color> + ", count => (found + 1), color => ToHex (randomColor)));
                var start = (raid.Start != null) ? raid.Start.ToString () : "N/A";
                sb.AppendLine (Format (GetMsg ("Raid: Started"), date => start));
                if (raid.Completed) {
                    TimeSpan ts = raid.End - raid.Start;
                    var end = (raid.End != null) ? raid.End.ToString () : "N/A";
                    sb.Append ("   |- ").AppendLine (Format (GetMsg ("Raid: Duration"), duration => Math.Round (ts.TotalMinutes, 2)));
                    sb.Append ("   |- ").AppendLine (Format (GetMsg ("Raid: Ended"), date => end));
                }

                var initiator = covalence.Players.FindPlayerById (raid.initiator.ToString ());
                if (initiator != null) {
                    sb.Append ("   |- ").AppendLine (Format (GetMsg ("Raid: Initiator"), initiatorName => initiator.Name, initiatorID => initiator.Id));
                }

                if (raid.blockOwners.Count > 0) {
                    var victimList = string.Join (", ", raid.blockOwners.Select (x => covalence.Players.FindPlayerById (x.ToString ()).Name).ToArray ());
                    sb.Append ("   |- ").AppendLine (Format (GetMsg ("Raid: PlayerList"), listName => "Property Of", list => victimList));
                }

                if (raid.participants.Count > 0) {
                    var participantList = string.Join (", ", raid.blockOwners.Where (x => !raid.blockOwners.Contains (x)).Select (x => covalence.Players.FindPlayerById (x.ToString ()).Name).ToArray ());
                    if (!string.IsNullOrEmpty (participantList.Trim ())) {
                        sb.Append ("   |- ").AppendLine (Format (GetMsg ("Raid: PlayerList"), listName => "Perpetrators", list => participantList));
                    }
                }

                if (raid.weapons.Count > 0)
                    sb.Append ("   |- ").AppendLine (GetWeaponList (raid));


                if (raid.blocksDestroyed.Count > 0 || raid.entitiesDestroyed.Count > 0)
                    sb.Append ("   |- ").AppendLine (GetDestroyedList (raid));


                return true;
            }

            return false;
        }

        void RegisterKill (BasePlayer player, BasePlayer attacker)
        {
            var behavior = player.GetComponent<RaidBehavior> ();
            if (behavior != null && behavior.raid != null) {
                var activeItem = attacker.GetActiveItem ();
                var itemid = 0;
                if (activeItem != null)
                    itemid = activeItem.info.itemid;

                behavior.raid.Kill (new AttackVector (attacker.transform.position, player.transform.position, itemid, player.userID, attacker.userID));

                GameObject.Destroy (behavior);
            }
        }

        void StructureAttack (BaseEntity targetEntity, BaseEntity sourceEntity, int weapon, bool destroy = false)
        {
            BasePlayer source;

            if (sourceEntity.ToPlayer () is BasePlayer)
                source = sourceEntity.ToPlayer ();
            else {
                var ownerID = (sourceEntity.OwnerID == 0) ? sourceEntity.OwnerID.ToString () : string.Empty;
                if (!string.IsNullOrEmpty (ownerID))
                    source = BasePlayer.Find (ownerID);
                else
                    return;
            }

            if (source == null)
                return;

            var targetID = targetEntity.OwnerID.IsSteamId () ? targetEntity.OwnerID.ToString () : string.Empty;

            if (!string.IsNullOrEmpty (targetID) && targetID != source.UserIDString) {
                var targetIDUint = Convert.ToUInt64 (targetID);
                /* var target = covalence.Players.FindPlayerById (targetID);*/
                Raid raid;
                var raidFound = TryGetRaid (source, targetIDUint, targetEntity.transform.position, out raid);
                raid.lastWeapon = weapon;


                if (raid.blockOwners.Count == 0)
                    raid.victim = targetIDUint;

                if (!raid.blockOwners.Contains (targetIDUint))
                    raid.blockOwners.Add (targetIDUint);

                if (destroy) {
                    if (targetEntity is BuildingBlock) {
                        var grade = ((BuildingBlock)targetEntity).grade;
                        if (raid.blocksDestroyed.ContainsKey (grade))
                            raid.blocksDestroyed [grade]++;
                        else
                            raid.blocksDestroyed.Add (grade, 1);
                    } else if (targetEntity is BaseCombatEntity) {
                        var name = targetEntity.ShortPrefabName;
                        if (raid.entitiesDestroyed.ContainsKey (name))
                            raid.entitiesDestroyed [name]++;
                        else
                            raid.entitiesDestroyed.Add (name, 1);
                    }
                } else {
                    if (raid.weapons.ContainsKey (weapon))
                        raid.weapons [weapon]++;
                    else
                        raid.weapons.Add (weapon, 1);
                }

                if (raid.lastAttackVector != null)
                    raid.lastAttackVector.victim = targetIDUint;

                raid.lastDamage = targetEntity.transform.position;

                if (!raidFound && announceRaidStart) {
                    AnnounceRaidMsg (raid, AnnouncementType.Start);
                    if (announceToSlack)
                        AnnounceRaidMsg (raid, AnnouncementType.Slack_Start);

                    if (announceToDiscord)
                        AnnounceRaidMsg (raid, AnnouncementType.Discord_Start);
                }
            }
        }

        Raid FindRaid (Vector3 position, out List<BasePlayer> nearbyTargets)
        {
            Raid existingRaid = null;

            nearbyTargets = GetNearbyPlayers (position);

            if (existingRaid == null && nearbyTargets.Count > 0) {
                foreach (var nearbyTarget in nearbyTargets) {
                    var behavior = nearbyTarget.GetComponent<RaidBehavior> ();
                    if (behavior != null && behavior.raid != null && existingRaid != behavior.raid && !behavior.raid.Completed) {
                        existingRaid = behavior.raid;
                        break;
                    }
                }
            }

            return existingRaid;
        }

        List<BasePlayer> GetNearbyPlayers (Vector3 position)
        {
            var nearbyTargets = Pool.GetList<BasePlayer> ();
            Vis.Entities<BasePlayer> (position, raidDistance, nearbyTargets, blockLayer);
            nearbyTargets = Sort (position, nearbyTargets);

            return nearbyTargets;
        }

        bool TryGetRaid (BasePlayer source, ulong victim, Vector3 position, out Raid raid)
        {
            Raid existingRaid = null;
            List<BasePlayer> nearbyTargets = null;
            var sourceBehavior = source.GetComponent<RaidBehavior> ();

            if (sourceBehavior != null && sourceBehavior.raid != null && !sourceBehavior.raid.Completed)
                existingRaid = sourceBehavior.raid;
            else
                existingRaid = FindRaid (position, out nearbyTargets);

            bool found = true;

            if (existingRaid == null || (existingRaid != null && existingRaid.Completed)) {
                found = false;
                var newRaid = StartRaid (source, victim, position);
                existingRaid = newRaid;

                if (nearbyTargets == null)
                    nearbyTargets = GetNearbyPlayers (position);

                foreach (var nearbyTarget in nearbyTargets) {
                    var behavior = nearbyTarget.GetComponent<RaidBehavior> ();
                    if (behavior == null || (behavior != null && behavior.raid == null)) {
                        existingRaid.Participate (nearbyTarget);
                    }
                }
            } else if (sourceBehavior == null || (sourceBehavior != null && sourceBehavior.raid == null))
                existingRaid.Participate (source);


            if (nearbyTargets != null)
                Pool.FreeList<BasePlayer> (ref nearbyTargets);

            RefreshRaid (existingRaid);
            raid = existingRaid;
            return found;
        }

        public Raid StartRaid (BasePlayer source, ulong victim, Vector3 position)
        {
            var raid = new Raid (this, source.userID, victim, position);

            RefreshRaid (raid);

            raid.Participate (source);
            raid.OnStarted ();

            return raid;
        }

        private string GetAnnouncementMsg (AnnouncementType type)
        {
            var msgName = string.Empty;
            switch (type) {
            case AnnouncementType.Start:
                msgName = "Announce: Start";
                break;
            case AnnouncementType.End:
                msgName = "Announce: End";
                break;
            case AnnouncementType.Slack_Start:
                msgName = "Announce: Slack Start";
                break;
            case AnnouncementType.Slack_End:
                msgName = "Announce: Slack End";
                break;
            case AnnouncementType.Discord_Start:
                msgName = "Announce: Discord Start";
                break;
            case AnnouncementType.Discord_End:
                msgName = "Announce: Discord End";
                break;
            }

            if (!string.IsNullOrEmpty (msgName))
                return GetMsg (msgName);

            return msgName;
        }

        public void CheckRaid (Raid raid)
        {
            var ts = DateTime.Now - raid.lastRefresh;
            if (ts.TotalSeconds > raidDuration) {
                if (announceToLustyMap && lustyMapDuration > 0)
                    LustyMap?.Call ("RemoveMarker", raid.start.ToString ());

                StopRaid (raid);
                if (announceRaidEnd) {
                    AnnounceRaidMsg (raid, AnnouncementType.End);
                    if (announceToSlack)
                        AnnounceRaidMsg (raid, AnnouncementType.Slack_End);

                    if (announceToDiscord)
                        AnnounceRaidMsg (raid, AnnouncementType.Discord_End);

                }
            }
        }

        void AnnounceRaidMsg (Raid raid, AnnouncementType type)
        {
            if (announceDelay > 0)
                timer.In (announceDelay, delegate () {
                    AnnounceRaid (raid, type);
                });
            else
                AnnounceRaid (raid, type);
        }

        public void RefreshRaid (Raid raid)
        {

            raid.lastRefresh = DateTime.Now;
            Timer t;

            if (timers.TryGetValue (raid, out t)) {
                if (t.Destroyed) {
                    timers.Add (raid, t = timer.Repeat (raidDuration, 0, () => CheckRaid (raid)));
                }
            } else {
                timers.Add (raid, t = timer.Repeat (raidDuration, 0, () => CheckRaid (raid)));
            }
        }

        public void DestroyTimer (Raid raid)
        {
            Timer raidTimer;
            if (timers.TryGetValue (raid, out raidTimer)) {
                if (!raidTimer.Destroyed)
                    raidTimer.Destroy ();

                tim
// ... [Code preview truncated due to length. Full source in attached file] ...

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