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

FREE DroneTurrets : 1.3.3 1.3.3

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using VLB;
namespace Oxide.Plugins {
    [Info("Drone Turrets", "WhiteThunder", "1.3.3")]
    [Description("Allows players to deploy auto turrets to RC drones.")]
    internal class DroneTurrets : CovalencePlugin {
#region Fields
        [PluginReference]
        private readonly Plugin DroneSettings, EntityScaleManager;
        private Configuration _config;
        private const float TurretScale = 0.6f;
        private const string PermissionDeploy = "droneturrets.deploy";
        private const string PermissionDeployNpc = "droneturrets.deploynpc";
        private const string PermissionDeployFree = "droneturrets.deploy.free";
        private const string PermissionAutoDeploy = "droneturrets.autodeploy";
        private const string PermissionControl = "droneturrets.control";
        private const string SpherePrefab = "assets/prefabs/visualization/sphere.prefab";
        private const string AutoTurretPrefab = "assets/prefabs/npc/autoturret/autoturret_deployed.prefab";
        private const string NpcAutoTurretPrefab = "assets/content/props/sentry_scientists/sentry.bandit.static.prefab";
        private const string ElectricSwitchPrefab = "assets/prefabs/deployable/playerioents/simpleswitch/switch.prefab";
        // private const string AlarmPrefab = "assets/prefabs/io/electric/other/alarmsound.prefab";
        private const string AlarmPrefab = "assets/prefabs/deployable/playerioents/alarms/audioalarm.prefab";
        private const string SirenLightPrefab = "assets/prefabs/io/electric/lights/sirenlightorange.prefab";
        private const string DeployEffectPrefab = "assets/prefabs/npc/autoturret/effects/autoturret-deploy.prefab";
        private const string CodeLockDeniedEffectPrefab = "assets/prefabs/locks/keypad/effects/lock.code.denied.prefab";
        private const int AutoTurretItemId = -2139580305;
        private const BaseEntity.Slot TurretSlot = BaseEntity.Slot.UpperModifier;
        private static readonly Vector3 SphereEntityLocalPosition = new(0, -0.14f, 0);
        private static readonly Vector3 TurretSwitchPosition = new Vector3(0, 0.36f, -0.32f);
        private static readonly Quaternion TurretSwitchRotation = Quaternion.Euler(0, 180, 0);
        private static readonly Vector3 SphereTransformScale = new(TurretScale, TurretScale, TurretScale);
        private static readonly Vector3 TurretTransformScale = new(1 / TurretScale, 1 / TurretScale, 1 / TurretScale);
        private readonly object True = true;
        private readonly object False = false;
        private DynamicHookSubscriber<NetworkableId> _turretDroneTracker;
#endregion
#region Hooks
        private void Init() {
            permission.RegisterPermission(PermissionDeploy, this);
            permission.RegisterPermission(PermissionDeployNpc, this);
            permission.RegisterPermission(PermissionDeployFree, this);
            permission.RegisterPermission(PermissionAutoDeploy, this);
            permission.RegisterPermission(PermissionControl, this);
            var dynamicHookNames = new List<string> {
                nameof(OnServerCommand), nameof(OnSwitchToggle), nameof(OnSwitchToggled), nameof(OnTurretTarget), nameof(OnEntityTakeDamage), nameof(OnEntityKill), nameof(OnEntityDeath), nameof(CanPickupEntity), nameof(OnBookmarkControlStarted), nameof(OnBookmarkControlEnded), nameof(canRemove),
            }
            ;
            _turretDroneTracker = new DynamicHookSubscriber<NetworkableId>(this, dynamicHookNames.ToArray());
            _turretDroneTracker.UnsubscribeAll();
        }
        private void OnServerInitialized() {
            foreach (var entity in BaseNetworkable.serverEntities) {
                var drone = entity as Drone;
                if (drone == null || !RCUtils.IsRCDrone(drone)) continue;
                var turret = GetDroneTurret(drone);
                if (turret == null) continue;
                RefreshDroneTurret(drone, turret);
            }
            foreach (var player in BasePlayer.activePlayerList) {
                var turret = RCUtils.GetControlledEntity<AutoTurret>(player, out var station);
                if (turret == null) continue;
                OnBookmarkControlStarted(station, player, turret.GetIdentifier(), turret);
            }
        }
        private void Unload() {
            DroneController.DestroyAll();
        }
        private object OnServerCommand(ConsoleSystem.Arg arg) {
            if (arg.Connection == null) return null;
            var player = arg.Player();
            if (player == null) return null;
            if (arg.cmd.FullName == "vehicle.swapseats") {
                HandleSwapSeats(player);
                return null;
            }
            if (arg.cmd.FullName == "inventory.lighttoggle") return HandleLightToggle(player);
            return null;
        }
        private void OnEntityBuilt(Planner planner, GameObject go) {
            if (planner == null || go == null) return;
            var drone = go.ToBaseEntity() as Drone;
            if (drone == null) return;
            var player = planner.GetOwnerPlayer();
            if (player == null) return;
            var drone2 = drone;
            NextTick(() => {
                // Delay this check to allow time for other plugins to deploy an entity to this slot.if (drone2 == null || player == null || drone2.GetSlot(TurretSlot) != null)
                return;
                if (permission.UserHasPermission(player.UserIDString, PermissionAutoDeploy)) {
                    DeployAutoTurret(drone2, player, 1);
                }
                else if (permission.UserHasPermission(player.UserIDString, PermissionDeploy) && UnityEngine.Random.Range(0, 100) < _config.TipChance) {
                    ChatMessage(player, Lang.TipDeployCommand);
                }
            }
            );
        }
        private object OnSwitchToggle(ElectricSwitch electricSwitch, BasePlayer player) {
            var turret = GetParentTurret(electricSwitch);
            if (turret == null) return null;
            var drone = GetParentDrone(turret);
            if (drone == null) return null;
            if (!player.CanBuild()) {
                // Disallow switching the turret on and off while building blocked.Effect.server.Run(CodeLockDeniedEffectPrefab, electricSwitch, 0, Vector3.zero, Vector3.forward);
                return False;
            }
            return null;
        }
        private void OnSwitchToggled(ElectricSwitch electricSwitch) {
            var turret = GetParentTurret(electricSwitch);
            if (turret == null) return;
            var drone = GetParentDrone(turret);
            if (drone == null) return;
            if (electricSwitch.IsOn()) {
                turret.InitiateStartup();
            }
            else {
                turret.InitiateShutdown();
            }
            RefreshAlarmState(drone, turret);
        }
        private object OnTurretTarget(AutoTurret turret, BaseCombatEntity target) {
            if (turret == null || target == null || GetParentDrone(turret) == null) return null;
            if (!_config.TargetAnimals && target is BaseAnimalNPC) return False;
            var basePlayer = target as BasePlayer;
            if (basePlayer != null) {
                if (!_config.TargetNPCs && basePlayer.IsNpc) return False;
                if (!_config.TargetPlayers && basePlayer.userID.IsSteamId()) return False;
                // Don't target human or NPC players in safe zones, unless they are hostile.if (basePlayer.InSafeZone() && (basePlayer.IsNpc || !basePlayer.IsHostile()))
                return False;
                return null;
            }
            return null;
        }
        // Redirect damage from the turret to the drone.private object OnEntityTakeDamage(AutoTurret turret, HitInfo info)
        {
            var drone = GetParentDrone(turret);
            if (drone == null) return null;
            drone.Hurt(info);
            HitNotify(drone, info);
            return True;
        }
        // Redirect damage from the turret switch to the drone.private object OnEntityTakeDamage(ElectricSwitch electricSwitch, HitInfo info)
        {
            var autoTurret = GetParentTurret(electricSwitch);
            if (autoTurret == null) return null;
            var drone = GetParentDrone(autoTurret);
            if (drone == null) return null;
            drone.Hurt(info);
            HitNotify(drone, info);
            return True;
        }
        private void OnEntityKill(Drone drone) {
            if (GetDroneTurret(drone)) return;
            _turretDroneTracker.Remove(drone.net.ID);
        }
        private void OnEntityKill(AutoTurret turret) {
            SphereEntity parentSphere;
            var drone = GetParentDrone(turret, out parentSphere);
            if (drone == null) return;
            var parentSphere2 = parentSphere;
            parentSphere.Invoke(() => {
                // EntityScaleManager may have already destroyed the sphere in the same frame.if (!parentSphere2.IsDestroyed)
                {
                    parentSphere2.Kill();
                }
            }
            , 0);
            _turretDroneTracker.Remove(drone.net.ID);
            var drone2 = drone;
            drone.Invoke(() => RefreshDroneSettingsProfile(drone2), 0);
        }
        private void OnEntityDeath(Drone drone) {
            if (!RCUtils.IsRCDrone(drone)) return;
            var turret = GetDroneTurret(drone);
            if (turret != null) {
                // Causing the turret to die allows its inventory to potentially be dropped.// This approach is intentionally used, as opposed to dropping the inventory
                // directly, in order to respect vanilla behavior around `turret.dropChance`, and
                // to allow other plugins to intercept the OnEntityDeath(AutoTurret) hook to kill
                // the inventory before vanilla logic drops it.turret.Die();
            }
        }
        private object CanPickupEntity(BasePlayer player, Drone drone) {
            if (CanPickupInternal(drone)) return null;
            ChatMessage(player, Lang.ErrorCannotPickupWithTurret);
            return False;
        }
        private void OnBookmarkControlStarted(ComputerStation station, BasePlayer player, string bookmarkName, Drone drone) {
            var turret = GetDroneTurret(drone);
            if (turret == null) return;
            RefreshAlarmState(drone, turret);
        }
        private void OnBookmarkControlStarted(ComputerStation station, BasePlayer player, string bookmarkName, AutoTurret turret) {
            var drone = GetParentDrone(turret);
            if (drone == null) return;
            if (!RCUtils.HasController(turret, player)) return;
            if (!HasPermissionToControl(player)) {
                RCUtils.RemoveController(turret);
                RCUtils.AddFakeViewer(turret);
                RCUtils.AddViewer(turret, player);
                RCUtils.RemoveController(turret);
                station.SetFlag(ComputerStation.Flag_HasFullControl, false);
                return;
            }
            if (RCUtils.CanControl(player, drone)) {
                RCUtils.RemoveController(drone);
                RCUtils.AddViewer(drone, player);
                DroneController.AddToDrone(drone, turret, player);
                ExposedHooks.OnBookmarkControlStarted(station, player, drone.GetIdentifier(), drone);
            }
        }
        private void OnBookmarkControlEnded(ComputerStation station, BasePlayer player, Drone drone) {
            if (drone == null) return;
            var turret = GetDroneTurret(drone);
            if (turret != null) {
                var drone2 = drone;
                var turret2 = turret;
                // Delay in case the drone is hovering.NextTick(() =>
                {
                    if (drone2 == null || turret2 == null) return;
                    RefreshAlarmState(drone2, turret2);
                }
                );
            }
        }
        private void OnBookmarkControlEnded(ComputerStation station, BasePlayer player, AutoTurret turret) {
            if (turret == null) return;
            var drone = GetParentDrone(turret);
            if (drone == null) return;
            if (!RCUtils.HasController(drone, player)) return;
            RCUtils.RemoveController(drone);
            // Notify other plugins such as Drone Hover, Limited Drone Range and Limited Drone Height.ExposedHooks.OnBookmarkControlEnded(station, player, drone);
        }
        // This hook is exposed by plugin: Remover Tool (RemoverTool).private string canRemove(BasePlayer player, Drone drone)
        {
            if (CanPickupInternal(drone)) return null;
            return GetMessage(player, Lang.ErrorCannotPickupWithTurret);
        }
        // This hook is exposed by plugin: Drone Settings (DroneSettings).private string OnDroneTypeDetermine(Drone drone)
        {
            return GetDroneTurret(drone) != null ? Name : null;
        }
#endregion
#region API
        private AutoTurret API_DeployAutoTurret(Drone drone, BasePlayer player) {
            if (GetDroneTurret(drone) != null || drone.GetSlot(TurretSlot) != null || DeployTurretWasBlocked(drone, player)) return null;
            return DeployAutoTurret(drone, player);
        }
        private NPCAutoTurret API_DeployNpcAutoTurret(Drone drone, BasePlayer player) {
            if (GetDroneTurret(drone) != null || drone.GetSlot(TurretSlot) != null || DeployNpcTurretWasBlocked(drone)) return null;
            return DeployNpcAutoTurret(drone, player);
        }
#endregion
#region Exposed Hooks
        private static class ExposedHooks {
            // Oxide hook.public static void OnBookmarkControlStarted(ComputerStation station, BasePlayer player, string name, IRemoteControllable controllable)
            {
                Interface.CallHook("OnBookmarkControlStarted", station, player, name, controllable);
            }
            // Oxide hook.public static void OnBookmarkControlEnded(ComputerStation station, BasePlayer player, IRemoteControllable controllable)
            {
                Interface.CallHook("OnBookmarkControlEnded", station, player, controllable);
            }
            // Oxide hook.public static void OnEntityBuilt(BaseEntity heldEntity, GameObject gameObject)
            {
                Interface.CallHook("OnEntityBuilt", heldEntity, gameObject);
            }
            public static object OnDroneTurretDeploy(Drone drone, BasePlayer deployer) {
                return Interface.CallHook("OnDroneTurretDeploy", drone, deployer);
            }
            public static void OnDroneTurretDeployed(Drone drone, AutoTurret turret, BasePlayer deployer) {
                Interface.CallHook("OnDroneTurretDeployed", drone, turret, deployer);
            }
            public static object OnDroneNpcTurretDeploy(Drone drone, BasePlayer deployer) {
                return Interface.CallHook("OnDroneNpcTurretDeploy", drone, deployer);
            }
            public static void OnDroneNpcTurretDeployed(Drone drone, NPCAutoTurret turret, BasePlayer deployer) {
                Interface.CallHook("OnDroneNpcTurretDeployed", drone, turret, deployer);
            }
        }
#endregion
#region Commands
        [Command("droneturret")]
        private void DroneTurretCommand(IPlayer player) {
            if (player.IsServer) return;
            var basePlayer = player.Object as BasePlayer;
            if (!basePlayer.CanInteract()) return;
            if (!VerifyPermission(player, PermissionDeploy) || !VerifyDroneFound(player, out var drone) || !VerifyCanBuild(player, drone) || !VerifyDroneHasNoTurret(player, drone) || !VerifyDroneHasSlotVacant(player, drone)) return;
            Item autoTurretPaymentItem = null;
            var conditionFraction = 1f;
            if (!player.HasPermission(PermissionDeployFree)) {
                autoTurretPaymentItem = FindPlayerAutoTurretItem(basePlayer);
                if (autoTurretPaymentItem == null) {
                    ReplyToPlayer(player, Lang.ErrorNoTurretItem);
                    return;
                }
                conditionFraction = GetItemConditionFraction(autoTurretPaymentItem);
            }
            if (DeployTurretWasBlocked(drone, basePlayer)) return;
            if (DeployAutoTurret(drone, basePlayer, conditionFraction) == null) {
                ReplyToPlayer(player, Lang.ErrorDeployFailed);
                return;
            }
            if (autoTurretPaymentItem != null) {
                UseItem(basePlayer, autoTurretPaymentItem);
            }
        }
        [Command("dronenpcturret")]
        private void DroneNpcTurretCommand(IPlayer player, string cmd, string[] args) {
            if (player.IsServer) return;
            var basePlayer = player.Object as BasePlayer;
            if (!basePlayer.CanInteract()) return;
            if (!VerifyPermission(player, PermissionDeployNpc) || !VerifyDroneFound(player, out var drone) || !VerifyCanBuild(player, drone) || !VerifyDroneHasNoTurret(player, drone) || !VerifyDroneHasSlotVacant(player, drone) || DeployNpcTurretWasBlocked(drone, basePlayer)) return;
            if (DeployNpcAutoTurret(drone, basePlayer) == null) {
                ReplyToPlayer(player, Lang.ErrorDeployFailed);
            }
        }
#endregion
#region Helper Methods - Command Checks
        private bool VerifyPermission(IPlayer player, string perm) {
            if (player.HasPermission(perm)) return true;
            ReplyToPlayer(player, Lang.ErrorNoPermission);
            return false;
        }
        private bool VerifyDroneFound(IPlayer player, out Drone drone) {
            var basePlayer = player.Object as BasePlayer;
            drone = GetLookEntity(basePlayer, 3) as Drone;
            if (drone != null && RCUtils.IsRCDrone(drone)) return true;
            ReplyToPlayer(player, Lang.ErrorNoDroneFound);
            return false;
        }
        private bool VerifyCanBuild(IPlayer player, Drone drone) {
            var basePlayer = player.Object as BasePlayer;
            if (basePlayer.CanBuild() && basePlayer.CanBuild(drone.WorldSpaceBounds())) return true;
            ReplyToPlayer(player, Lang.ErrorBuildingBlocked);
            return false;
        }
        private bool VerifyDroneHasNoTurret(IPlayer player, Drone drone) {
            if (GetDroneTurret(drone) == null) return true;
            ReplyToPlayer(player, Lang.ErrorAlreadyHasTurret);
            return false;
        }
        private bool VerifyDroneHasSlotVacant(IPlayer player, Drone drone) {
            if (drone.GetSlot(TurretSlot) == null) return true;
            ReplyToPlayer(player, Lang.ErrorIncompatibleAttachment);
            return false;
        }
#endregion
#region Helpers
        private static class RCUtils {
            public static bool IsRCDrone(Drone drone) {
                return drone is not DeliveryDrone;
            }
            public static bool HasController(IRemoteControllable controllable) {
                return controllable.ControllingViewerId.HasValue;
            }
            public static bool HasController(IRemoteControllable controllable, BasePlayer player) {
                return controllable.ControllingViewerId?.SteamId == player.userID;
            }
            public static bool HasFakeController(IRemoteControllable controllable) {
                return controllable.ControllingViewerId?.SteamId == 0;
            }
            public static bool HasRealController(IRemoteControllable controllable) {
                return controllable.ControllingViewerId.GetValueOrDefault().SteamId != 0;
            }
            public static bool CanControl(BasePlayer player, IRemoteControllable controllable) {
                return !HasRealController(controllable) || HasController(controllable, player);
            }
            public static void RemoveController(IRemoteControllable controllable) {
                var controllerId = controllable.ControllingViewerId;
                if (controllerId.HasValue) {
                    controllable.StopControl(controllerId.Value);
                }
            }
            public static bool AddViewer(IRemoteControllable controllable, BasePlayer player) {
                return controllable.InitializeControl(new CameraViewerId(player.userID, 0));
            }
            public static void RemoveViewer(IRemoteControllable controllable, BasePlayer player) {
                controllable.StopControl(new CameraViewerId(player.userID, 0));
            }
            public static bool AddFakeViewer(IRemoteControllable controllable) {
                return controllable.InitializeControl(new CameraViewerId());
            }
            public static T GetControlledEntity<T>(BasePlayer player, out ComputerStation station) where T : class {
                station = player.GetMounted() as ComputerStation;
                if ((object)station == null) return null;
                return station.currentlyControllingEnt.Get(serverside : true) as T;
            }
            public static T GetControlledEntity<T>(BasePlayer player) where T : class {
                ComputerStation station;
                return GetControlledEntity<T>(player, out station);
            }
        }
        private static bool DeployTurretWasBlocked(Drone drone, BasePlayer deployer) {
            var hookResult = ExposedHooks.OnDroneTurretDeploy(drone, deployer);
            return hookResult is false;
        }
        private static bool DeployNpcTurretWasBlocked(Drone drone, BasePlayer deployer = null) {
            var hookResult = ExposedHooks.OnDroneNpcTurretDeploy(drone, deployer);
            return hookResult is false;
        }
        private static Drone GetParentDrone(BaseEntity entity, out SphereEntity parentSphere) {
            parentSphere = entity.GetParentEntity() as SphereEntity;
            return parentSphere != null ? parentSphere.GetParentEntity() as Drone : null;
        }
        private static Drone GetParentDrone(BaseEntity entity) {
            return GetParentDrone(entity, out _);
        }
        private static AutoTurret GetDroneTurret(Drone drone) {
            return drone.GetSlot(TurretSlot) as AutoTurret;
        }
        private static T GetChildOfType<T>(BaseEntity entity, string prefabName = null) where T : BaseEntity {
            foreach (var child in entity.children) {
                var childOfType = child as T;
                if (childOfType != null && (prefabName == null || child.PrefabName == prefabName)) return childOfType;
            }
            return null;
        }
        private static IOEntity GetTurretAlarm(AutoTurret turret) {
            return GetChildOfType<IOEntity>(turret, AlarmPrefab);
        }
        private static IOEntity GetTurretLight(AutoTurret turret) {
            return GetChildOfType<IOEntity>(turret, SirenLightPrefab);
        }
        private static bool ShouldPowerAlarm(Drone drone, AutoTurret turret) {
            return drone.IsBeingControlled && (turret.booting || turret.IsOn());
        }
        private static bool CanPickupInternal(Drone drone) {
            if (!RCUtils.IsRCDrone(drone)) return true;
            var turret = GetDroneTurret(drone);
            if (turret == null) return true;
            // Prevent drone pickup while it has a turret (the turret must be removed first).// Ignores NPC turrets since they can't be picked up.return turret == null || turret is NPCAutoTurret;
        }
        private static void HitNotify(BaseEntity entity, HitInfo info) {
            var player = info.Initiator as BasePlayer;
            if (player == null) return;
            entity.ClientRPCPlayer(null, player, "HitNotify");
        }
        private static SphereEntity SpawnSphereEntity(Drone drone) {
            var sphereEntity = GameManager.server.CreateEntity(SpherePrefab, SphereEntityLocalPosition) as SphereEntity;
            if (sphereEntity == null) return null;
            SetupSphereEntity(sphereEntity);
            sphereEntity.currentRadius = TurretScale;
            sphereEntity.lerpRadius = TurretScale;
            sphereEntity.SetParent(drone);
            sphereEntity.Spawn();
            return sphereEntity;
        }
        private static void RemoveProblemComponents(BaseEntity entity) {
            foreach (var collider in entity.GetComponentsInChildren<Collider>()) {
                if (!collider.isTrigger) {
                    UnityEngine.Object.DestroyImmediate(collider);
                }
            }
            UnityEngine.Object.DestroyImmediate(entity.GetComponent<DestroyOnGroundMissing>());
            UnityEngine.Object.DestroyImmediate(entity.GetComponent<GroundWatch>());
        }
        private static void AddRigidBodyToTriggerCollider(AutoTurret turret) {
            // Without this hack, the drone's sweep test can collide with other entities using the
            // turret trigger collider, causing the drone to occasionally reduce altitude like when
            // it's close to the ground.turret.targetTrigger.GetOrAddComponent<Rigidbody>().isKinematic = true;
        }
        private static IOEntity AttachTurretAlarm(Drone drone, AutoTurret turret) {
            var turretAlarm = GameManager.server.CreateEntity(AlarmPrefab, new Vector3(0, 0.185f, 0)) as IOEntity;
            if (turretAlarm == null) return null;
            turretAlarm.pickup.enabled = false;
            turretAlarm.SetFlag(IOEntity.Flag_HasPower, ShouldPowerAlarm(drone, turret));
            RemoveProblemComponents(turretAlarm);
            HideInputsAndOutputs(turretAlarm);
            turretAlarm.SetParent(turret);
            turretAlarm.Spawn();
            return turretAlarm;
        }
        private static IOEntity AttachTurretLight(Drone drone, AutoTurret turret) {
            var turretLight = GameManager.server.CreateEntity(SirenLightPrefab, new Vector3(0, 0.3f, 0), Quaternion.Euler(180, 0, 0)) as IOEntity;
            if (turretLight == null) return null;
            turretLight.SetFlag(IOEntity.Flag_HasPower, ShouldPowerAlarm(drone, turret));
            RemoveProblemComponents(turretLight);
            HideInputsAndOutputs(turretLight);
            turretLight.SetParent(turret);
            turretLight.Spawn();
            return turretLight;
        }
        private static ElectricSwitch AttachTurretSwitch(AutoTurret autoTurret) {
            var position = autoTurret.transform.TransformPoint(TurretSwitchPosition);
            var rotation = autoTurret.transform.rotation * TurretSwitchRotation;
            var electricSwitch = GameManager.server.CreateEntity(ElectricSwitchPrefab, position, rotation) as ElectricSwitch;
            if (electricSwitch == null) return null;
            SetupTurretSwitch(electricSwitch);
            electricSwitch.Spawn();
            electricSwitch.SetParent(autoTurret, true);
            return electricSwitch;
        }
        private static void HideInputsAndOutputs(IOEntity ioEntity) {
            // Hide the inputs and outputs on the client.foreach (var input in ioEntity.inputs)
            {
                input.type = IOEntity.IOType.Generic;
            }
            foreach (var output in ioEntity.outputs) {
                output.type = IOEntity.IOType.Generic;
            }
        }
        private static void SetupTurretSwitch(ElectricSwitch electricSwitch) {
            // Damage will be processed by the drone.electricSwitch.baseProtection = null;
            electricSwitch.pickup.enabled = false;
            electricSwitch.SetFlag(IOEntity.Flag_HasPower, true);
            RemoveProblemComponents(electricSwitch);
            HideInputsAndOutputs(electricSwitch);
            if (electricSwitch.HasParent()) {
                var transform = electricSwitch.transform;
                if (transform.localPosition != TurretSwitchPosition) {
                    transform.localPosition = TurretSwitchPosition;
                    electricSwitch.InvalidateNetworkCache();
                    electricSwitch.SendNetworkUpdate_Position();
                }
            }
        }
        private static void SetupSphereEntity(SphereEntity sphereEntity) {
            sphereEntity.EnableSaving(true);
            // Fix the issue where leaving the area and returning would not recreate the sphere and its children on clients.sphereEntity.EnableGlobalBroadcast(false);
            // Needs to be called since we aren't using server side lerping.sphereEntity.transform.localScale = SphereTransformScale;
        }
        private static BaseEntity GetLookEntity(BasePlayer basePlayer, float maxDistance = 3) {
            return Physics.Raycast(basePlayer.eyes.HeadRay(), out var hit, maxDistance, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Ignore) ? hit.GetEntity() : null;
        }
        private static AutoTurret GetParentTurret(BaseEntity entity) {
            return entity.GetParentEntity() as AutoTurret;
        }
        private static void RunOnEntityBuilt(Item turretItem, AutoTurret autoTurret) {
            ExposedHooks.OnEntityBuilt(turretItem.GetHeldEntity(), autoTurret.gameObject);
        }
        private static void UseItem(BasePlayer basePlayer, Item item, int amountToConsume = 1) {
            item.UseItem(amountToConsume);
            basePlayer.Command("note.inv", item.info.itemid, -amountToConsume);
        }
        private static float GetItemConditionFraction(Item item) {
            return item.hasCondition ? item.condition / item.info.condition.max : 1.0f;
        }
        private static Item FindPlayerAutoTurretItem(BasePlayer basePlayer) {
            return basePlayer.inventory.FindItemByItemID(AutoTurretItemId);
        }
        private void RefreshDroneSettingsProfile(Drone drone) {
            DroneSettings?.Call("API_RefreshDroneProfile", drone);
        }
        private void SwitchControl(BasePlayer player, ComputerStation station, IRemoteControllable previous, IRemoteControllable next) {
            var nextEnt = next.GetEnt();
            if (nextEnt == null) return;
            station.StopControl(player);
            station.SendNetworkUpdateImmediate();
            var forcedDroneHover = false;
            var drone = previous as Drone ?? next as Drone;
            // Check for a controller, in case Drone Hover has already added a fake one.if ((object)drone != null && !RCUtils.HasController(drone))
            {
                RCUtils.AddFakeViewer(drone);
                forcedDroneHover = true;
            }
            NextTick(() => {
                if (player == null || player.IsDestroyed || station == null || station.IsDestroyed || ((previous as BaseEntity)?.IsDestroyed ?? false) || ((next as BaseEntity)?.IsDestroyed ?? false) || station.currentlyControllingEnt.IsValid(serverside : true)) {
                    if (forcedDroneHover && RCUtils.HasFakeController(drone)) {
                        RCUtils.RemoveController(drone);
                    }
                    return;
                }
                RCUtils.RemoveController(next);
                station.currentlyControllingEnt.uid = nextEnt.net.ID;
                station.currentPlayerID = player.userID;
                var isControlling = RCUtils.AddViewer(next, player);
                station.SetFlag(ComputerStation.Flag_HasFullControl, isControlling, networkupdate : false);
                station.SendNetworkUpdateImmediate();
                // station.SendControlBookmarks(player);
                station.InvokeRepeating(station.ControlCheck, 0f, 0f);
                ExposedHooks.OnBookmarkControlStarted(station, player, next.GetIdentifier(), next);
            }
            );
        }
        private bool HasPermissionToControl(BasePlayer player) {
            if (!_config.RequirePermission) return true;
            return permission.UserHasPermission(player.UserIDString, PermissionControl);
        }
        private void RegisterWithEntityScaleManager(BaseEntity entity) {
            EntityScaleManager?.Call("API_RegisterScaledEntity", entity);
        }
        private void RefreshAlarmState(Drone drone, AutoTurret turret) {
            if (_config.EnableAudioAlarm) {
                var turretAlarm = GetTurretAlarm(turret);
                if (turretAlarm != null) {
                    turretAlarm.SetFlag(IOEntity.Flag_HasPower, ShouldPowerAlarm(drone, turret));
                }
            }
            if (_config.EnableSirenLight) {
                var turretLight = GetTurretLight(turret);
                if (turretLight != null) {
                    turretLight.SetFlag(IOEntity.Flag_HasPower, ShouldPowerAlarm(drone, turret));
                }
            }
        }
        private void SetupDroneTurret(Drone drone, AutoTurret turret) {
            // Damage will be processed by the drone.turret.baseProtection = null;
            turret.sightRange = _config.TurretRange;
            turret.targetTrigger.GetComponent<SphereCollider>().radius = _config.TurretRange;
            RemoveProblemComponents(turret);
            HideInputsAndOutputs(turret);
            AddRigidBodyToTriggerCollider(turret);
            if (_config.EnableAudioAlarm) {
                var turretAlarm = GetTurretAlarm(turret);
                if (turretAlarm != null) {
                    turretAlarm.SetFlag(IOEntity.Flag_HasPower, ShouldPowerAlarm(drone, turret));
                }
                else {
                    AttachTurretAlarm(drone, turret);
                }
            }
            if (_config.EnableSirenLight) {
                var turretLight = GetTurretLight(turret);
                if (turretLight != null) {
                    turretLight.SetFlag(IOEntity.Flag_HasPower, ShouldPowerAlarm(drone, turret));
                }
                else {
                    AttachTurretLight(drone, turret);
                }
            }
            if (_config.EnableAudioAlarm || _config.EnableSirenLight) {
                var droneForClosure = drone;
                var turretForClosure = turret;
                // Delay refreshing the alarm state in case the turret is being automatically powered on.NextTick(() =>
                {
                    if (droneForClosure == null || turretForClosure == null) return;
                    RefreshAlarmState(droneForClosure, turretForClosure);
                }
                );
            }
            // Invert the localScale of the turret to compensate for the sphereEntity localScale being increased.// Without doing this, the range of the turret corresponds to the sphere scale.// This works fine for now because the only colliders remaining are triggers.// This will require a different approach if the non-trigger colliders are reintroduced.turret.transform.localScale = TurretTransformScale;
            RegisterWithEntityScaleManager(turret);
            RefreshDroneSettingsProfile(drone);
            _turretDroneTracker.Add(drone.net.ID);
        }
        private void RefreshDroneTurret(Drone drone, AutoTurret turret) {
            var sphereEntity = turret.GetParentEntity() as SphereEntity;
            if (sphereEntity == null) return;
            SetupSphereEntity(sphereEntity);
            SetupDroneTurret(drone, turret);
            var electricSwitch = turret.GetComponentInChildren<ElectricSwitch>();
            if (electricSwitch != null) {
                SetupTurretSwitch(electricSwitch);
            }
        }
        private NPCAutoTurret DeployNpcAutoTurret(Drone drone, BasePlayer deployer) {
            var sphereEntity = SpawnSphereEntity(drone);
            if (sphereEntity == null) return null;
            var turret = GameManager.server.CreateEntity(NpcAutoTurretPrefab) as NPCAutoTurret;
            if (turret == null) {
                sphereEntity.Kill();
                return null;
            }
            turret.SetParent(sphereEntity);
            turret.Spawn();
            drone.SetSlot(TurretSlot, turret);
            SetupDroneTurret(drone, turret);
            Effect.server.Run(DeployEffectPrefab, turret.transform.position);
            ExposedHooks.OnDroneNpcTurretDeployed(drone, turret, deployer);
            return turret;
        }
        private AutoTurret DeployAutoTurret(Drone drone, BasePlayer basePlayer, float conditionFraction = 1) {
            var sphereEntity = SpawnSphereEntity(drone);
            if (sphereEntity == null) return null;
            var turret = GameManager.server.CreateEntity(AutoTurretPrefab) as AutoTurret;
            if (turret == null) {
                sphereEntity.Kill();
                return null;
            }
            if (basePlayer != null) {
                turret.OwnerID = basePlayer.userID;
            }
            turret.SetFlag(IOEntity.Flag_HasPower, true);
            turret.SetParent(sphereEntity);
            turret.Spawn();
            turret.SetHealth(turret.MaxHealth() * conditionFraction);
            AttachTurretSwitch(turret);
            drone.SetSlot(TurretSlot, turret);
            SetupDroneTurret(drone, turret);
            Effect.server.Run(DeployEffectPrefab, turret.transform.position);
            ExposedHooks.OnDroneTurretDeployed(drone, turret, basePlayer);
            if (basePlayer == null) return turret;
            if (!turret.IsAuthed(basePlayer)) {
                turret.authorizedPlayers.Add(new ProtoBuf.PlayerNameID {
                    userid = basePlayer.userID, username = basePlayer.displayName
                }
                );
                turret.SendNetworkUpdate();
            }
            // Allow other plugins to detect the auto turret being deployed (e.g., to add a weapon automatically).var turretItem = FindPlayerAutoTurretItem(basePlayer);
            if (turretItem != null) {
                RunOnEntityBuilt(turretItem, turret);
            }
            else {
                // Temporarily increase the player inventory capacity to ensure there is enough space.basePlayer.inventory.containerMain.capacity++;
                var temporaryTurretItem = ItemManager.CreateByItemID(AutoTurretItemId);
                if (basePlayer.inventory.GiveItem(temporaryTurretItem)) {
                    RunOnEntityBuilt(temporaryTurretItem, turret);
                    temporaryTurretItem.RemoveFromContainer();
                }
                temporaryTurretItem.Remove();
                basePlayer.inventory.containerMain.capacity--;
            }
            return turret;
        }
        private object HandleLightToggle(BasePlayer player) {
            var turret = RCUtils.GetControlledEntity<AutoTurret>(player, out _);
            if (turret == null || !RCUtils.HasController(turret, player)) return null;
            var weapon = turret.GetAttachedWeapon();
            if (weapon == null) return null;
            weapon.SetLightsOn(!weapon.LightsOn());
            return False;
        }
        private void HandleSwapSeats(BasePlayer player) {
            var controllable = RCUtils.GetControlledEntity<IRemoteControllable>(player, out var station);
            if (controllable == null) return;
            AutoTurret turret;
            var drone = controllable as Drone;
            if (drone != null) {
                turret = GetDroneTurret(drone);
                if (turret != null && turret.IsOn() && !turret.PeacekeeperMode() && turret is not NPCAutoTurret) {
                    SwitchControl(player, station, drone, turret);
                }
                return;
            }
            turret = controllable as AutoTurret;
            if (turret != null) {
                drone = GetParentDrone(turret);
                if (drone != null) {
                    SwitchControl(player, station, turret, drone);
                }
                return;
            }
        }
