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

FREE BetterVanish : 1.7.3 1.7.3

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Facepunch;
using Network;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using Rust;
using Rust.AI;
using Rust.Registry;
using UnityEngine;
using QueryGrid = BaseEntity.Query;
using Human_Npc = global::HumanNPC;

namespace Oxide.Plugins
{
    [Info("BetterVanish", "CosaNostra", "1.7.3")]
    [Description("Customized & Optimized \"Vanish\"")]
    public class BetterVanish : RustPlugin
    {
        // Hooks: OnVanishDisappear(BasePlayer), OnVanishReappear(BasePlayer)
        // API: _IsInvisible(BasePlayer), _IsInvisible(IPlayer), _Disappear(BasePlayer), _Reappear(BasePlayer)

        #region Constants

        private const string PermUse = "bettervanish.allowed";
        private const string PermUseOther = "bettervanish.allowedother";
        private const string PermPermanent = "bettervanish.perma";
        private const string PermUnvanish = "bettervanish.unvanish";
        private const string PermInvSpy = "bettervanish.invspy";
        private const string PermSkipLocks = "bettervanish.skiplocks";
        private const string CuiName = "VanishIcon";
        private const string PlayerPrefab = "assets/prefabs/player/player.prefab";
        private const string PlayerCorpsePrefab = "assets/prefabs/player/player_corpse.prefab";
        private const string EffectDisappear = "assets/bundled/prefabs/fx/gestures/cameratakescreenshot.prefab";
        private const string EffectAppear = "assets/bundled/prefabs/fx/gestures/drink_vomit.prefab";
        private static readonly Effect EffectInstance = new Effect();
        private static readonly DamageTypeList EmptyDmgList = new DamageTypeList();
        private static readonly GameObjectRef EmptyObjRef = new GameObjectRef();
        private static readonly object FalseObj = false;
        private static readonly object TrueObj = true;
        //
        private enum VanishEvent { Disappear, Reappear, Disconnect, Unload }
        //
        private static readonly List<string> HooksLst = new List<string>
        {
            nameof(OnEntityMarkHostile), nameof(OnEntityTakeDamage), nameof(OnPlayerDisconnected), nameof(CanUseLockedEntity), nameof(OnPlayerViolation), 
            nameof(OnTeamInvite), nameof(OnPlayerColliderEnable)
        };

        #endregion

        #region Fields

        private static BetterVanish _instance;
        private static CuiElementContainer _cui;
        private GameObjectRef _fallDmgEff = EmptyObjRef, _drownEff = EmptyObjRef;
        private bool _isShutdown;
        private bool _lastHooksState = true;

        #endregion

        #region Configuration

        private const int CfgRev = 4;
        private static Configuration _config;

        public class Configuration
        {
            [JsonProperty(PropertyName = "Show visual indicator (true/false)")]
            public bool ShowIndicator;

            [JsonProperty(PropertyName = "Visual indicator image address")]
            public string IndicatorAddress;

            [JsonProperty(PropertyName = "Visual indicator anchor min")]
            public string IndicatorAnchorMin;

            [JsonProperty(PropertyName = "Visual indicator anchor max")]
            public string IndicatorAnchorMax;

            [JsonProperty(PropertyName = "Visual indicator color")]
            public string IndicatorColor;

            [JsonProperty("Depth of an underground teleport (upon disconnection)")]
            public float UndergroundTeleportDepth;

            [JsonProperty(PropertyName = "Block all incoming damage while vanished (true/false)")]
            public bool BlockAllIncomingDamage;

            [JsonProperty(PropertyName = "Block all outgoing damage while vanished (true/false)")]
            public bool BlockAllOutgoingDamage;

            [JsonProperty(PropertyName = "Auto vanish on connect (true/false)")]
            public bool AutoVanish;

            [JsonProperty(PropertyName = "Auto noclip on connect (true/false)")]
            public bool AutoNoclip;
            
            [JsonProperty(PropertyName = "Auto noclip on vanish (true/false)")]
            public bool AutoNoclipOnVanish;
            
            [JsonProperty(PropertyName = "Turn off noclip on reappear (true/false)")]
            public bool TurnOffNoclipOnReappear;

            [JsonProperty(PropertyName = "Persist vanish (don't unhide upon leave & restore after restart)")]
            public bool PersistVanish;

            [JsonProperty(PropertyName = "Use sound effects (true/false)")]
            public bool SoundEffects;
            
            [JsonProperty(PropertyName = "Enable safepoints (true/false)")]
            public bool SafePoints;

