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

FREE FriendlySAM : 1.0.1 1.0.1

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("FriendlySAM", "wGw", "1.0.1")]
    [Description("SAM sites ignore players and air vehicles that are authorised on the covering Tool Cupboard. Pure event-driven, zero per-tick.")]
    public class FriendlySAM : RustPlugin
    {
        #region Fields

        private Configuration _config;

        // TC net.ID → currently authorised player userIDs
        private readonly Dictionary<ulong, HashSet<ulong>> _tcAuthCache = new Dictionary<ulong, HashSet<ulong>>();

        // Air vehicles we protect (mini, scrap heli, attack heli)
        private static readonly HashSet<string> AirVehiclePrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            "minicopter.entity",
            "scraptransporthelicopter",
            "attackhelicopter.entity"
        };

        private const string PermAdmin = "friendlysam.admin";

        #endregion

        #region Config

        private class Configuration
        {
            [JsonProperty("Version (do not edit)")]
            public VersionNumber Version { get; set; } = new VersionNumber(1, 0, 1);

            [JsonProperty("Enabled")]
            public bool Enabled { get; set; } = true;

            [JsonProperty("Debug (console spam)")]
            public bool Debug { get; set; } = false;
        }

        protected override void LoadDefaultConfig()
        {
            _config = new Configuration();
            SaveConfig();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config == null)
                    throw new Exception("Config is null");

                if (_config.Version < new VersionNumber(1, 0, 1))
                {
                    _config.Version = new VersionNumber(1, 0, 1);
                }
            }
            catch
            {
                PrintWarning("Config corrupt or missing — generating defaults.");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(_config, true);

        #endregion

        #region Oxide Hooks - Lifecycle

        private void Init()
        {
            permission.RegisterPermission(PermAdmin, this);
        }

        private void OnServerInitialized()
        {
            // Delay slightly so all TCs are fully loaded
            timer.Once(2f, RebuildAllTcCache);
        }

        private void Unload()
        {
            _tcAuthCache.Clear();
        }

        #endregion

        #region Hooks - SAM Targeting

        private object OnSamSiteTarget(SamSite samSite, SamSite.ISamSiteTarget target)
        {
            if (!_config.Enabled || samSite == null || target == null)
                return null;

            // Monument / static / orphan SAMs stay fully aggressive
            BuildingPrivlidge priv = samSite.GetBuildingPrivilege();
            if (priv == null)
                return null;

            // --- Player on foot ---
            BasePlayer player = target as BasePlayer;
            if (player != null)
            {
                if (IsAuthedCached(priv, player.userID))
                {
                    if (_config.Debug)
                        Puts($"[FriendlySAM] Blocked player {player.displayName} ({player.userID}) on TC {priv.net.ID}");
                    return false;
                }
                return null;
            }

            // --- Air vehicle ---
            BaseEntity entity = target as BaseEntity;
            if (entity == null || !AirVehiclePrefabs.Contains(entity.ShortPrefabName))
                return null;

            BaseVehicle vehicle = entity as BaseVehicle;
            if (vehicle == null)
                return null;

            // If any seated player is authorised on this TC, the whole vehicle is friendly
            if (vehicle.mountPoints != null)
            {
                for (int i = 0; i < vehicle.mountPoints.Count; i++)
                {
                    var mount = vehicle.mountPoints[i];
                    if (mount?.mountable == null)
                        continue;

                    BasePlayer occupant = mount.mountable.GetMounted();
                    if (occupant != null && IsAuthedCached(priv, occupant.userID))
                    {
                        if (_config.Debug)
                            Puts($"[FriendlySAM] Blocked air vehicle {entity.ShortPrefabName} (occupant {occupant.displayName}) on TC {priv.net.ID}");
                        return false;
                    }
                }
            }

            return null;
        }

        #endregion

        #region Hooks - Cupboard Auth Changes

        private void OnCupboardAuthorize(BuildingPrivlidge priv, BasePlayer player)
        {
            InvalidateTc(priv);
        }

        private void OnCupboardDeauthorize(BuildingPrivlidge priv, BasePlayer player)
        {
            InvalidateTc(priv);
        }

        private void OnCupboardClearList(BuildingPrivlidge priv, BasePlayer player)
        {
            InvalidateTc(priv);
        }

        private void OnEntityKill(BuildingPrivlidge priv)
        {
            InvalidateTc(priv);
        }

        #endregion

        #region Cache

        private bool IsAuthedCached(BuildingPrivlidge priv, ulong userId)
        {
            if (priv == null || priv.net == null)
                return false;

            ulong tcId = priv.net.ID.Value;

            if (!_tcAuthCache.TryGetValue(tcId, out HashSet<ulong> set))
            {
                // Cache miss — build on demand
                set = BuildAuthSet(priv);
                _tcAuthCache[tcId] = set;
            }

            return set.Contains(userId);
        }

        private HashSet<ulong> BuildAuthSet(BuildingPrivlidge priv)
        {
            var set = new HashSet<ulong>();
            if (priv?.authorizedPlayers == null)
                return set;

            // In current Rust, authorizedPlayers is a collection of ulong userIDs
            foreach (ulong userId in priv.authorizedPlayers)
            {
                set.Add(userId);
            }

            return set;
        }

        private void InvalidateTc(BuildingPrivlidge priv)
        {
            if (priv?.net == null)
                return;

            _tcAuthCache.Remove(priv.net.ID.Value);

            if (_config.Debug)
                Puts($"[FriendlySAM] Invalidated TC cache for {priv.net.ID}");
        }

        private void RebuildAllTcCache()
        {
            _tcAuthCache.Clear();

            foreach (var priv in UnityEngine.Object.FindObjectsOfType<BuildingPrivlidge>())
            {
                if (priv == null || priv.net == null || priv.IsDestroyed)
                    continue;

                _tcAuthCache[priv.net.ID.Value] = BuildAuthSet(priv);
            }

            Puts($"[FriendlySAM] Rebuilt TC auth cache — {_tcAuthCache.Count} cupboards");
        }

        #endregion

        #region Commands

        [ChatCommand("friendlysam.reload")]
        [ConsoleCommand("friendlysam.reload")]
        private void CmdReload(BasePlayer player, string command, string[] args)
        {
            if (player != null && !permission.UserHasPermission(player.UserIDString, PermAdmin))
            {
                player.ChatMessage("You do not have permission to use this command.");
                return;
            }

            LoadConfig();
            RebuildAllTcCache();

            string msg = $"[FriendlySAM] Reloaded. Enabled={_config.Enabled} | Cached TCs={_tcAuthCache.Count}";
            if (player != null)
                player.ChatMessage(msg);
            else
                Puts(msg);
        }

        #endregion
    }
}

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