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

FREE WorkcartCardReaders : 0.4.1 0.4.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Core.Libraries.Covalence;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using VLB;
namespace Oxide.Plugins {
    [Info("Workcart Card Readers", "WhiteThunder", "0.4.1")]
    [Description("Adds card readers to workcarts which players must authorize on to ride.")]
    internal class WorkcartCardReaders : CovalencePlugin {
#region Fields
        [PluginReference]
        private Plugin AutomatedWorkcarts, CargoTrainEvent;
        private static WorkcartCardReaders _pluginInstance;
        private static Configuration _pluginConfig;
        private static StoredMapData _mapData;
        private const string PermissionFreeRides = "workcartcardreaders.freerides";
        private const string PermissionManageCardReaders = "workcartcardreaders.manage";
        private const string CardReaderPrefab = "assets/prefabs/io/electric/switches/cardreader.prefab";
        private const string ItemBrokenEffectPrefab = "assets/bundled/prefabs/fx/item_break.prefab";
        private const string CardReaderDeployEffectPrefab = "assets/prefabs/deployable/tuna can wall lamp/effects/tuna-can-lamp-deploy.prefab";
        private static readonly Vector3 StaticCardReaderOffset = new Vector3(0, 1.35f, 0);
        private readonly Dictionary<ulong, Timer> _playerTimers = new Dictionary<ulong, Timer>();
        private readonly Dictionary<ulong, float> _playerLastWarned = new Dictionary<ulong, float>();
        private readonly HashSet<ulong> _globallyAuthorizedPlayers = new HashSet<ulong>();
        private readonly MapCardReaderManager _mapCardReaderManager = new MapCardReaderManager();
#endregion
#region Hooks
        private void Init() {
            _pluginInstance = this;
            _mapData = StoredMapData.Load();
            permission.RegisterPermission(PermissionFreeRides, this);
            permission.RegisterPermission(PermissionManageCardReaders, this);
            Unsubscribe(nameof(OnEntitySpawned));
            Unsubscribe(nameof(OnWorkcartAutomationStarted));
            Unsubscribe(nameof(OnWorkcartAutomationStopped));
        }
        private void OnServerInitialized() {
            CheckDependencies();
            if (_mapData != null && _mapData.CardReaderPositions.Count > 0) {
                if (_pluginConfig.EnableGlobalAuthorization) {
                    _mapCardReaderManager.CreateAll();
                    Puts($"Spawned {_mapData.CardReaderPositions.Count} card readers in the map.");
                }
                else {
                    LogWarning($"Not spawning {_mapData.CardReaderPositions.Count} card reader(s) in the map because EnableGlobalAuthorization is false.");
                }
            }
            if (_pluginConfig.AddToAllWorkcarts) {
                foreach (var workcart in BaseNetworkable.serverEntities.OfType<TrainEngine>()) AddCardReader(workcart);
                Subscribe(nameof(OnEntitySpawned));
            }
            else if (_pluginConfig.AddToAutomatedWorkcarts) {
                var workcartList = GetAutomatedWorkcarts();
                if (workcartList != null) {
                    foreach (var workcart in workcartList) AddCardReader(workcart);
                }
                Subscribe(nameof(OnWorkcartAutomationStarted));
                Subscribe(nameof(OnWorkcartAutomationStopped));
            }
        }
        private void Unload() {
            _mapCardReaderManager.DestroyAll();
            foreach (var workcart in BaseNetworkable.serverEntities.OfType<TrainEngine>()) WorkcartCardReader.RemoveFromWorkcart(workcart);
            _mapData = null;
            _pluginConfig = null;
            _pluginInstance = null;
        }
        private void OnEntitySpawned(TrainEngine workcart) {
            // Delay to give other plugins a chance to save the id in order to block the hook.NextTick(() =>
            {
                if (workcart != null) AddCardReader(workcart);
            }
            );
        }
        // This hook is exposed by plugin: Automated Workcarts (AutomatedWorkcarts).private void OnWorkcartAutomationStarted(TrainEngine workcart)
        {
            AddCardReader(workcart);
        }
        // This hook is exposed by plugin: Automated Workcarts (AutomatedWorkcarts).private void OnWorkcartAutomationStopped(TrainEngine workcart)
        {
            WorkcartCardReader.RemoveFromWorkcart(workcart);
        }
        // When players board an automated workcart...private void OnEntityEnter(TriggerParent triggerParent, BasePlayer player)
        {
            var workcart = triggerParent.gameObject.ToBaseEntity() as TrainEngine;
            if (workcart == null) return;
            var workcartCardReader = WorkcartCardReader.GetForWorkcart(workcart);
            if (workcartCardReader == null || IsPlayerAuthorized(player, workcartCardReader)) return;
            // Ignore if the player is already onboard somehow (there are multiple triggers).if (HasPlayerOnBoard(workcart, player))
            return;
            NextTick(() => {
                if (workcart == null || workcartCardReader == null || player == null) return;
                DestroyExistingPlayerTimer(player);
                float lastWarned;
                if (!_playerLastWarned.TryGetValue(player.userID, out lastWarned) || Time.realtimeSinceStartup > lastWarned + 5) {
                    ChatMessage(player, Lang.WarningSwipeRequired, _pluginConfig.AllowedSecondsToSwipeBeforeEject);
                    _playerLastWarned[player.userID] = Time.realtimeSinceStartup;
                }
                _playerTimers[player.userID] = timer.Once(_pluginConfig.AllowedSecondsToSwipeBeforeEject, () => {
                    if (!IsPlayerAuthorized(player, workcartCardReader) && HasPlayerOnBoard(workcart, player)) PerformEject(workcart, player);
                    _playerTimers.Remove(player.userID);
                }
                );
            }
            );
        }
        // When players leave an automated workcart...private void OnEntityLeave(TriggerParent triggerParent, BasePlayer player)
        {
            var workcart = triggerParent.gameObject.ToBaseEntity() as TrainEngine;
            if (workcart == null) return;
            var workcartCardReader = WorkcartCardReader.GetForWorkcart(workcart);
            if (workcartCardReader == null) return;
            NextTick(() => {
                if (workcart == null || workcartCardReader == null || player == null) return;
                // Ignore if the player is still onboard somehow (there are multiple triggers).if (HasPlayerOnBoard(workcart, player))
                return;
                DestroyExistingPlayerTimer(player);
                if (IsPlayerAuthorized(player, workcartCardReader) && !permission.UserHasPermission(player.UserIDString, PermissionFreeRides)) {
                    ChatMessage(player, Lang.InfoStillAuthorized, _pluginConfig.AuthorizationGraceTimeSecondsOffWorkcart);
                    _playerTimers[player.userID] = timer.Once(_pluginConfig.AuthorizationGraceTimeSecondsOffWorkcart, () => {
                        if (DeauthorizePlayer(workcart, workcartCardReader, player)) _playerTimers.Remove(player.userID);
                    }
                    );
                }
            }
            );
        }
        // When players swipe a card reader that is static or on an automated workcart...private bool? OnCardSwipe(CardReader cardReader, Keycard keycard, BasePlayer player)
        {
            var workcart = cardReader.GetParentEntity() as TrainEngine;
            WorkcartCardReader workcartCardReader = null;
            if (!_mapCardReaderManager.IsMapCardReader(cardReader)) {
                if (workcart == null) return null;
                workcartCardReader = WorkcartCardReader.GetForWorkcart(workcart);
                if (workcartCardReader == null) return null;
            }
            var cardItem = keycard.GetItem();
            var cardConfig = _pluginConfig.FindMatchingCardConfig(keycard, cardItem);
            if (cardConfig == null) {
                ChatMessage(player, Lang.ErrorCardNotAccepted);
                Effect.server.Run(cardReader.accessDeniedEffect.resourcePath, cardReader.audioPosition.position, Vector3.up);
                return false;
            }
            Effect.server.Run(cardReader.accessGrantedEffect.resourcePath, cardReader.audioPosition.position, Vector3.up);
            if (IsPlayerAuthorized(player, workcartCardReader)) {
                ChatMessage(player, Lang.SuccessAlreadyAuthorized);
                return false;
            }
            if (!AuthorizePlayer(workcart, workcartCardReader, player)) return false;
            if (cardConfig.PercentConditionLossPerSwipe > 0f) {
                cardItem.conditionNormalized -= cardConfig.PercentConditionLossPerSwipe * 0.01f;
                if (cardItem.condition <= 0.01f) {
                    Effect.server.Run(ItemBrokenEffectPrefab, player, 0u, Vector3.zero, Vector3.zero);
                    cardItem.Remove();
                }
                else {
                    cardItem.MarkDirty();
                }
            }
            DestroyExistingPlayerTimer(player);
            if (_pluginConfig.EnableGlobalAuthorization) ChatMessage(player, Lang.SuccessAuthorizedToAllWorkcarts);
            else ChatMessage(player, Lang.SuccessAuthorizedToWorkcart);
            return false;
        }
#endregion
#region Dependencies
        private void CheckDependencies() {
            if (_pluginConfig.AddToAllWorkcarts) return;
            if (_pluginConfig.AddToAutomatedWorkcarts && AutomatedWorkcarts == null) LogError("AutomatedWorkcarts is not loaded, get it at http://umod.org.If you don't intend to use this plugin with Automated Workcarts, then set \"AddToAutomatedWorkcarts\" to false in the config and you will no longer see this message.");
        }
        private TrainEngine[] GetAutomatedWorkcarts() {
            return AutomatedWorkcarts?.Call("API_GetAutomatedWorkcarts") as TrainEngine[];
        }
        private bool IsCargoTrain(TrainEngine workcart) {
            return CargoTrainEvent?.Call("IsTrainSpecial", workcart.net.ID)?.Equals(true) ?? false;
        }
#endregion
#region API
        private bool API_AddCardReader(TrainEngine workcart) {
            if (WorkcartCardReader.GetForWorkcart(workcart) != null) return true;
            return AddCardReader(workcart);
        }
        private void API_RemoveCardReader(TrainEngine workcart) {
            WorkcartCardReader.RemoveFromWorkcart(workcart);
        }
        private bool API_HasCardReader(TrainEngine workcart) {
            return WorkcartCardReader.GetForWorkcart(workcart) != null;
        }
        private bool API_AuthorizePlayer(BasePlayer player, TrainEngine workcart) {
            WorkcartCardReader workcartCardReader = null;
            if (!_pluginConfig.EnableGlobalAuthorization) {
                workcartCardReader = WorkcartCardReader.GetForWorkcart(workcart);
                if (workcartCardReader == null) return false;
            }
            if (IsPlayerAuthorized(player, workcartCardReader)) return true;
            return AuthorizePlayer(workcart, workcartCardReader, player);
        }
        private bool API_DeauthorizePlayer(BasePlayer player, TrainEngine workcart) {
            WorkcartCardReader workcartCardReader = null;
            if (!_pluginConfig.EnableGlobalAuthorization) {
                workcartCardReader = WorkcartCardReader.GetForWorkcart(workcart);
                if (workcartCardReader == null) return false;
            }
            if (!IsPlayerAuthorized(player, workcartCardReader)) return true;
            return DeauthorizePlayer(workcart, workcartCardReader, player);
        }
        private bool API_IsPlayerAuthorized(BasePlayer player, TrainEngine workcart) {
            WorkcartCardReader workcartCardReader = null;
            if (!_pluginConfig.EnableGlobalAuthorization) {
                workcartCardReader = WorkcartCardReader.GetForWorkcart(workcart);
                if (workcartCardReader == null) return false;
            }
            return IsPlayerAuthorized(player, workcartCardReader);
        }
#endregion
#region Exposed Hooks
        private static bool AddCardReaderWasBlocked(TrainEngine workcart) {
            object hookResult = Interface.CallHook("OnWorkcartCardReaderAdd", workcart);
            return hookResult is bool && (bool)hookResult == false;
        }
        private static bool AuthorizePlayerWasBlocked(BasePlayer player, TrainEngine workcart) {
            object hookResult = Interface.CallHook("OnWorkcartPlayerAuthorize", player, workcart);
            return hookResult is bool && (bool)hookResult == false;
        }
        private static void CallHookPlayerAuthorized(BasePlayer player, TrainEngine workcart) {
            Interface.CallHook("OnWorkcartPlayerAuthorized", player, workcart);
        }
        private static bool DeauthorizePlayerWasBlocked(BasePlayer player, TrainEngine workcart) {
            object hookResult = Interface.CallHook("OnWorkcartPlayerDeauthorize", player, workcart);
            return hookResult is bool && (bool)hookResult == false;
        }
        private static void CallHookPlayerDeauthorized(BasePlayer player, TrainEngine workcart) {
            Interface.CallHook("OnWorkcartPlayerDeauthorized", player, workcart);
        }
        private static bool EjectPlayerWasBlocked(BasePlayer player, TrainEngine workcart) {
            object hookResult = Interface.CallHook("OnWorkcartPlayerEject", player, workcart);
            return hookResult is bool && (bool)hookResult == false;
        }
        private static Vector3? CallHookDetermineEjectPosition(BasePlayer player, TrainEngine workcart) {
            object hookResult = Interface.CallHook("OnWorkcartEjectPositionDetermine", player, workcart);
            return hookResult is Vector3 ? (Vector3)hookResult : (Vector3?)null;
        }
        private static void CallHookPlayerEjected(BasePlayer player, TrainEngine workcart) {
            Interface.CallHook("OnWorkcartPlayerEjected", player, workcart);
        }
#endregion
#region Commands
        [Command("wcr.spawn")]
        private void CommandSpawnCardReader(IPlayer player) {
            if (player.IsServer || !VerifyGlobalAuthorizationEnabled(player) || !VerifyPermission(player, PermissionManageCardReaders)) return;
            var basePlayer = player.Object as BasePlayer;
            RaycastHit hit;
            if (!TryRaycast(basePlayer, out hit, 10)) {
                ReplyToPlayer(player, Lang.ErrorNoSurface);
                return;
            }
            var hitVector = hit.point - basePlayer.eyes.position;
            var reflectVector = Vector3.Reflect(hitVector, hit.normal);
            var middleVector = Vector3.Lerp(-hitVector, reflectVector, 0.5f);
            var rotation = Quaternion.LookRotation(middleVector);
            _mapCardReaderManager.CreateMapCardReader(new PositionAndRotation {
                Position = hit.point - rotation * StaticCardReaderOffset, RotationAngles = rotation.eulerAngles,
            }
            );
        }
        [Command("wcr.kill")]
        private void CommandKillCardReader(IPlayer player) {
            if (player.IsServer || !VerifyGlobalAuthorizationEnabled(player) || !VerifyPermission(player, PermissionManageCardReaders)) return;
            var basePlayer = player.Object as BasePlayer;
            var cardReader = GetLookEntity(basePlayer, 10) as CardReader;
            if (cardReader == null) {
                ReplyToPlayer(player, Lang.ErrorNoCardReaderFound);
                return;
            }
            if (!_mapCardReaderManager.IsMapCardReader(cardReader)) {
                ReplyToPlayer(player, Lang.ErrorNotMapCardReader);
                return;
            }
            _mapCardReaderManager.DestroyMapCardReader(cardReader);
        }
#endregion
#region Helper Methods - Command Checks
        private bool VerifyPermission(IPlayer player, string permissionName) {
            if (player.HasPermission(permissionName)) return true;
            ReplyToPlayer(player, Lang.ErrorNoPermission);
            return false;
        }
        private bool VerifyGlobalAuthorizationEnabled(IPlayer player) {
            if (_pluginConfig.EnableGlobalAuthorization) return true;
            ReplyToPlayer(player, Lang.ErrorGlobalAuthorizationDisabled);
            return false;
        }
#endregion
#region Helper Methods
        private static bool TryRaycast(BasePlayer player, out RaycastHit hit, float maxDistance) => Physics.Raycast(player.eyes.HeadRay(), out hit, maxDistance, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Ignore);
        private static BaseEntity GetLookEntity(BasePlayer player, float maxDistance) {
            RaycastHit hit;
            return TryRaycast(player, out hit, maxDistance) ? hit.GetEntity() : null;
        }
        private static bool AddCardReader(TrainEngine workcart) {
            if (AddCardReaderWasBlocked(workcart)) return false;
            if (_pluginInstance.IsCargoTrain(workcart)) return false;
            WorkcartCardReader.AddToWorkcart(workcart);
            return true;
        }
        private static CardReader CreateCardReader(Vector3 position, Quaternion rotation, BaseEntity parent = null) {
            var reader = GameManager.server.CreateEntity(CardReaderPrefab, position, rotation) as CardReader;
            if (reader == null) return null;
            reader.SetFlag(IOEntity.Flag_HasPower, true);
            reader.accessLevel = _pluginConfig.CardReaderAccessLevel;
            reader.SetParent(parent);
            reader.EnableSaving(false);
            reader.Spawn();
            Effect.server.Run(CardReaderDeployEffectPrefab, reader.transform.position, Vector3.up);
            return reader;
        }
        private static bool HasPlayerOnBoard(TrainEngine workcart, BasePlayer player) {
            if (!workcart.platformParentTrigger.HasAnyEntityContents) return false;
            foreach (var entity in workcart.platformParentTrigger.entityContents) {
                if (player == entity) return true;
            }
            return false;
        }
        private void DestroyExistingPlayerTimer(BasePlayer player) {
            Timer timerInstance;
            if (_playerTimers.TryGetValue(player.userID, out timerInstance)) {
                timerInstance.Destroy();
                _playerTimers.Remove(player.userID);
            }
        }
        private bool IsPlayerAuthorized(BasePlayer player, WorkcartCardReader workcartCardReader) {
            if (permission.UserHasPermission(player.UserIDString, PermissionFreeRides)) return true;
            return _pluginConfig.EnableGlobalAuthorization ? _globallyAuthorizedPlayers.Contains(player.userID) : workcartCardReader.IsPlayerAuthorized(player);
        }
        private bool AuthorizePlayer(TrainEngine workcart, WorkcartCardReader workcartCardReader, BasePlayer player) {
            if (AuthorizePlayerWasBlocked(player, workcart)) return false;
            if (_pluginConfig.EnableGlobalAuthorization) _globallyAuthorizedPlayers.Add(player.userID);
            else workcartCardReader.AuthorizePlayer(player);
            CallHookPlayerAuthorized(player, workcart);
            return true;
        }
        private bool DeauthorizePlayer(TrainEngine workcart, WorkcartCardReader workcartCardReader, BasePlayer player) {
            if (DeauthorizePlayerWasBlocked(player, workcart)) return false;
            if (_pluginConfig.EnableGlobalAuthorization) _globallyAuthorizedPlayers.Remove(player.userID);
            else workcartCardReader.DeauthorizePlayer(player);
            CallHookPlayerDeauthorized(player, workcart);
            return true;
        }
        private Vector3 DetermineEjectPosition(BasePlayer player, TrainEngine workcart) {
            var overridePosition = CallHookDetermineEjectPosition(player, workcart);
            if (overridePosition != null) return (Vector3)overridePosition;
            var playerLocalPosition = workcart.transform.InverseTransformPoint(player.transform.position);
            return workcart.transform.TransformPoint(new Vector3(-2.3f, 1.34f, playerLocalPosition.z));
        }
        private void PerformEject(TrainEngine workcart, BasePlayer player) {
            if (EjectPlayerWasBlocked(player, workcart)) return;
            var ejectPosition = DetermineEjectPosition(player, workcart);
            // Remove the player from the parent trigger to unparent them before teleporting,
            // or else they may appear underwater briefly.workcart.platformParentTrigger.RemoveEntity(player);
            player.Teleport(ejectPosition);
            player.ForceUpdateTriggers();
            ChatMessage(player, Lang.InfoRemovedForNotSwiping);
            CallHookPlayerEjected(player, workcart);
        }
#endregion
#region Workcart Card Readers
        private class WorkcartCardReader : EntityComponent<TrainEngine> {
            private const float SpeedTolerance = 3;
            public static void AddToWorkcart(TrainEngine workcart) => workcart.GetOrAddComponent<WorkcartCardReader>();
            public static WorkcartCardReader GetForWorkcart(TrainEngine workcart) => workcart.GetComponent<WorkcartCardReader>();
            public static void RemoveFromWorkcart(TrainEngine workcart) => UnityEngine.Object.DestroyImmediate(workcart.gameObject.GetComponent<WorkcartCardReader>());
            private HashSet<ulong> _authorizedUsers;
            private TrainEngine _workcart;
            private float _previousSpeed;
            private CardReader[] _cardReaders;
            private void Awake() {
                if (!_pluginConfig.EnableGlobalAuthorization) _authorizedUsers = new HashSet<ulong>();
                var readerPositions = _pluginConfig.CardReaderPositions;
                _cardReaders = new CardReader[readerPositions.Length];
                for (var i = 0; i < readerPositions.Length; i++) {
                    var entry = readerPositions[i];
                    _cardReaders[i] = CreateCardReader(entry.Position, entry.Rotation, baseEntity);
                }
                _previousSpeed = baseEntity.GetTrackSpeed();
                InvokeRandomized(CheckSpeed, 1, 1, 0.1f);
            }
            public void AuthorizePlayer(BasePlayer player) => _authorizedUsers.Add(player.userID);
            public bool IsPlayerAuthorized(BasePlayer player) => _authorizedUsers.Contains(player.userID);
            public void DeauthorizePlayer(BasePlayer player) => _authorizedUsers.Remove(player.userID);
            private void CheckSpeed() {
                var trackSpeed = baseEntity.GetTrackSpeed();
                if (trackSpeed < SpeedTolerance && _previousSpeed > SpeedTolerance) {
                    foreach (var cardReader in _cardReaders) {
                        // Temporarily fix the card reader being invisible.cardReader.TerminateOnClient(BaseNetworkable.DestroyMode.None);
                        cardReader.SendNetworkUpdateImmediate();
                    }
                }
                _previousSpeed = trackSpeed;
            }
            private void OnDestroy() {
                if (_cardReaders == null) return;
                foreach (var cardReader in _cardReaders) {
                    if (cardReader != null && !cardReader.IsDestroyed) cardReader.Kill();
                }
            }
        }
#endregion
#region Map Card Readers
        private class MapCardReaderManager {
            private Dictionary<CardReader, PositionAndRotation> _spawnedMapCardReaders = new Dictionary<CardReader, PositionAndRotation>();
            public void CreateMapCardReader(PositionAndRotation positionAndRotation) {
                var cardReader = CreateCardReader(positionAndRotation.Position, positionAndRotation.Rotation);
                _spawnedMapCardReaders[cardReader] = positionAndRotation;
                _mapData.AddCardReader(positionAndRotation);
            }
            public void DestroyMapCardReader(CardReader cardReader) {
                PositionAndRotation positionAndRotation;
                if (_spawnedMapCardReaders.TryGetValue(cardReader, out positionAndRotation)) {
                    _mapData.RemoveCardReader(positionAndRotation);
                    cardReader.Kill();
                }
            }
            public bool IsMapCardReader(CardReader cardReader) => _spawnedMapCardReaders.ContainsKey(cardReader);
            public void CreateAll() {
                foreach (var positionAndRotation in _mapData.CardReaderPositions) {
                    var cardReader = CreateCardReader(positionAndRotation.Position, positionAndRotation.Rotation);
                    _spawnedMapCardReaders[cardReader] = positionAndRotation;
                }
            }
            public void DestroyAll() {
                foreach (var cardReader in _spawnedMapCardReaders.Keys) {
                    if (cardReader != null) cardReader.Kill();
                }
            }
        }
#endregion
#region Map Data
        private class StoredMapData {
            [JsonProperty("CardReaderPositions")]
            public List<PositionAndRotation> CardReaderPositions = new List<PositionAndRotation>();
            // Return example: proceduralmap.1500.548423.212
            private static string GetPerWipeSaveName() => World.SaveFileName.Substring(0, World.SaveFileName.LastIndexOf("."));
            // Return example: proceduralmap.1500.548423
            private static string GetCrossWipeSaveName() {
                var saveName = GetPerWipeSaveName();
                return saveName.Substring(0, saveName.LastIndexOf("."));
            }
            private static bool IsProcedural() => World.SaveFileName.StartsWith("proceduralmap");
            private static string GetFilepath() => IsProcedural() ? $"{_pluginInstance.Name}/{GetPerWipeSaveName()}" : $"{_pluginInstance.Name}/{GetCrossWipeSaveName()}";
            public static StoredMapData Load() {
                var filepath = GetFilepath();
                if (Interface.Oxide.DataFileSystem.ExistsDatafile(filepath)) return Interface.Oxide.DataFileSystem.ReadObject<StoredMapData>(filepath) ?? new StoredMapData();
                return new StoredMapData();
            }
            public StoredMapData Save() {
                Interface.Oxide.DataFileSystem.WriteObject(GetFilepath(), this);
                return this;
            }
            public void AddCardReader(PositionAndRotation positionAndRotation) {
                CardReaderPositions.Add(positionAndRotation);
                Save();
            }
            public void RemoveCardReader(PositionAndRotation positionAndRotation) {
                CardReaderPositions.Remove(positionAndRotation);
                Save();
            }
        }
#endregion
#region Configuration
        private class PositionAndRotation {
            [JsonProperty("Position")]
            public Vector3 Position;
            [JsonProperty("RotationAngles")]
            public Vector3 RotationAngles;
            private Quaternion? _rotation;
            [JsonIgnore]
            public Quaternion Rotation {
                get {
                    if (_rotation == null) _rotation = Quaternion.Euler(RotationAngles);
                    return (Quaternion)_rotation;
                }
            }
        }
        private class CardSettings {
            [JsonProperty("AccessLevel", DefaultValueHandling = DefaultValueHandling.Ignore)]
            public int AccessLevel;
            [JsonProperty("Skin", DefaultValueHandling = DefaultValueHandling.Ignore)]
            public ulong Skin;
            [JsonProperty("PercentConditionLossPerSwipe")]
            public int PercentConditionLossPerSwipe;
        }
        private class Configuration : SerializableConfiguration {
            [JsonProperty("AddToAllWorkcarts")]
            public bool AddToAllWorkcarts = false;
            [JsonProperty("AddToAutomatedWorkcarts")]
            public bool AddToAutomatedWorkcarts = true;
            [JsonProperty("AllowedSecondsToSwipeBeforeEject")]
            public float AllowedSecondsToSwipeBeforeEject = 10;
            [JsonProperty("EnableGlobalAuthorization")]
            public bool EnableGlobalAuthorization = false;
            [JsonProperty("AuthorizationGraceTimeSecondsOffWorkcart")]
            public float AuthorizationGraceTimeSecondsOffWorkcart = 60;
            [JsonProperty("CardReaderAccessLevel")]
            public int CardReaderAccessLevel = 1;
            [JsonProperty("AcceptedCards")]
            public CardSettings[] AcceptedCards = new CardSettings[] {
                new CardSettings {
                    AccessLevel = 1, PercentConditionLossPerSwipe = 20,
                }
                , new CardSettings {
                    AccessLevel = 2, PercentConditionLossPerSwipe = 15,
                }
                , new CardSettings {
                    AccessLevel = 3, PercentConditionLossPerSwipe = 10,
                }
                , new CardSettings {
                    Skin = 1988408422, PercentConditionLossPerSwipe = 0,
                }
                ,
            }
            ;
            [JsonProperty("CardReaderPositions")]
            public PositionAndRotation[] CardReaderPositions = new PositionAndRotation[] {
                new PositionAndRotation {
                    Position = new Vector3(0.1f, 1.4f, 1.8165f), RotationAngles = new Vector3(0, 180, 0),
                }
                ,
            }
            ;
            public CardSettings FindMatchingCardConfig(Keycard keycard, Item cardItem) {
                foreach (var cardConfig in AcceptedCards) {
                    if (cardItem.skin != 0) {
                        // The card has a skin which must match.if (cardConfig.Skin == cardItem.skin)
                        return cardConfig;
                    }
                    else if (cardConfig.AccessLevel != 0) {
                        // The card does not have a skin but has a specified access level which must match.if (cardConfig.AccessLevel == keycard.accessLevel)
                        return cardConfig;
                    }
                }
                return null;
            }
        }
        private Configuration GetDefaultConfig() => new Configuration();
#endregion
#region Configuration Boilerplate
        private class SerializableConfiguration {
            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(SerializableConfiguration 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) {
            bool changed = false;
            foreach (var key in currentWithDefaults.Keys) {
                object currentRawValue;
                if (currentRaw.TryGetValue(key, out currentRawValue)) {
                    var defaultDictValue = currentWithDefaults[key] as Dictionary<string, object>;
                    var currentDictValue = currentRawValue as Dictionary<string, object>;
                    if (defaultDictValue != null) {
                        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() => _pluginConfig = GetDefaultConfig();
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _pluginConfig = Config.ReadObject<Configuration>();
                if (_pluginConfig == null) {
                    throw new JsonException();
                }
                if (MaybeUpdateConfig(_pluginConfig)) {
                    LogWarning("Configuration appears to be outdated; updating and saving");
                    SaveConfig();
                }
            }
            catch (Exception e) {
                LogError(e.Message);
                LogWarning($"Configuration file {Name}.json is invalid; using defaults");
                LoadDefaultConfig();
            }
        }
        protected override void SaveConfig() {
            Log($"Configuration changes saved to {Name}.json");
            Config.WriteObject(_pluginConfig, true);
        }
#endregion
#region Localization
        private string GetMessage(string playerId, string messageName, params object[] args) {
            var message = lang.GetMessage(messageName, this, playerId);
            return args.Length > 0 ? string.Format(message, args) : message;
        }
        private string GetMessage(IPlayer player, string messageName, params object[] args) => GetMessage(player.Id, messageName, args);
        private string GetMessage(BasePlayer player, string messageName, params object[] args) => GetMessage(player.UserIDString, messageName, args);
        private void ReplyToPlayer(IPlayer player, string messageName, params object[] args) => player.Reply(string.Format(GetMessage(player, messageName), args));
        private void ChatMessage(BasePlayer player, string messageName, params object[] args) => player.ChatMessage(string.Format(GetMessage(player, messageName), args));
        private class Lang {
            public const string ErrorNoPermission = "Error.NoPermission";
            public const string ErrorCardNotAccepted = "Error.CardNotAccepted";
            public const string ErrorGlobalAuthorizationDisabled = "Error.GlobalAuthorizationDisabled";
            public const string ErrorNoSurface = "Error.NoSurface";
            public const string ErrorNoCardReaderFound = "Error.NoCardReaderFound";
            public const string ErrorNotMapCardReader = "Error.NotMapCardReader";
            public const string WarningSwipeRequired = "Warning.SwipeRequired";
            public const string SuccessAuthorizedToWorkcart = "Success.AuthorizedToWorkcart";
            public const string SuccessAuthorizedToAllWorkcarts = "Success.AuthorizedToAllWorkcarts";
            public const string SuccessAlreadyAuthorized = "Success.AlreadyAuthorized";
            public const string InfoStillAuthorized = "Info.StillAuthorized";
            public const string InfoRemovedForNotSwiping = "Info.RemovedForNotSwiping";
        }
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                [Lang.ErrorNoPermission]
                = "You don't have permission to do that.", [Lang.ErrorCardNotAccepted] = "Error: That card is not accepted here.", [Lang.ErrorGlobalAuthorizationDisabled] = "Error: Static card readers are not allowed while global authorizaton is disabled.", [Lang.ErrorNoSurface] = "Error: No surface.", [Lang.ErrorNoCardReaderFound] = "Error: No card reader found.", [Lang.ErrorNotMapCardReader] = "Error: Not a map card reader.", [Lang.WarningSwipeRequired] = "You have <color=#f30>{0}</color> seconds to swipe a workcart pass.", [Lang.SuccessAuthorizedToWorkcart] = "You are <color=#3f3>authorized</color> to ride this workcart.", [Lang.SuccessAuthorizedToAllWorkcarts] = "You are <color=#3f3>authorized</color> to ride all workcarts.", [Lang.SuccessAlreadyAuthorized] = "You are already <color=#3f3>authorized</color>.", [Lang.InfoStillAuthorized] = "You are still authorized for <color=#fd4>{0}</color> seconds.", [Lang.InfoRemovedForNotSwiping] = "You were removed from the workcart because you did not swipe a workcart pass in time.",
            }
            , this, "en");
        }
#endregion
    }
}

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