            [JsonProperty(PropertyName = "Remove all safepoints after wipe (true/false)")]
            public bool SafePointsRemoval;

            [JsonProperty(PropertyName = "Config revision (do not edit)")]
            public int ConfigRev;

            public static Configuration DefaultConfig()
            {
                return new Configuration
                {
                    ShowIndicator = true,
                    IndicatorAddress = "https://i.imgur.com/dOvX4uA.png",
                    IndicatorColor = "0.7 0 0 1",
                    IndicatorAnchorMin = "0.1 0.001",
                    IndicatorAnchorMax = "0.17 0.10",
                    UndergroundTeleportDepth = 15,
                    BlockAllIncomingDamage = true,
                    BlockAllOutgoingDamage = true,
                    AutoVanish = true,
                    AutoNoclip = true,
                    AutoNoclipOnVanish = true,
                    TurnOffNoclipOnReappear = true, 
                    PersistVanish = true,
                    SoundEffects = true,
                    SafePoints = true,
                    SafePointsRemoval = true,
                    ConfigRev = CfgRev
                };
            }
        }

        private void MigrateConfig()
        {
            switch (_config.ConfigRev)
            {
                case 1:
                case 2:
                case 3:
                    _config.ConfigRev = CfgRev;
                    break;
            }
            SaveConfig();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if(_config.ConfigRev != CfgRev)
                    MigrateConfig();
            }
            catch
            {
                PrintWarning($"Could not read oxide/config/{Name}.json, creating new config file");
                LoadDefaultConfig();
                SaveConfig();
            }
        }

        protected override void LoadDefaultConfig() => _config = Configuration.DefaultConfig();

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

        #endregion

        #region Data
        
        private readonly ListHashSet<ulong> _hiddenPlayers = new ListHashSet<ulong>();
        private readonly ListHashSet<ulong> _hiddenPlayersPersist = new ListHashSet<ulong>();
        private Dictionary<ulong, string> _safePoints;

        private void LoadSafePoints() =>
            _safePoints = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, string>>($"{nameof(BetterVanish)}-SafePoints");

        private void SaveSafePoints() => Interface.Oxide.DataFileSystem.WriteObject($"{nameof(BetterVanish)}-SafePoints", _safePoints);

        private void LoadPersistPlayers()
        {
            var lst = Interface.Oxide.DataFileSystem.ReadObject<List<ulong>>($"{nameof(BetterVanish)}-PersistPlr");
            _hiddenPlayersPersist.Clear();
            _hiddenPlayersPersist.AddRange(lst);
        }

        private void SavePersistPlayers() =>
            Interface.Oxide.DataFileSystem.WriteObject($"{nameof(BetterVanish)}-PersistPlr", new List<ulong>(_hiddenPlayersPersist));

        private void LoadData()
        {
            LoadSafePoints();
            LoadPersistPlayers();
        }

        private void SaveData()
        {
            SaveSafePoints();
            SavePersistPlayers();
        }
        
        #endregion

        #region Classes
        
        private class VanishComponent : MonoBehaviour, IEntity
        {
            private BasePlayer _owner;
            private GameObject _dummyObj;

            private static readonly ListHashSet<Type> InterestedTriggers = new ListHashSet<Type>
            {
                typeof(TriggerWorkbench), typeof(TriggerLadder), typeof(TriggerParent), typeof(TriggerParentEnclosed), typeof(TriggerParentExclusion),
                typeof(TriggerMount)
            };

            private void Awake()
            {
                _owner = GetComponent<BasePlayer>();
                if(_owner.IsConnected)
                    StartNetworkGroupsUpdate();
                SetupDummyCollider();
            }

            private void UpdateNetworkGroups()
            {
                if (_owner.IsConnected && !_owner.IsSpectating())
                    _owner.net.UpdateGroups(_owner.transform.position);
            }

            public void StopNetworkGroupsUpdate() => CancelInvoke(nameof(UpdateNetworkGroups));
            
            public void StartNetworkGroupsUpdate() => InvokeRepeating(nameof(UpdateNetworkGroups), 3f, 3f);
            
            private void OnDestroy()
            {
                Entity.Unregister(_dummyObj);
                _owner.RemoveFromTriggers();
                Destroy(_dummyObj);
                _dummyObj = null;
                _owner = null;
            }

            #region Trigger Subsystem

            public bool IsDestroyed => _owner.IsDestroyed;