#endregion
#region Dynamic Hook Subscriptions
        private class DynamicHookSubscriber<T> {
            private DroneTurrets _plugin;
            private HashSet<T> _list = new();
            private string[] _hookNames;
            public DynamicHookSubscriber(DroneTurrets plugin, params string[] hookNames) {
                _plugin = plugin;
                _hookNames = hookNames;
            }
            public void Add(T item) {
                if (_list.Add(item) && _list.Count == 1) {
                    SubscribeAll();
                }
            }
            public void Remove(T item) {
                if (_list.Remove(item) && _list.Count == 0) {
                    UnsubscribeAll();
                }
            }
            public void SubscribeAll() {
                foreach (var hookName in _hookNames) {
                    _plugin.Subscribe(hookName);
                }
            }
            public void UnsubscribeAll() {
                foreach (var hookName in _hookNames) {
                    _plugin.Unsubscribe(hookName);
                }
            }
        }
#endregion
#region Drone Controller
        private class DroneController : ListComponent<DroneController> {
            public static void AddToDrone(Drone drone, AutoTurret turret, BasePlayer player) {
                var component = drone.gameObject.GetComponent<DroneController>();
                if (component == null) {
                    component = drone.gameObject.AddComponent<DroneController>();
                    component._drone = drone;
                    component._turret = turret;
                }
                else {
                    component.enabled = true;
                }
                component._controller = player;
                component._viewerId = new CameraViewerId(player.userID, 0);
            }
            public static void DestroyAll() {
                foreach (var component in InstanceList.ToArray()) {
                    DestroyImmediate(component);
                }
            }
            private Drone _drone;
            private AutoTurret _turret;
            private BasePlayer _controller;
            private CameraViewerId _viewerId;
            private void Update() {
                if (!RCUtils.HasController(_turret, _controller) || RCUtils.GetControlledEntity<AutoTurret>(_controller) != _turret) {
                    enabled = false;
                    return;
                }
                // Optimization: Skip if there was no user input this frame.if (_controller.lastTickTime < Time.time)
                return;
                // Send only keyboard inputs to the drone.var input = _controller.serverInput;
                var originalMouseDelta = input.current.mouseDelta;
                input.current.mouseDelta = Vector3.zero;
                _drone.UserInput(input, _viewerId);
                input.current.mouseDelta = originalMouseDelta;
                if (_drone.currentInput.movement == Vector3.zero) return;
                // Rotate the drone movement direction by the turret aim direction.var worldDirection = _drone.transform.InverseTransformVector(_drone.currentInput.movement);
                var turretRotation = Quaternion.Euler(0, Quaternion.LookRotation(_turret.aimDir).eulerAngles.y, 0);
                _drone.currentInput.movement = turretRotation * worldDirection;
            }
            private void OnDestroy() {
                if (RCUtils.HasController(_drone, _controller)) {
                    RCUtils.RemoveController(_drone);
                }
            }
        }
