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

FREE NextGenPVE : 1.8.3 1.8.3

Нет прав для скачивания
C#:
#region License (GPL v2)
/*
    NextGenPVE - Prevent damage to players and objects in a Rust PVE environment
    Copyright (c) 2020 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 License (GPL v2)
// Reference: System.Data.SQLite
// Reference: System.Net.Http
using Facepunch;
using HarmonyLib;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("NextGen PVE", "RFC1920", "1.8.3")]
    [Description("Prevent damage to players and objects in a PVE environment")]
    internal class NextGenPVE : RustPlugin {
#region vars
        // Ruleset to multiple zones
        private Dictionary<string, NextGenPVEZoneMap> ngpvezonemaps = new();
        private Dictionary<int, NGPVE_Schedule> ngpveschedule = new();
        private Dictionary<string, long> lastConnected = new();
        private Dictionary<ulong, DateTime> playerShotHeli = new();
        private const string permNextGenPVEUse = "nextgenpve.use";
        private const string permNextGenPVEAdmin = "nextgenpve.admin";
        private const string permNextGenPVEGod = "nextgenpve.god";
        private ConfigData configData;
        private SQLiteConnection sqlConnection;
        private string connStr;
        private bool newsave;
        public Dictionary<string, List<string>> steamFriends = new();
        private List<ulong> isopen = new();
        private readonly string BannerColor = "Grey";
        private string TextColor = "Red";
        [PluginReference]
        private readonly Plugin ZoneManager, Humanoids, HumanNPC, Friends, Clans, GUIAnnouncements, NREHook, RustIO;
        private readonly string logfilename = "log";
        private bool dolog;
        private bool onfoundnre;
        private bool enabled;
        private bool inPurge;
        private bool purgeLast;
        private Timer scheduleTimer;
        private Timer heliTimer;
        private const string NGPVEPLUGINS = "nextgenpve.plugins";
        private const string NGPVERULELIST = "nextgenpve.rulelist";
        private const string NGPVEEDITRULESET = "nextgenpve.ruleseteditor";
        private const string NGPVERULEEDIT = "nextgenpve.ruleeditor";
        private const string NGPVEENTEDIT = "nextgenpve.enteditor";
        private const string NGPVEVALUEEDIT = "nextgenpve.value";
        private const string NGPVESCHEDULEEDIT = "nextgenpve.schedule";
        private const string NGPVEENTSELECT = "nextgenpve.selectent";
        private const string NGPVENPCSELECT = "nextgenpve.selectnpc";
        private const string NGPVERULESELECT = "nextgenpve.selectrule";
        private const string NGPVERULEEXCLUSIONS = "nextgenpve.exclusions";
        private const string NGPVECUSTOMSELECT = "nextgenpve.customsel";
#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.Message(Lang(key, player.Id, args));
        private void LMessage(IPlayer player, string key, params object[] args) => player.Reply(Lang(key, player.Id, args));
#endregion
#region init
        private void Init() {
            DynamicConfigFile dataFile = Interface.GetMod().DataFileSystem.GetDatafile(Name + "/nextgenpve");
            dataFile.Save();
            connStr = "Data Source=" + Regex.Escape(Path.Combine(Interface.GetMod().DataDirectory, Name)) + Path.DirectorySeparatorChar + "nextgenpve.db";
            LoadConfigVariables();
            AddCovalenceCommand("pveupdate", "CmdUpdateEnts");
            AddCovalenceCommand("pvebackup", "CmdNextGenPVEbackup");
            AddCovalenceCommand("pverule", "CmdNextGenPVEGUI");
            AddCovalenceCommand("pveenable", "CmdNextGenPVEenable");
            AddCovalenceCommand("pvedrop", "CmdNextGenPVEDrop");
            AddCovalenceCommand("pvelog", "CmdNextGenPVElog");
            AddCovalenceCommand("pvedebug", "CmdNextGenPVEDebug");
            AddCovalenceCommand("pvereload", "CmdNextGenPVEReadCfg");
            permission.RegisterPermission(permNextGenPVEUse, this);
            permission.RegisterPermission(permNextGenPVEAdmin, this);
            permission.RegisterPermission(permNextGenPVEGod, this);
        }
        private void OnServerInitialized() {
            ConsoleSystem.Run(ConsoleSystem.Option.Server.FromServer(), "server.pve 0");
            sqlConnection = new SQLiteConnection(connStr);
            sqlConnection.Open();
            if (NREHook && configData.Options.enableDebugOnErrors) {
                Puts("NREHook is installed.  Will enable debugging if NRE is fired.");
            }
            LoadData();
            if (newsave) {
                Puts("Wipe detected.  Clearing zone maps and setting purge schedule, if enabled.");
                ngpvezonemaps = new Dictionary<string, NextGenPVEZoneMap>();
                newsave = false;
                NextTick(() => {
                    NewPurgeSchedule();
                    SaveData();
                    UpdateEnts();
                }
                );
            }
            const string query = "CREATE INDEX IF NOT EXISTS ruleset_name_idx ON ngpve_rulesets (name, zone, damage, enabled, exception);" + "CREATE INDEX IF NOT EXISTS rules_idx ON ngpve_rules (name, source, target);" + "CREATE INDEX IF NOT EXISTS ent_idx ON ngpve_entities (name, type);REINDEX;";
            using (SQLiteCommand us = new(query, sqlConnection)) {
                us.ExecuteNonQuery();
            }
            if (configData.Options.useSteam && configData.Options.steamApiKey?.Length > 0) {
                foreach (BasePlayer player in BasePlayer.activePlayerList) {
                    GetSteamFriends(player);
                }
            }
            enabled = true;
            if (configData.Options.useSchedule) RunSchedule(true);
            HeliTimer();
        }
        private void HeliTimer() {
            if (!configData.Options.UseHeliTimerToDetectPlayer) return;
            if (configData.Options.debug) Puts("Checking playerShotHeli");
            float heliminutes = configData.Options.heliTimerMinutes > 0 ? configData.Options.heliTimerMinutes : 5;
            heliTimer = timer.Once(60, () => HeliTimer());
            if (playerShotHeli.Count == 0) {
                return;
            }
            foreach (KeyValuePair<ulong, DateTime> ht in new Dictionary<ulong, DateTime>(playerShotHeli)) {
                if (configData.Options.debug) Puts($"Player {ht.Key} found in playerShotHeli.");
                if (ht.Value.AddMinutes(heliminutes) >= DateTime.Now) {
                    playerShotHeli.Remove(ht.Key);
                    if (configData.Options.debug) Puts($"Player {ht.Key} removed from playerShotHeli list.");
                }
            }
        }
        private void OnNewSave() => newsave = true;
        private void OnPlayerConnected(BasePlayer player) {
            if (configData.Options.useSteam && configData.Options.steamApiKey?.Length > 0) GetSteamFriends(player);
        }
        private void OnUserConnected(IPlayer player) => OnUserDisconnected(player);
        private void OnUserDisconnected(IPlayer player) {
            if (player == null) return;
            try {
                if (!player.Id.IsSteamId()) return;
            }
            catch {
                return;
            }
            lastConnected.TryGetValue(player?.Id, out long lc);
            if (lc > 0) {
                lastConnected[player?.Id] = ToEpochTime(DateTime.UtcNow);
            }
            else {
                lastConnected.Add(player?.Id, ToEpochTime(DateTime.UtcNow));
            }
            SaveData();
        }
        private object OnServerCommand(ConsoleSystem.Arg arg) {
            if (arg != null) {
                try {
                    string[] newargs = new string[arg.Args.Length];
                    foreach (StringView x in arg.Args) {
                        _ = newargs.AddToArray(x.ToString());
                    }
                    return OnPlayerCommand(arg?.Player(), arg.cmd.FullName, newargs);
                }
                catch {
                }
            }
            return null;
        }
        private object OnPlayerCommand(BasePlayer player, string command, string[] args) {
            if (player != null) {
                if (isopen.Contains(player.userID) && !command.StartsWith("pve")) {
                    Puts($"Player tried to run command while gui open: {command}");
                    return true;
                }
            }
            return null;
        }
        private void UpdateEnts() {
            // Populate the entities table with any new entities (Typically only at wipe but can be run manually via pveupdate.)
            // All new ents are added as unknown for manual recategorization (except those containing 'npc').
            Puts("Finding new entity types...");
            List<string> names = Pool.Get<List<string>>();
            foreach (UnityEngine.Object obj in Resources.FindObjectsOfTypeAll(new BaseCombatEntity().GetType())) {
                string objname = obj?.GetType().ToString();
                if (string.IsNullOrEmpty(objname)) continue;
                if (objname.Contains("Entity")) continue;
                if (names.Contains(objname)) continue;
                // Saves 20-30 seconds of processing time.
                string category = objname.Contains("npc", CompareOptions.OrdinalIgnoreCase) ? "npc" : "unknown";
                names.Add(objname);
                //Puts($"Checking {objname}");
                using SQLiteConnection c = new(connStr);
                c.Open();
                string query = $"INSERT INTO ngpve_entities (name, type) SELECT '{category}', '{objname}' WHERE NOT EXISTS (SELECT * FROM ngpve_entities WHERE type='{objname}')";
                using SQLiteCommand us = new(query, c);
                if (us.ExecuteNonQuery() > 0) {
                    query = $"UPDATE ngpve_entities SET time=CURRENT_TIMESTAMP WHERE name='{category}' AND type='{objname}'";
                    using SQLiteCommand ct = new(query, c);
                    ct.ExecuteNonQuery();
                    Puts($"Added {objname} as {category}.");
                }
            }
            foreach (UnityEngine.Object obj in Resources.FindObjectsOfTypeAll(new GrenadeWeapon().GetType())) {
                string objname = obj?.GetType().ToString();
                if (string.IsNullOrEmpty(objname)) continue;
                if (objname.Contains("Entity")) continue;
                if (names.Contains(objname)) continue;
                // Saves 20-30 seconds of processing time.
                string category = objname.Contains("npc", CompareOptions.OrdinalIgnoreCase) ? "npc" : "grenade";
                names.Add(objname);
                using SQLiteConnection c = new(connStr);
                c.Open();
                string query = $"INSERT INTO ngpve_entities (name, type) SELECT '{category}', '{objname}' WHERE NOT EXISTS (SELECT * FROM ngpve_entities WHERE type='{objname}')";
                using SQLiteCommand us = new(query, c);
                if (us.ExecuteNonQuery() > 0) {
                    query = $"UPDATE ngpve_entities SET time=CURRENT_TIMESTAMP WHERE name={category} AND type='{objname}'";
                    using SQLiteCommand ct = new(query, c);
                    ct.ExecuteNonQuery();
                    Puts($"Added {objname} as {category}.");
                }
            }
            Pool.FreeUnmanaged(ref names);
            Puts("Done!");
            CleanupEnts();
        }
        private void CleanupEnts() {
            // Find things defined as unknown but also in another category and delete the unknowns.
            // name is category, type is ObjectName
            using SQLiteConnection c = new(connStr);
            c.Open();
            List<string> types = Pool.Get<List<string>>();
            List<string> toremove = Pool.Get<List<string>>();
            using (SQLiteCommand us = new("SELECT name, type FROM ngpve_entities ORDER BY name", c)) using (SQLiteDataReader rentry = us.ExecuteReader()) {
                while (rentry.Read()) {
                    string name = rentry.GetString(0);
                    string type = rentry.GetString(1);
                    if (types.Contains(type) && name == "unknown") {
                        toremove.Add(type);
                        continue;
                    }
                    if (!types.Contains(type)) types.Add(type);
                }
            }
            if (toremove.Count > 0) {
                Puts("Cleaning up entity types...");
                string q = $"DELETE FROM ngpve_entities WHERE name='unknown' AND type in ('{string.Join("','", toremove)}')";
                using (SQLiteCommand us = new(q, c)) {
                    us.ExecuteNonQuery();
                }
                Puts("Done!");
            }
            Pool.FreeUnmanaged(ref types);
            Pool.FreeUnmanaged(ref toremove);
        }
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                ["notauthorized"]
                = "You don't have permission to use this command.", ["zonemanagerreq"] = "ZoneManager required for handling multiple active rulesets.", ["nextgenpverulesets"] = "NextGenPVE Rulesets", ["nextgenpverulesetsf"] = "NextGenPVE Rulesets and Flags", ["rulesets"] = "Rulesets", ["pveenabled"] = "PVE Enabled for {0} ruleset.", ["pvedisabled"] = "PVE Disabled for {0} ruleset.", ["nextgenpveruleset"] = "NextGenPVE Ruleset", ["nextgenpverule"] = "NextGenPVE Rule", ["nextgenpveruleselect"] = "NextGenPVE Rule Select", ["nextgenpveentselect"] = "NextGenPVE Entity Select", ["nextgenpvenpcselect"] = "NextGenPVE NPC Turret Target Exclusions", ["npcselectnotes"] = "Selected (Disabled) items in orange will be excluded from targeting by turrets, etc.  Items in green will be targeted (Enabled).  Use the Global Flags as a reference.", ["nextgenpveentedit"] = "NextGenPVE Entity Edit", ["nextgenpvevalue"] = "NextGenPVE Ruleset Value", ["nextgenpveexclusions"] = "NextGenPVE Ruleset Exclusions", ["nextgenpveschedule"] = "NextGenPVE Ruleset Schedule", ["scheduling"] = "Schedules should be in the format of 'day(s);starttime;endtime'.  Use * for all days.  Enter 0 to clear.", ["current2chedule"] = "Currently scheduled for day: {0} from {1} until {2}", ["noschedule"] = "Not currently scheduled", ["activelevels"] = "Active Levels", ["ground"] = "Ground", ["tunnel"] = "Tunnel", ["tunneld"] = "Tunnel Depth", ["sky"] = "Sky", ["skys"] = "Sky Start Height", ["all"] = "All", ["flags"] = "Global Flags", ["defload"] = "Set Defaults", ["deflag"] = "Reset Flags", ["reload"] = "Reload Config", ["default"] = "default", ["drop"] = "RESET DATABASE", ["none"] = "none", ["close"] = "Close", ["clone"] = "Clone", ["allow"] = "Allow", ["block"] = "Block", ["save"] = "Save", ["edit"] = "Edit", ["delete"] = "Delete", ["new"] = "new", ["newcat"] = "New Collection", ["setcat"] = "Set Collection", ["clicktoedit"] = "^Click to Edit^", ["editname"] = "Edit Name", ["editnpc"] = "Edit NPC Targeting", ["standard"] = "Standard", ["automated"] = "Automated", ["add"] = "Add", ["all"] = "All", ["true"] = "True", ["false"] = "False", ["editing"] = "Editing", ["source"] = "Source", ["target"] = "Target", ["exclude"] = "Exclude from", ["enableset"] = "Enable set to {0}", ["enabled"] = "Enabled", ["disabled"] = "Disabled", ["genabled"] = "Globally Enabled", ["gdisabled"] = "Globally Disabled", ["zone"] = "Zone", ["purgeactive"] = "PURGE ACTIVE", ["purgeinactive"] = "PURGE IS OVER", ["sinvert"] = "Invert Schedule", ["sinverted"] = "Schedule Inverted", ["schedule"] = "Schedule", ["schedulep"] = "Schedule (Active period)", ["schedulei"] = "Schedule (Inactive period)", ["scheduled"] = "Schedule Disabled", ["editing"] = "Editing", ["select"] = "Select", ["damage"] = "Damage", ["stock"] = "Stock", ["custom"] = "Custom", ["customedit"] = "Rule/Ent Editor", ["lookup"] = "lookup", ["unknown"] = "Unknown", ["search"] = "Search", ["defaultdamage"] = "Default Damage", ["damageexceptions"] = "Damage Exceptions", ["sourceexcl"] = "Source Exclusions", ["targetexcl"] = "Target Exclusions", ["clicktosetcoll"] = "Click to set collection", ["rule"] = "Rule", ["rules"] = "Rules", ["entities"] = "Entities", ["uentities"] = "Unknown Entities", ["logging"] = "Logging set to {0}", ["debug"] = "Debug set to {0}", ["day"] = "Day", ["starthour"] = "Start Hour", ["endhour"] = "End Hour", ["startminute"] = "Start Minute", ["endminute"] = "End Minute", ["NPCAutoTurretTargetsPlayers"] = "NPC AutoTurret Targets Players", ["NPCAutoTurretTargetsNPCs"] = "NPC AutoTurret Targets NPCs", ["AutoTurretTargetsPlayers"] = "AutoTurret Targets Players", ["HeliTurretTargetsPlayers"] = "Heli Turret Targets Players", ["AutoTurretTargetsNPCs"] = "AutoTurret Targets NPCs", ["NPCSamSitesIgnorePlayers"] = "NPC SamSites Ignore Players", ["SamSitesIgnorePlayers"] = "SamSites Ignore Players", ["NPCSamSitesTargetPlayers"] = "(ext) NPC SamSites Target Players", ["SamSitesTargetPlayers"] = "(ext) SamSites Target Players", ["NPCSamSitesTargetNPCs"] = "(ext) NPC SamSites Target NPCs", ["SamSitesTargetNPCs"] = "(ext) SamSites Target NPCs", ["NPCSamSitesTargetAnimals"] = "(ext) NPC SamSites Target Animals", ["SamSitesTargetAnimals"] = "(ext) SamSites Target Animals", ["AllowSuicide"] = "Allow Player Suicide", ["AllowFriendlyFire"] = "Allow Friendly Fire", ["TrapsIgnorePlayers"] = "Traps Ignore Players", ["HonorBuildingPrivilege"] = "Honor Building Privilege", ["UnprotectedBuildingDamage"] = "Unprotected Building Damage", ["UseHeliTimerToDetectPlayer"] = "Use Heli Timer To Detect Player", ["TwigDamage"] = "Twig Damage", ["HonorRelationships"] = "Honor Relationships", ["backup"] = "Backup Database", ["BackupDone"] = "NextGenPVE database has been backed up to {0}", ["RestoreDone"] = "NextGenPVE database has been restored from {0}", ["RestoreFailed"] = "Unable to restore from {0}!  Verify presence of file.", ["RestoreFilename"] = "Restore requires source filename ending in '.db'!", ["RestoreAvailable"] = "Available files:\n\t{0}"
            }
            , this, "en");
        }
        private void Unload() {
            foreach (BasePlayer player in BasePlayer.activePlayerList) {
                //if (!permission.UserHasPermission(player?.UserIDString, permNextGenPVEAdmin)) continue;
                CuiHelper.DestroyUi(player, NGPVERULELIST);
                CuiHelper.DestroyUi(player, NGPVERULEEDIT);
                CuiHelper.DestroyUi(player, NGPVEVALUEEDIT);
                CuiHelper.DestroyUi(player, NGPVESCHEDULEEDIT);
                CuiHelper.DestroyUi(player, NGPVEEDITRULESET);
                CuiHelper.DestroyUi(player, NGPVERULESELECT);
                CuiHelper.DestroyUi(player, NGPVEENTSELECT);
                CuiHelper.DestroyUi(player, NGPVENPCSELECT);
                CuiHelper.DestroyUi(player, NGPVEENTEDIT);
                CuiHelper.DestroyUi(player, NGPVERULEEXCLUSIONS);
                CuiHelper.DestroyUi(player, NGPVECUSTOMSELECT);
            }
            scheduleTimer?.Destroy();
            heliTimer?.Destroy();
            sqlConnection?.Close();
        }
        private void LoadData() {
            bool found = false;
            using (SQLiteConnection c = new(connStr)) {
                c.Open();
                using SQLiteCommand r = new("SELECT name FROM sqlite_master WHERE type='table' AND name='ngpve_entities'", c);
                using SQLiteDataReader rentry = r.ExecuteReader();
                while (rentry.Read()) {
                    found = true;
                }
            }
            if (!found) LoadDefaultEntities();
            found = false;
            using (SQLiteConnection c = new(connStr)) {
                c.Open();
                using SQLiteCommand r = new("SELECT name FROM sqlite_master WHERE type='table' AND name='ngpve_rules'", c);
                using SQLiteDataReader rentry = r.ExecuteReader();
                while (rentry.Read()) {
                    found = true;
                }
            }
            if (!found) LoadDefaultRules();
            found = false;
            using (SQLiteConnection c = new(connStr)) {
                c.Open();
                using SQLiteCommand r = new("SELECT name FROM sqlite_master WHERE type='table' AND name='ngpve_rulesets'", c);
                using SQLiteDataReader rentry = r.ExecuteReader();
                while (rentry.Read()) {
                    found = true;
                }
            }
            if (!found) LoadDefaultRuleset();
            found = false;
            using (SQLiteConnection c = new(connStr)) {
                c.Open();
                using SQLiteCommand r = new("SELECT name FROM sqlite_master WHERE type='table' AND name='ngpve_targetexclusion'", c);
                using SQLiteDataReader rentry = r.ExecuteReader();
                while (rentry.Read()) {
                    found = true;
                }
            }
            if (!found) LoadNPCTgtExclDb();
            ngpvezonemaps = Interface.GetMod().DataFileSystem.ReadObject<Dictionary<string, NextGenPVEZoneMap>>(Name + "/ngpve_zonemaps");
            lastConnected = Interface.GetMod().DataFileSystem.ReadObject<Dictionary<string, long>>(Name + "/ngpve_lastconnected");
        }
        private void SaveData() {
            Interface.GetMod().DataFileSystem.WriteObject(Name + "/ngpve_zonemaps", ngpvezonemaps);
            Interface.GetMod().DataFileSystem.WriteObject(Name + "/ngpve_lastconnected", lastConnected);
        }
#endregion
#region Oxide_hooks
        private object OnTrapTrigger(BaseTrap trap, GameObject go) {
            if (!enabled) return null;
            BasePlayer player = go.GetComponent<BasePlayer>();
            if (trap is null) return null;
            if (player is null) return null;
            object cantraptrigger = Interface.CallHook("CanEntityTrapTrigger", new object[] {
                trap, player
            }
            );
            if (cantraptrigger is object && cantraptrigger is bool && (bool)cantraptrigger) return null;
            if (configData.Options.TrapsIgnorePlayers) return false;
            return null;
        }
        private BasePlayer GetMountedPlayer(BaseMountable mount) {
            if (mount.GetMounted()) {
                return mount.GetMounted();
            }
            if (mount as BaseVehicle) {
                BaseVehicle vehicle = mount as BaseVehicle;
                foreach (BaseVehicle.MountPointInfo point in vehicle.mountPoints) {
                    if (point.mountable.IsValid() && point.mountable.GetMounted()) {
                        return point.mountable.GetMounted();
                    }
                }
            }
            return null;
        }
        private object OnSamSiteTarget(SamSite sam, BaseMountable mountable) {
            if (sam is null) return null;
            if (mountable is null) return null;
            BasePlayer player = GetMountedPlayer(mountable);
            if (player.IsValid()) {
                if (sam.OwnerID == 0 && configData.Options.NPCSamSitesIgnorePlayers) {
                    DoLog($"Skipping targeting by NPC SamSite of player {player.displayName}");
                    return true;
                    // block
                }
                else if (sam.OwnerID > 0 && configData.Options.SamSitesIgnorePlayers) {
                    DoLog($"Skipping targeting by SamSite of player {player.displayName}");
                    return true;
                    // block
                }
                try {
                    if (configData.Options.CanEntityBeTargeted?.Count > 0) {
                        foreach (string plugin in configData.Options.CanEntityBeTargeted) {
                            Plugin plug = plugins.Find(plugin);
                            object extCanEntityBeTargeted = plug?.Call("CanEntityBeTargeted");
                            if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                                return null;
                            }
                        }
                    }
                    else {
                        object extCanEntityBeTargeted = Interface.CallHook("CanEntityBeTargeted", new object[] {
                            player, sam
                        }
                        );
                        if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                            if ((bool)extCanEntityBeTargeted) {
                                return null;
                                // allow
                            }
                            else {
                                return true;
                                // block
                            }
                        }
                    }
                }
                catch {
                    if (configData.Options.debug) Puts("Humanoids detection failure.");
                }
            }
            return null;
            // allow
        }
        private object CanBeTargeted(BasePlayer target, GunTrap turret) {
            if (target is null) return null;
            if (turret is null) return null;
            if (!enabled) return null;
            try {
                if (configData.Options.CanEntityBeTargeted?.Count > 0) {
                    foreach (string plugin in configData.Options.CanEntityBeTargeted) {
                        Plugin plug = plugins.Find(plugin);
                        object extCanEntityBeTargeted = plug?.Call("CanEntityBeTargeted");
                        if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                            return null;
                        }
                    }
                }
                else {
                    object extCanEntityBeTargeted = Interface.CallHook("CanEntityBeTargeted", new object[] {
                        target, turret
                    }
                    );
                    if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                        return null;
                    }
                }
            }
            catch {
            }
            if (IsHumanoid(target) || IsHumanNPC(target) || target.IsNpc) {
                if (!configData.Options.AutoTurretTargetsNPCs) return false;
            }
            else if (!configData.Options.AutoTurretTargetsPlayers) {
                return false;
            }
            return null;
        }
        private object CanBeTargeted(BasePlayer target, FlameTurret turret) {
            if (!enabled) return null;
            if (target is null) return null;
            if (turret is null) return null;
            try {
                if (configData.Options.CanEntityBeTargeted?.Count > 0) {
                    foreach (string plugin in configData.Options.CanEntityBeTargeted) {
                        Plugin plug = plugins.Find(plugin);
                        object extCanEntityBeTargeted = plug?.Call("CanEntityBeTargeted");
                        if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                            return null;
                        }
                    }
                }
                else {
                    object extCanEntityBeTargeted = Interface.CallHook("CanEntityBeTargeted", new object[] {
                        target, turret
                    }
                    );
                    if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                        return null;
                    }
                }
            }
            catch {
            }
            if (IsHumanoid(target) || IsHumanNPC(target) || target.IsNpc) {
                if (!configData.Options.AutoTurretTargetsNPCs) return false;
            }
            else if (!configData.Options.AutoTurretTargetsPlayers) {
                return false;
            }
            return null;
        }
        private object CanBeTargeted(BasePlayer target, HelicopterTurret turret) {
            if (!enabled) return null;
            if (target is null) return null;
            if (turret is null) return null;
            if (!configData.Options.HeliTurretTargetsPlayers) return false;
            return null;
        }
        private object CanBeTargeted(BasePlayer target, AutoTurret turret) {
            if (!enabled) return null;
            if (target is null) return null;
            if (turret is null) return null;
            try {
                if (configData.Options.CanEntityBeTargeted?.Count > 0) {
                    foreach (string plugin in configData.Options.CanEntityBeTargeted) {
                        Plugin plug = plugins.Find(plugin);
                        object extCanEntityBeTargeted = plug?.Call("CanEntityBeTargeted");
                        if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                            return null;
                        }
                    }
                }
                else {
                    object extCanEntityBeTargeted = Interface.CallHook("CanEntityBeTargeted", new object[] {
                        target, turret
                    }
                    );
                    if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                        return null;
                    }
                }
            }
            catch {
            }
            if (IsHumanoid(target) || IsHumanNPC(target) || target.IsNpc) {
                if (!configData.Options.AutoTurretTargetsNPCs) return false;
            }
            else if (!configData.Options.AutoTurretTargetsPlayers) {
                return false;
            }
            return null;
        }
        private object CanBeTargeted(BasePlayer target, NPCAutoTurret turret) {
            if (!enabled) return null;
            if (target is null) return null;
            if (turret is null) return null;
            try {
                if (configData.Options.CanEntityBeTargeted?.Count > 0) {
                    foreach (string plugin in configData.Options.CanEntityBeTargeted) {
                        Plugin plug = plugins.Find(plugin);
                        object extCanEntityBeTargeted = plug?.Call("CanEntityBeTargeted");
                        if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                            return null;
                        }
                    }
                }
                else {
                    object extCanEntityBeTargeted = Interface.CallHook("CanEntityBeTargeted", new object[] {
                        target, turret
                    }
                    );
                    if (extCanEntityBeTargeted is object && extCanEntityBeTargeted is bool && (bool)extCanEntityBeTargeted) {
                        return null;
                    }
                }
            }
            catch {
            }
            if (IsHumanoid(target) || IsHumanNPC(target) || target.IsNpc) {
                if (!configData.Options.NPCAutoTurretTargetsNPCs) return false;
            }
            else if (!configData.Options.NPCAutoTurretTargetsPlayers) {
                return false;
            }
            return null;
        }
        private bool BlockFallDamage(BaseCombatEntity entity) {
            // Special case where attack by scrapheli initiates fall damage on a player.  This was often used to kill players and bypass the rules.
            List<BaseEntity> ents = Pool.Get<List<BaseEntity>>();
            Vis.Entities(entity.transform.position, 5, ents);
            foreach (BaseEntity ent in ents) {
                if (ent.ShortPrefabName == "scraptransporthelicopter" && configData.Options.BlockScrapHeliFallDamage) {
                    DoLog("Fall caused by scrapheli.  Blocking...");
                    Pool.FreeUnmanaged(ref ents);
                    return true;
                }
            }
            Pool.FreeUnmanaged(ref ents);
            return false;
        }
#endregion
#region inbound_hooks
        // Requires NREHook.cs from https://github.com/Remod-org/NREHook
        // We also check for the presence of this plugin to avoid callouts from other plugins.
        private void OnFoundNRE(string plugin, string unused) {
            Puts("BOGUS");
            if (NREHook && plugin == Name && configData.Options.enableDebugOnErrors && !onfoundnre) {
                if (configData.Options.autoDebugTime == 0) return;
                Puts("Error encountered.  ENABLING FULL DEBUG NOW!!!!!!!!!!");
                // Enable full debug for defined time in seconds
                configData.Options.debug = true;
                dolog = true;
                onfoundnre = true;
                timer.Once(configData.Options.autoDebugTime, () => {
                    configData.Options.debug = false;
                    dolog = false;
                    onfoundnre = false;
                    Puts("AUTOMATED DEBUG NOW DISABLED..........");
                }
                );
            }
        }
        private void ReloadConfig() => LoadConfigVariables(true);
        private bool TogglePVE(bool on = true) => enabled = on;
        private bool TogglePVERuleset(string rulesetname, bool on = true) {
            string enable = "0";
            if (on) enable = "1";
            using SQLiteConnection c = new(connStr);
            c.Open();
            using SQLiteCommand cmd = new($"UPDATE ngpve_rulesets SET enabled='{enable}", c);
            cmd.ExecuteNonQuery();
            return true;
        }
        private bool IsInPVEZone(BaseCombatEntity target) {
            string zone = "default";
            if (ZoneManager && configData.Options.useZoneManager) {
                string[] targetzone = GetEntityZones(target);
                //DoLog($"Found {sourcezone.Length} source zone(s) and {targetzone.Length} target zone(s).");
                if (targetzone.Length > 0) {
                    foreach (string z in targetzone) {
                        zone = z;
                        DoLog($"Found zone {zone}", 1);
                        break;
                    }
                }
            }
            string mquery = "SELECT DISTINCT name, zone, damage, enabled FROM ngpve_rulesets WHERE zone='0' OR zone='default'";
            switch (zone) {
                case "default" : DoLog("Default ruleset query");
                break;
                default : mquery = $"SELECT DISTINCT name, zone, damage, enabled FROM ngpve_rulesets WHERE zone='{zone}' OR zone='lookup'";
                break;
            }
            using SQLiteCommand findIt = new(mquery, sqlConnection);
            using SQLiteDataReader readMe = findIt.ExecuteReader();
            while (readMe.Read()) {
                if (!readMe.IsDBNull(2) && !readMe.IsDBNull(3) && readMe.GetInt32(2) == 1 && readMe.GetInt32(3) == 0) {
                    // Default damage for this ruleset is ENabled but ruleset is DISabled.
                    return true;
                }
                else if (!readMe.IsDBNull(2) && !readMe.IsDBNull(3) && readMe.GetInt32(2) == 0 && readMe.GetInt32(3) == 1) {
                    // Default damage for this ruleset is DISabled and ruleset is ENabled.
                    return true;
                }
            }
            return false;
        }
        private bool AddOrUpdateMapping(string zoneId, string rulesetname) {
            if (string.IsNullOrEmpty(zoneId)) return false;
            if (string.IsNullOrEmpty(rulesetname)) return false;
            DoLog($"AddOrUpdateMapping called for ruleset: {rulesetname}, zone: {zoneId}", 0);
            bool foundRuleset = false;
            using (SQLiteConnection c = new(connStr)) {
                c.Open();
                using SQLiteCommand au = new($"SELECT DISTINCT enabled FROM ngpve_rulesets WHERE name='{rulesetname}'", c);
                using SQLiteDataReader ar = au.ExecuteReader();
                while (ar.Read()) {
                    foundRuleset = true;
                }
            }
            if (foundRuleset) {
                if (!ngpvezonemaps.ContainsKey(rulesetname)) {
                    ngpvezonemaps.Add(rulesetname, new NextGenPVEZoneMap());
                }
                if (!ngpvezonemaps[rulesetname].map.Contains(zoneId)) {
                    ngpvezonemaps[rulesetname].map.Add(zoneId);
                }
                // Verify zones are valid
                ngpvezonemaps[rulesetname].map = CleanupZones(ngpvezonemaps[rulesetname].map);
                SaveData();
                using SQLiteConnection c = new(connStr);
                c.Open();
                DoLog($"UPDATE ngpve_rulesets SET zone='lookup' WHERE rulesetname='{rulesetname}'");
                using SQLiteCommand cmd = new($"UPDATE ngpve_rulesets SET zone='lookup' WHERE name='{rulesetname}'", c);
                cmd.ExecuteNonQuery();
                return true;
            }
            else {
                using (SQLiteConnection c = new(connStr)) {
                    c.Open();
                    DoLog($"INSERT INTO ngpve_rulesets VALUES('{rulesetname}', '1', '1', '1', 'lookup', '', '', '', '', 0, 0)");
                    using SQLiteCommand cmd = new($"INSERT INTO ngpve_rulesets VALUES('{rulesetname}', '1', '1', '1', 'lookup', '', '', '', '', 0, 0)", c);
                    cmd.ExecuteNonQuery();
                }
                if (ngpvezonemaps.ContainsKey(rulesetname)) ngpvezonemaps.Remove(rulesetname);
                ngpvezonemaps.Add(rulesetname, new NextGenPVEZoneMap() {
                    map = new List<string>() {
                        zoneId
                    }
                }
                );
                //Verify zones are valid
                //ngpvezonemaps[rulesetname].map = CleanupZones(ngpvezonemaps[rulesetname].map);
                SaveData();
                return true;
            }
        }
        private bool RemoveMapping(string zoneId) {
            DoLog($"RemoveMapping called for zone: {zoneId}", 0);
            bool found = false;
            foreach (KeyValuePair<string, NextGenPVEZoneMap> map in ngpvezonemaps) {
                if (map.Value.map is null) continue;
                if (map.Value.map.Contains(zoneId)) {
                    ngpvezonemaps[map.Key].map.Remove(zoneId);
                    SaveData();
                    DoLog($"RemoveMapping found and removed {zoneId} from ruleset {map.Key}", 0);
                    found = true;
                }
            }
            if (!found) {
                DoLog($"RemoveMapping did not find {zoneId} in any ruleset", 0);
            }
            return found;
        }
        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitinfo) {
            if (!enabled) return null;
            if (entity is null) return null;
            if (hitinfo is null) return null;
            Rust.DamageType majority = Rust.DamageType.Generic;
            try {
                majority = hitinfo.damageTypes.GetMajorityDamageType();
                if (majority == Rust.DamageType.Decay || majority == Rust.DamageType.Radiation) return null;
            }
            catch {
            }
            if (configData.Options.debug) Puts("ENTRY:");
            if (configData.Options.debug) Puts("Checking for null fall damage");
            if (majority == Rust.DamageType.Fall && hitinfo?.Initiator is null) {
                DoLog($"Null initiator for attack on {entity?.ShortPrefabName} by Fall");
                if (BlockFallDamage(entity)) {
                    if (configData.Options.debug) Puts(":EXIT");
                    return true;
                }
            }
            if (configData.Options.debug) Puts("Calling external damage hook");
            try {
                object CanTakeDamage = Interface.CallHook("CanEntityTakeDamage", new object[] {
                    entity, hitinfo
                }
                );
                if (CanTakeDamage is object && CanTakeDamage is bool && (bool)CanTakeDamage) {
                    if (configData.Options.debug) Puts($"Calling external damage hook for {hitinfo?.Initiator} attacking {entity?.ShortPrefabName} PASSED: ALLOW\n:EXIT");
                    return null;
                }
            }
            catch {
                if (configData.Options.debug) Puts("Calling external damage hook FAILED!");
            }
            string stype = "";
            string ttype = "";
            bool canhurt;
            DoLog("\nBEGIN:");
            if (hitinfo?.WeaponPrefab is object && hitinfo?.WeaponPrefab?.ShortPrefabName == "rocket_mlrs") {
                if (configData.Options.debug) Puts($"attacker prefab: {hitinfo?.WeaponPrefab?.ShortPrefabName}, victim prefab: {entity?.ShortPrefabName}");
                if (configData.Options.debug) Puts("Calling EvaluateRulesets: MLRS");
                canhurt = EvaluateRulesets(hitinfo?.WeaponPrefab, entity, hitinfo?.WeaponPrefab?.ShortPrefabName, out stype, out ttype);
            }
            //else if (!ReferenceEquals(hitinfo?.WeaponPrefab, null) && hitinfo?.WeaponPrefab?.ShortPrefabName == "homingmissile")
            //{
            //    if (configData.Options.debug) Puts($"attacker prefab: {hitinfo?.WeaponPrefab?.ShortPrefabName}, victim prefab: {entity?.ShortPrefabName}");
            //    if (configData.Options.debug) Puts("Calling EvaluateRulesets: Missile Launcher");
            //    canhurt = EvaluateRulesets(hitinfo?.WeaponPrefab, entity, hitinfo?.WeaponPrefab?.ShortPrefabName, out stype, out ttype);
            //}
            else if (hitinfo?.Initiator is null) {
                if (configData.Options.debug) Puts($"attacker prefab: {hitinfo?.Initiator?.ShortPrefabName}, victim prefab: {entity?.ShortPrefabName}");
                if (configData.Options.debug) Puts("NOT calling EvaluateRulesets: NULL INITIATOR");
                canhurt = true;
            }
            else {
                if (configData.Options.debug) Puts($"attacker prefab: {hitinfo?.Initiator?.ShortPrefabName}, victim prefab: {entity?.ShortPrefabName}");
                if (configData.Options.debug) Puts("Calling EvaluateRulesets: Standard");
                canhurt = EvaluateRulesets(hitinfo?.Initiator, entity, hitinfo?.Initiator?.ShortPrefabName, out stype, out ttype);
            }
            if (stype.Length == 0 && ttype.Length == 0) {
                if (configData.Options.debug) Puts("Calling EvaluateRulesets DETECTION FAILED");
                return null;
            }
            if (configData.Options.debug) Puts("Calling EvaluateRulesets PASSED");
            if (stype == "BasePlayer") {
                BasePlayer hibp = hitinfo?.Initiator as BasePlayer;
                if (configData.Options.debug) Puts("Checking for god perms");
                //if (hibp != null && permission.UserHasPermission(hibp.UserIDString, permNextGenPVEGod))
                if (hibp is object && permission.UserHasPermission(hibp?.UserIDString, permNextGenPVEGod)) {
                    Puts("Admin almighty!");
                    return null;
                }
                if (configData.Options.debug) Puts("Checking for suicide flag or friendly fire");
                if (ttype == "BasePlayer") {
                    ulong sid = hibp.userID;
                    ulong tid = (entity as BasePlayer)?.userID ?? 0;
                    if (tid.IsSteamId() && sid > 0 && tid > 0) {
                        if (sid == tid && configData.Options.AllowSuicide) {
                            DoLog("AllowSuicide TRUE");
                            canhurt = true;
                        }
                        else {
                            object isfr = IsFriend(sid, tid);
                            if (isfr is object && isfr is bool && (bool)isfr && configData.Options.AllowFriendlyFire) {
                                DoLog("AllowFriendlyFire TRUE");
                                canhurt = true;
                            }
                        }
                    }
                }
            }
            if (canhurt) {
                DoLog($"DAMAGE ALLOWED for {stype} attacking {ttype}, majority damage type {majority}");
                if (configData.Options.debug) Puts(":EXIT");
                return null;
            }
            DoLog($"DAMAGE BLOCKED for {stype} attacking {ttype}, majority damage type {majority}");
            if (configData.Options.debug) Puts(":EXIT");
            return true;
        }
#endregion
#region Main
        private bool EvaluateRulesets(BaseEntity source, BaseEntity target, string srcPrefab, out string stype, out string ttype) {
            stype = "";
            ttype = "";
            if (source is null || target is null) {
                if (configData.Options.debug) Puts("Null source or target object");
                return false;
            }
            if (configData.Options.debug) Puts("Getting source type");
            if (srcPrefab == "rocket_mlrs") {
                stype = "MLRS";
                if (configData.Options.debug) Puts("Source is MLRS.");
            }
            else if (srcPrefab == "fireball_small_molotov") {
                stype = "MolotovCocktail";
            }
            else if (IsPatrolHelicopter(source)) {
                stype = "PatrolHelicopter";
                if (configData.Options.debug) Puts("Source is helicopter.");
            }
            else {
                stype = source?.GetType()?.Name;
      
// ... [Code preview truncated due to length. Full source in attached file] ...

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