            private void SetupDummyCollider()
            {
                _dummyObj = _owner.gameObject.CreateChild();
                _dummyObj.name = "VanishTrig";
                _dummyObj.tag = "DeployVolumeIgnore";
                Entity.Register(_dummyObj, this);
                _dummyObj.layer = (int)Layer.Player_Server;
                _dummyObj.AddComponent<SphereCollider>().isTrigger = true;
            }

            private IEnumerable<TriggerBase> GetValidTriggers(Collider collider) => collider.GetComponentsInParent<TriggerBase>().Where(t=>t.InterestedInObject(_owner.gameObject) && InterestedTriggers.Contains(t.GetType()));

            private void OnTriggerEnter(Collider collider)
            {
				if(_owner.IsSpectating())
					return;
                foreach (var trigger in GetValidTriggers(collider)) 
                    trigger.OnTriggerEnter(_owner.playerCollider);
            }

            private void OnTriggerExit(Collider collider)
            {
				if(_owner.IsSpectating())
					return;
                foreach (var trigger in GetValidTriggers(collider)) 
                    trigger.OnTriggerExit(_owner.playerCollider);
            }

            #endregion
            
        }

        private class LootProxyController : FacepunchBehaviour
        {
            public BasePlayer lootsrc;
            public BasePlayer looter;
            public PlayerCorpse proxy;

            public void Init(BasePlayer lootSource, BasePlayer looterPlayer)
            {
                lootsrc = lootSource;
                looter = looterPlayer;
            }

            private void Awake()
            {
                proxy = GetComponent<PlayerCorpse>();
                InvokeRepeating(LifeCheck, 1f,.65f);
            }

            private void PlayerStoppedLooting(BasePlayer player) => Destroy(this);

            private void LifeCheck()
            {
                if (lootsrc && looter && looter.IsConnected)
                    return;
                Destroy(this);
            }

            private void OnDestroy()
            {
                proxy.containers = null;
                proxy.Kill();
            }
        }

        #endregion

        #region Localization