#endregion
#region Configuration
        private class Configuration : BaseConfiguration {
            [JsonProperty("RequirePermissionToControlDroneTurrets")]
            public bool RequirePermission;
            [JsonProperty("TargetPlayers")]
            public bool TargetPlayers = true;
            [JsonProperty("TargetNPCs")]
            public bool TargetNPCs = true;
            [JsonProperty("TargetAnimals")]
            public bool TargetAnimals = true;
            [JsonProperty("EnableAudioAlarm")]
            public bool EnableAudioAlarm = false;
            [JsonProperty("EnableSirenLight")]
            public bool EnableSirenLight = false;
            [JsonProperty("TurretRange")]
            public float TurretRange = 30f;
            [JsonProperty("TipChance")]
            public int TipChance = 25;
        }
        private Configuration GetDefaultConfig() => new();
#endregion
#region Configuration Helpers
        private class BaseConfiguration {
            public string ToJson() => JsonConvert.SerializeObject(this);
            public Dictionary<string, object> ToDictionary() => JsonHelper.Deserialize(ToJson()) as Dictionary<string, object>;
        }
        private static class JsonHelper {
            public static object Deserialize(string json) => ToObject(JToken.Parse(json));
            private static object ToObject(JToken token) {
                switch (token.Type) {
                    case JTokenType.Object : return token.Children<JProperty>().ToDictionary(prop => prop.Name, prop => ToObject(prop.Value));
                    case JTokenType.Array : return token.Select(ToObject).ToList();
                    default : return ((JValue)token).Value;
                }
            }
        }
        private bool MaybeUpdateConfig(BaseConfiguration config) {
            var currentWithDefaults = config.ToDictionary();
            var currentRaw = Config.ToDictionary(x => x.Key, x => x.Value);
            return MaybeUpdateConfigDict(currentWithDefaults, currentRaw);
        }
        private bool MaybeUpdateConfigDict(Dictionary<string, object> currentWithDefaults, Dictionary<string, object> currentRaw) {
            var changed = false;
            foreach (var key in currentWithDefaults.Keys) {
                if (currentRaw.TryGetValue(key, out var currentRawValue)) {
                    var currentDictValue = currentRawValue as Dictionary<string, object>;
                    if (currentWithDefaults[key] is Dictionary<string, object> defaultDictValue) {
                        if (currentDictValue == null) {
                            currentRaw[key] = currentWithDefaults[key];
                            changed = true;
                        }
                        else if (MaybeUpdateConfigDict(defaultDictValue, currentDictValue)) changed = true;
                    }
                }
                else {
                    currentRaw[key] = currentWithDefaults[key];
                    changed = true;
                }
            }
            return changed;
        }
        protected override void LoadDefaultConfig() => _config = GetDefaultConfig();
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _config = Config.ReadObject<Configuration>();
        
// ... [Code preview truncated due to length. Full source in attached file] ...

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