        protected override void LoadDefaultMessages()
        {
            // English
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["CommandVanish"] = "vanish",
                ["CommandSetVanish"] = "setvanish",
                ["CommandUnvanishAll"] = "unvanishall",
                ["CommandInvSpy"] = "invspy",
                ["VanishDisabled"] = "<color=#FF686B>Vanish disabled</color>",
                ["VanishEnabled"] = "<color=#91D6FF>Vanish enabled</color>",
                ["VanishDisabledOther"] = "<color=#FF686B>You disabled vanish on {0}</color>",
                ["VanishEnabledOther"] = "<color=#91D6FF>You enabled vanish on {0}</color>",
                ["VanishPermanent"] = "<color=#FF686B>You have no rights to disable vanish!</color>",
                ["UnvanishedPlayers"] = "<color=#FF686B>You unvanished {0} players!</color>",
                ["SetVanishHelp"] = "Syntax: /setvanish PlayerName",
                ["SafePointNotSet"] = "You haven\'t set your <color=#F7B267>Safe Point</color>!\nType <color=#FF686B>/vanish safepoint</color> to save your current position.\nYou will be automatically teleported there upon disconnection.",
                ["SafePointSaved"] = "Your current position is saved as a Safe Point!",
                ["MultiplePlayers"] = "Multiple players found!\nRefine your search or use Steam ID.",
                ["NothingInSight"] = "No players in sight",
                ["NoSuchPlayer"] = "No such player found ({0})",
                ["InvSpyLooting"] = "Looting: {0} ({1}).",
            }, this);
        }

        #endregion

        #region Initialization

        private void Init()
        {
            _instance = this;
            permission.RegisterPermission(PermUse, this);
            permission.RegisterPermission(PermUseOther, this);
            permission.RegisterPermission(PermPermanent, this);
            permission.RegisterPermission(PermUnvanish, this);
            permission.RegisterPermission(PermInvSpy, this);
            permission.RegisterPermission(PermSkipLocks, this);
            AddCommandAliases("CommandVanish", nameof(VanishCommand));
            AddCommandAliases("CommandSetVanish", nameof(SetVanishCommand));
            AddCommandAliases("CommandUnvanishAll", nameof(UnvanishAllCommand));
            AddCommandAliases("CommandInvSpy", nameof(InvSpyCommand));
            if (!_config.AutoNoclip && !_config.AutoVanish && !_config.PersistVanish)
                Unsubscribe(nameof(OnPlayerConnected));
            LoadData();
            ManageHooks();
            _cui = new CuiElementContainer
            {
                new CuiElement
                {
                    Name = CuiName,
                    Parent = "Hud.Menu",
                    Components =
                    {
                        new CuiRawImageComponent { Color = _config.IndicatorColor, Url = _config.IndicatorAddress, Sprite = "assets/icons/refresh.png" },
                        new CuiRectTransformComponent { AnchorMin = _config.IndicatorAnchorMin, AnchorMax = _config.IndicatorAnchorMax }
                    }
                }
            };
        }
        
        private void OnServerInitialized()
        {
            var pp = GameManager.server.FindPrefab(PlayerPrefab).GetComponent<BaseEntity>().ToPlayer();
            _drownEff = pp.drownEffect;
            _fallDmgEff = pp.fallDamageEffect;
            DisappearAll();
        }

        private void OnNewSave(string _)
        {
            if (_config.SafePointsRemoval) 
                _safePoints.Clear();
            _hiddenPlayersPersist.Clear();
            SaveData();
        }

        #endregion

        #region De-initialization

        private void OnServerShutdown() => _isShutdown = true;

        private void Unload()
        {
            foreach (var uid in _hiddenPlayers.ToArray())
            {
                var plr = FindPlayerById(uid);
                if(plr)
                    HandleEvent(plr, VanishEvent.Unload);
            }
            SaveData();
            if (!_isShutdown) 
                ReappearAll();
            _config = null;
            _cui = null;
            _instance = null;
        }

        #endregion

        #region Commands

        private void VanishCommand(IPlayer iplayer, string command, string[] args)
        {
            var player = (BasePlayer)iplayer.Object;
            if (!player.IsAdmin && !HasPerm(player.UserIDString, PermUse))
                return;
            if (args.Length > 0 && args[0].Equals("safepoint") && _config.SafePoints)
            {
                _safePoints[player.userID] = $"{player.transform.position.x} {player.transform.position.y} {player.transform.position.z}";
                Player.Message(player, Lang("SafePointSaved", player.UserIDString));
                return;
            }
            var isVanished = IsPlayerVanished(player);
            if (isVanished && IsPlayerPermanent(player))
            {
                Player.Message(player, Lang("VanishPermanent", player.UserIDString));
                return;
            }
            HandleEvent(player, isVanished ? VanishEvent.Reappear : VanishEvent.Disappear);
        }

        private void SetVanishCommand(IPlayer iplayer, string command, string[] args)
        {
            var player = (BasePlayer)iplayer.Object;
            if (!player.IsAdmin && !HasPerm(player.UserIDString, PermUseOther))
                return;
            if (args.Length > 0)
            {
                var playerName = string.Join(" ", args);
                var result = FindPlayer(playerName);
                var target = result as BasePlayer;
                if (target == null && result != null)
                {
                    Player.Message(player, Lang("MultiplePlayers", player.UserIDString));
                    return;
                }

                if (target == null)
                {
                    Player.Message(player, Lang("NoSuchPlayer", player.UserIDString, playerName));
                    return;
                }

                var isVanished = IsPlayerVanished(target);
                HandleEvent(target, isVanished ? VanishEvent.Reappear : VanishEvent.Disappear);
                Player.Message(player, Lang(isVanished ? "VanishDisabledOther" : "VanishEnabledOther", player.UserIDString, target.displayName));
            }
            else
                Player.Message(player, Lang("SetVanishHelp", player.UserIDString));
        }

        private void UnvanishAllCommand(IPlayer iplayer, string command, string[] args)
        {
            var player = (BasePlayer)iplayer.Object;
            if (!player.IsAdmin && !HasPerm(player.UserIDString, PermUnvanish))
                return;
            var count = 0;
            ReappearAll(_=>count++);
            Player.Message(player, Lang("UnvanishedPlayers", player.UserIDString, count));
        }

        private void InvSpyCommand(IPlayer iplayer, string command, string[] args)
        {
            var player = (BasePlayer)iplayer.Object;
            if (!player.IsAdmin && (!HasPerm(player.UserIDString, PermInvSpy)))
                return;
            timer.In(.15f, () => InvSpyShowLoot(player, args));
        }

        #endregion

        #region Vanishing Act

        private void Disappear(BasePlayer player, bool showGui = true)
        {
            if (IsPlayerVanished(player))
                return;
            if (player.IsConnected)
            {
                if (!_hiddenPlayers.Contains(player.userID))
                    _hiddenPlayers.Add(player.userID);
                _hiddenPlayersPersist.Remove(player.userID);
            }
            else
                player.SetServerFall(false);
            player.syncPosition = false;
            player.limitNetworking = true;
            player.fallDamageEffect = EmptyObjRef;
            player.drownEffect = EmptyObjRef;
            player.GetHeldEntity()?.SetHeld(false);
            player.DisablePlayerCollider();
            VanishComponent vc;
            if (player.gameObject.TryGetComponent(out vc))
                vc.StartNetworkGroupsUpdate();
            else
                player.gameObject.AddComponent<VanishComponent>();
            SimpleAIMemory.AddIgnorePlayer(player);
            QueryGrid.Server.RemovePlayer(player);
            RemoveFromTargets(player);
            if (player.IsConnected)
            {
                if (showGui)
                    VanishGui(player);
                Player.Message(player, Lang("VanishEnabled", player.UserIDString));
                if (_config.SoundEffects)
                    SendEffectTo(EffectDisappear, player);
            }
            if(_config.AutoNoclipOnVanish && !player.isMounted && !player.IsFlying)
                player.SendConsoleCommand("noclip");
            ManageHooks();
            plugins.CallHook("OnVanishDisappear", player);
        }

        #endregion

        #region Reappearing Act

        private void Reappear(BasePlayer player)
        {
            if (!IsPlayerVanished(player) && !IsPlayerPersisted(player))
                return;
            _hiddenPlayers.Remove(player.userID);
            _hiddenPlayersPersist.Remove(player.userID);
            player.syncPosition = true;
            player.limitNetworking = false;
            UnityEngine.Object.Destroy(player.GetComponent<VanishComponent>());
            player.UpdateNetworkGroup();
            player.SendNetworkUpdate();
            player.GetHeldEntity()?.UpdateVisibility_Hand();
            player.EnablePlayerCollider();
            QueryGrid.Server.AddPlayer(player);
            SimpleAIMemory.RemoveIgnorePlayer(player);
            player.drownEffect = _drownEff;
            player.fallDamageEffect = _fallDmgEff;
            player.ForceUpdateTriggers();
            if (player.IsConnected)
            {
                DestroyVanishGui(player);
                Player.Message(player, Lang("VanishDisabled", player.UserIDString));
                if (_config.SoundEffects)
                    SendEffectTo(EffectAppear, player);
            }
            if(_config.TurnOffNoclipOnReappear && !player.isMounted && player.IsFlying)
                player.SendConsoleCommand("noclip");
            ManageHooks();
            plugins.CallHook("OnVanishReappear", player);
        }

        #endregion

        #region Hooks

        private object OnEntityTakeDamage(BaseEntity victim, HitInfo info)
        {
            var attacker = info?.InitiatorPlayer;
            if (victim == null && attacker == null)
                return null;
            var victimInvis = IsPlayerVanished(victim.ToPlayer());
            var attackerInvis = IsPlayerVanished(attacker);
            if (!victimInvis && !attackerInvis)
                return null;
            if (victimInvis && !_config.BlockAllIncomingDamage)
                return null;
            if (attackerInvis && !victimInvis && !_config.BlockAllOutgoingDamage)
                return null;
            if (info == null)
                return this;
            info.damageTypes = EmptyDmgList;
            info.HitMaterial = 0;
            info.DoHitEffects = false;
            info.PointStart = Vector3.zero;
            info.HitEntity = null;
            return this;
        }

        private object OnEntityMarkHostile(BasePlayer player) => IsPlayerVanished(player) ? this : null;

        private object OnPlayerColliderEnable(BasePlayer player, CapsuleCollider _) => IsPlayerVanished(player) ? this : null;

        private object CanUseLockedEntity(BasePlayer player, BaseLock baseLock)
        {
            if (!IsPlayerVanished(player))
                return null;
            if(player.IsAdmin || permission.UserHasPermission(player.UserIDString, PermSkipLocks))
                return TrueObj;
            var cl = baseLock as CodeLock;
            if (cl != null)
                return cl.whitelistPlayers.Contains(player.userID) || cl.guestPlayers.Contains(player.userID) ? TrueObj : FalseObj;
            return null;
        }

        private object OnPlayerViolation(BasePlayer player, AntiHackType type, float amount) => IsPlayerVanished(player) ? FalseObj : null;

        private object OnTeamInvite(BasePlayer inviter, BasePlayer target) => IsPlayerVanished(inviter) ? FalseObj : null;
        
        private void OnPlayerConnected(BasePlayer player)
        {
            if (player == null || !player.IsConnected)
                return;
            if(!player.IsAdmin && !HasPerm(player.UserIDString, PermUse))
                return;
            if((_config.PersistVanish && IsPlayerPersisted(player)) || _config.AutoVanish || IsPlayerPermanent(player))
                HandleEvent(player, VanishEvent.Disappear);
            if (_config.AutoNoclip)
                player.SendConsoleCommand("noclip");
        }
        
        private void OnPlayerDisconnected(BasePlayer player)
        {
            if (!_hiddenPlayers.Contains(player.userID))
                return;
            HandleEvent(player, VanishEvent.Disconnect);
        }

        #endregion

        #region GUI Indicator

        private static void VanishGui(BasePlayer player)
        {
            if (!_config.ShowIndicator)
                return;
            DestroyVanishGui(player);
            CuiHelper.AddUi(player, _cui);
        }

        private static void DestroyVanishGui(BasePlayer player)
        {
            if (!_config.ShowIndicator)
                return;
            CuiHelper.DestroyUi(player, CuiName);
        }

        #endregion

        #region Inventory Spy Logic

        private void InvSpyShowLoot(BasePlayer player, string[] args)
        {
            if (player.inventory.loot.IsLooting() || player.IsDead())
                return;
            BasePlayer target = null;
            var playerName = args != null ? string.Join(" ", args) : null;
            if (string.IsNullOrWhiteSpace(playerName))
            {
                var hits = Pool.GetList<RaycastHit>();
                GamePhysics.TraceAll(player.eyes.HeadRay(),.1f, hits, 5f, Layers.Server.Players);
                var hit = hits.FirstOrDefault(h => h.collider.gameObject != player.gameObject);
                if (hit.collider != null)
                    target = hit.transform.ToBaseEntity().ToPlayer();
                Pool.FreeList(ref hits);
            }
            else
            {
                var result = FindPlayer(playerName);
                target = result as BasePlayer;
                if (target == null && result != null)
                {
                    Player.Message(player, Lang("MultiplePlayers", player.UserIDString));
                    return;
                }
            }
            if (target == null)
            {
                Player.Message(player,
                    $"{(string.IsNullOrWhiteSpace(playerName) ? Lang("NothingInSight", player.UserIDString) : Lang("NoSuchPlayer", player.UserIDString, playerName))}.");
                return;
            }
            var proxyCorpse = InvSpyCreateProxy(player, target);
            player.inventory.loot.StartLootingEntity(proxyCorpse, false);
            player.inventory.loot.AddContainer(target.inventory.containerMain);
            player.inventory.loot.AddContainer(target.inventory.containerWear);
            player.inventory.loot.AddContainer(target.inventory.containerBelt);
            player.inventory.loot.SendImmediate();
            player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", "player_corpse");
            Player.Message(player, Lang("InvSpyLooting", player.UserIDString, GetPrettyPlayerName(target), target.UserIDString));
        }

        private static PlayerCorpse InvSpyCreateProxy(BasePlayer receiver, BasePlayer target)
        {
            var prx = (PlayerCorpse) GameManager.server.CreateEntity(PlayerCorpsePrefab, TerrainMeta.LowestPoint);
            prx.enableSaving = false;
            prx.syncPosition = false;
            prx.playerSteamID = receiver.userID;
            prx.playerName = GetPrettyPlayerName(target);
            prx.parentEnt = null;
            prx.Spawn();
            prx.InitializeHealth(float.MaxValue, float.MaxValue);
            prx.gameObject.AddComponent<LootProxyController>().Init(target, receiver);
            UnityEngine.Object.Destroy(prx.GetComponent<Buoyancy>());
            UnityEngine.Object.Destroy(prx.GetComponent<Rigidbody>());
            prx.CancelInvoke(prx.RemoveCorpse);
            prx.SetFlag(BaseEntity.Flags.Busy, true);
            SendEntitySnapshotEx(receiver, prx);
            return prx;
        }

        #endregion

        #region Logic

        private void HandleEvent(BasePlayer player, VanishEvent evt)
        {
            switch (evt)
            {
                case VanishEvent.Disappear:
                    Disappear(player);
                    if (_config.SafePoints && !HasSafePoint(player) && player.IsConnected && !player.IsSleeping()
                        && (player.IsAdmin || HasPerm(player.UserIDString, PermUse))) 
                        Player.Message(player, Lang("SafePointNotSet", player.UserIDString));
                    break;
                case VanishEvent.Reappear:
                    Reappear(player);
                    break;
                case VanishEvent.Disconnect:
                    NextTick(()=>player.SetServerFall(false));
                    if (((player.IsAdmin && _config.UndergroundTeleportDepth != 0f) || (_config.SafePoints && HasSafePoint(player)))) 
                        player.Teleport(GetSafePoint(player));
                    var vanishStay = false;
                    if (CanPersistPlayer(player))
                    {
                        AddPersistPlayer(player);
                        vanishStay = true;
                    }
                    if (IsPlayerPermanent(player))
                        vanishStay = true;
                    if (vanishStay)
                    {
                        _hiddenPlayers.Remove(player.userID);
                        player.GetComponent<VanishComponent>()?.StopNetworkGroupsUpdate();
                        NextTick(()=>player.DisablePlayerCollider());
                        ManageHooks();
                    }
                    else
                        Reappear(player);
                    break;
                case VanishEvent.Unload:
                    if (CanPersistPlayer(player)) 
                        AddPersistPlayer(player);
                    break;
            }
        }

        private static void RemoveFromTargets(BasePlayer player)
        {
            var hits = QueryGrid.Server.GetInSphere(player.GetNetworkPosition(), 64f, AIBrainSenses.queryResults,
                ent => ent is Human_Npc || ent is BaseAnimalNPC || ent is BaseFishNPC || ent is BradleyAPC);
            for (var i = 0; i < hits; i++)
            {
                var ent = AIBrainSenses.queryResults[i];
                if(ent is BradleyAPC)
                {
                    var apc = ((BradleyAPC)ent);
                    var ti = apc.targetList.FirstOrDefault(t => t.entity == player);
                    if (ti != null)
                    {
                        apc.targetList.Remove(ti);
                        Pool.Free(ref ti);
                        apc.UpdateTargetList();
                    }
                }
                else
                    RemoveFromTargets0(player, ent.GetComponent<BaseAIBrain>());
            }
        }

        private static void RemoveFromTargets0(BasePlayer player, BaseAIBrain brain)
        {
            if(brain == null)
                return;
            try
            {
                if(brain.Events != null && brain.Events.Memory.Entity.Get(brain.Events.CurrentInputMemorySlot) == player)
                    brain.Events.Memory.Entity.Remove(brain.Events.CurrentInputMemorySlot);
                brain.Senses.Memory.Players.Remove(player);
                brain.Senses.Memory.Targets.Remove(player);
                brain.Senses.Memory.Threats.Remove(player);
                brain.Senses.Memory.LOS.Remove(player);
                brain.Senses.Memory.All.RemoveAll(si => si.Entity == player);
            }
            catch (Exception e)
            {
                _instance.PrintError(
                    $"RemoveFromTargets failure ({e.GetType()})! Brain: {brain.GetType().FullName}.[E:{brain.Events != null};S:{brain.Senses != null};SM:{brain.Senses?.Memory != null}].Please report to us!");
            }
        }

        private void ReappearAll(Action<BasePlayer> onReappear = null)
        {
            var results = _hiddenPlayers.AsEnumerable();
            if (_config.PersistVanish)
                results = results.Concat(_hiddenPlayersPersist);
            foreach (var hiddenPlayer in results.Distinct().Select(uid => FindPlayerById(uid)))
            {
                if (!hiddenPlayer)
                    continue;
                Reappear(hiddenPlayer);
                onReappear?.Invoke(hiddenPlayer);
            }
        }

        private void DisappearAll(Action<BasePlayer> onDisappear = null)
        {
            var results = BasePlayer.allPlayerList.Where(p => IsPlayerPermanent(p) && !IsPlayerVanished(p));
            if (_config.PersistVanish)
                results = results.Concat(_hiddenPlayersPersist.Select(uid=> FindPlayerById(uid)).Where(p=>p));
            foreach (var hiddenPlayer in results.Distinct())
            {
                if (!hiddenPlayer || (!hiddenPlayer.IsAdmin && !HasPerm(hiddenPlayer.UserIDString, PermUse)))
                    continue;
                Disappear(hiddenPlayer);
                onDisappear?.Invoke(hiddenPlayer);
            }
        }
        
        private void AddPersistPlayer(BasePlayer player)
        {
            if(!_hiddenPlayersPersist.Contains(player.userID))
                _hiddenPlayersPersist.Add(player.userID);
            _hiddenPlayers.Remove(player.userID);
            ManageHooks();
        }

        #endregion

        #region Helpers

        private void AddCommandAliases(string key, string command)
        {
            foreach (var language in lang.GetLanguages(this))
            {
                var messages = lang.GetMessages(language, this);
                foreach (var message in messages.Where(m => m.Key.Equals(key)))
                    AddCovalenceCommand(message.Value, command);
            }
        }

        private void SubscribeToHooks()
        {
            foreach (var hook in HooksLst)
                Subscribe(hook);
        }

        private void UnSubscribeFromHooks()
        {
            foreach (var hook in HooksLst)
                Unsubscribe(hook);
        }

        private static void SendEffectTo(string effect, BasePlayer player)
        {
            EffectInstance.Init(Effect.Type.Generic, player, 0, Vector3.up, Vector3.zero);
            EffectInstance.pooledstringid = StringPool.Get(effect);
            var nw = Net.sv.StartWrite();
            nw.PacketID(Message.Type.Effect);
            EffectInstance.WriteToStream(nw);
            nw.Send(new SendInfo(player.net.connection));
            EffectInstance.Clear();
        }

        private bool HasSafePoint(BasePlayer player) => _config.SafePoints && _safePoints.ContainsKey(player.userID);

        private Vector3 GetSafePoint(BasePlayer player)
        {
            try
            {
                if (HasSafePoint(player))
                    return Vector3Ex.Parse(_safePoints[player.userID]);
            }
            catch { }
            return new Vector3(player.transform.position.x, TerrainMeta.HeightMap.GetHeight(player.transform.position) - _config.UndergroundTeleportDepth, player.transform.position.z);
        }

        private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);

        private bool HasPerm(string id, string perm) => permission.UserHasPermission(id, perm);

        private bool IsPlayerVanished(BasePlayer player) => player != null && _hiddenPlayers.Contains(player.userID);
        
        private bool IsPlayerVanished(ulong playerId) => _hiddenPlayers.Contains(playerId);

        private bool IsPlayerPersisted(BasePlayer player) => player != null && _hiddenPlayersPersist.Contains(player.userID);

        private bool IsPlayerPermanent(BasePlayer player) => HasPerm(player.UserIDString, PermPermanent) && HasPerm(player.UserIDString, PermUse);
        
        private bool CanPersistPlayer(BasePlayer player) =>
            _config.PersistVanish && !IsPlayerPermanent(player) && (player.IsAdmin || HasPerm(player.UserIDString, PermUse));

        private static object FindPlayer(string name, bool sleeping = true)
        {
            var player = BasePlayer.Find(name) ?? BasePlayer.FindSleeping(name);
            if (player != null)
                return player;
            var list = BasePlayer.activePlayerList.ToArray();
            if (sleeping)
                list = list.Concat(BasePlayer.sleepingPlayerList.Values).ToArray();
            var result = list.Where(p =>
                p.displayName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase) || p.displayName.Contains(name, CompareOptions.IgnoreCase));
            var players = result as BasePlayer[] ?? result.ToArray();
            if (players.Length == 0)
                return null;
            if (players.Length > 1)
                return players;
            return players[0];
        }
        
        private static BasePlayer FindPlayerById(ulong uid) => BasePlayer.FindByID(uid) ?? BasePlayer.FindSleeping(uid);

        private static void SendEntitySnapshotEx(BaseNetworkable receiver, BaseNetworkable ent)
        {
            if (ent == null || ent.net == null)
                return;
            ++receiver.net.connection.validate.entityUpdates;
            var saveInfo = new BaseNetworkable.SaveInfo
            {
                forConnection = receiver.net.connection,
                forDisk = false
            };
            var nw = Net.sv.StartWrite();
            nw.PacketID(Message.Type.Entities);
            nw.UInt32(receiver.net.connection.validate.entityUpdates);
            ent.ToStreamForNetwork(nw, saveInfo);
            nw.Send(new SendInfo(receiver.net.connection));
        }

        private static string GetPrettyPlayerName(BasePlayer player)
        {
            if (player.IsNpc)
                return $"*NPC* {player.ShortPrefabName}";
            else if (!player.IsConnected)
                return $"*Offline* {player.displayName}";
            else if (player.IsSleeping())
                return $"*Sleeping* {player.displayName}";
            return $"{player.displayName}";
        }
        
        private void ManageHooks()
        {
            var newState = _hiddenPlayers.Count > 0;
            if(newState == _lastHooksState)
                return;
            if(newState)
                SubscribeToHooks();
            else
                UnSubscribeFromHooks();
            _lastHooksState = newState;
        }
    
        #endregion

        #region API

        private bool _IsInvisible(BasePlayer player) => IsPlayerVanished(player);
        
        private bool _IsInvisible(IPlayer player) => IsPlayerVanished((BasePlayer)player.Object);

        private void _Disappear(BasePlayer player) => HandleEvent(player, VanishEvent.Disappear);

        private void _Reappear(BasePlayer player) => HandleEvent(player, VanishEvent.Reappear);

        #endregion

    }
}

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