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

FREE MonumentAddons : 0.14.1 0.14.1

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Plugins.MonumentAddonsExtensions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using VLB;
using static IOEntity;
using static WireTool;
using CustomSpawnCallback = System.Func<UnityEngine.Vector3, UnityEngine.Quaternion, Newtonsoft.Json.Linq.JObject, UnityEngine.Component>;
using CustomKillCallback = System.Action<UnityEngine.Component>;
using CustomUpdateCallback = System.Action<UnityEngine.Component, Newtonsoft.Json.Linq.JObject>;
using CustomAddDisplayInfoCallback = System.Action<UnityEngine.Component, Newtonsoft.Json.Linq.JObject, System.Text.StringBuilder>;
using CustomSetDataCallback = System.Action<UnityEngine.Component, object>;
using System.Text.RegularExpressions;
namespace Oxide.Plugins {
    [Info("Monument Addons", "WhiteThunder", "0.14.1")]
    [Description("Allows adding entities, spawn points and more to monuments.")]
    internal class MonumentAddons : CovalencePlugin {
#region Fields
        [PluginReference]
        private Plugin CopyPaste, CustomVendingSetup, EntityScaleManager, MonumentFinder, SignArtist;
        private MonumentAddons _plugin;
        private Configuration _config;
        private StoredData _data;
        private ProfileStateData _profileStateData;
        private const float MaxRaycastDistance = 100;
        private const float TerrainProximityTolerance = 0.001f;
        private const float MaxFindDistanceSquared = 4;
        private const float ShowVanillaDuration = 60;
        private const string PermissionAdmin = "monumentaddons.admin";
        private const string WireToolPlugEffect = "assets/prefabs/tools/wire/effects/plugeffect.prefab";
        private const string CargoShipShortName = "cargoshiptest";
        private const string DefaultProfileName = "Default";
        private const string DefaultUrlPattern = "https://github.com/WheteThunger/MonumentAddons/blob/master/Profiles/{0}.json?raw=true";
        private static readonly int HitLayers = Rust.Layers.Solid | Rust.Layers.Mask.Water;
        private static readonly Dictionary<string, string> JsonRequestHeaders = new Dictionary<string, string> {
            {
                "Content-Type", "application/json"
            }
        }
        ;
        private readonly ProfileStore _profileStore = new ProfileStore();
        private readonly OriginalProfileStore _originalProfileStore = new OriginalProfileStore();
        private readonly ProfileManager _profileManager;
        private readonly CoroutineManager _coroutineManager = new CoroutineManager();
        private readonly MonumentEntityTracker _entityTracker = new MonumentEntityTracker();
        private readonly AdapterListenerManager _adapterListenerManager;
        private readonly ControllerFactory _controllerFactory;
        private readonly CustomAddonManager _customAddonManager;
        private readonly UniqueNameRegistry _uniqueNameRegistry = new UniqueNameRegistry();
        private readonly AdapterDisplayManager _adapterDisplayManager;
        private readonly MonumentHelper _monumentHelper;
        private readonly WireToolManager _wireToolManager;
        private readonly IOManager _ioManager = new IOManager();
        private readonly UndoManager _undoManager = new UndoManager();
        private readonly Color[] _distinctColors = {
            Color.HSVToRGB(0, 1, 1), Color.HSVToRGB(0.1f, 1, 1), Color.HSVToRGB(0.2f, 1, 1), Color.HSVToRGB(0.35f, 1, 1), Color.HSVToRGB(0.55f, 1, 1), Color.HSVToRGB(0.8f, 1, 1), new Color(1, 1, 1),
        }
        ;
        private readonly object False = false;
        private ItemDefinition _waterDefinition;
        private ProtectionProperties _immortalProtection;
        private ActionDebounced _saveProfileStateDebounced;
        private Coroutine _startupCoroutine;
        private bool _serverInitialized;
        private bool _isLoaded = true;
        public MonumentAddons() {
            _profileManager = new ProfileManager(this, _originalProfileStore, _profileStore);
            _adapterDisplayManager = new AdapterDisplayManager(this, _uniqueNameRegistry);
            _adapterListenerManager = new AdapterListenerManager(this);
            _customAddonManager = new CustomAddonManager(this);
            _controllerFactory = new ControllerFactory(this);
            _monumentHelper = new MonumentHelper(this);
            _wireToolManager = new WireToolManager(this, _profileStore, _entityTracker);
            _saveProfileStateDebounced = new ActionDebounced(timer, 1, () => {
                if (!_isLoaded) return;
                _profileStateData.Save();
            }
            );
        }
#endregion
#region Hooks
        private void Init() {
            _plugin = this;
            _data = StoredData.Load(_profileStore);
            _profileStateData = ProfileStateData.Load(_data);
            _config.Init();
            // Ensure the profile folder is created to avoid errors.
            _profileStore.EnsureDefaultProfile();
            permission.RegisterPermission(PermissionAdmin, this);
            Unsubscribe(nameof(OnEntitySpawned));
            _adapterListenerManager.Init();
        }
        private void OnServerInitialized() {
            _waterDefinition = ItemManager.FindItemDefinition("water");
            _immortalProtection = ScriptableObject.CreateInstance<ProtectionProperties>();
            _immortalProtection.name = "MonumentAddonsProtection";
            _immortalProtection.Add(1);
            _uniqueNameRegistry.OnServerInitialized();
            _adapterListenerManager.OnServerInitialized();
            _monumentHelper.OnServerInitialized();
            _ioManager.OnServerInitialized();
            var entitiesToKill = _profileStateData.CleanDisabledProfileState();
            if (entitiesToKill.Count > 0) {
                CoroutineManager.StartGlobalCoroutine(KillEntitiesRoutine(entitiesToKill));
            }
            if (CheckDependencies()) {
                StartupRoutine();
            }
            _serverInitialized = true;
        }
        private void Unload() {
            _coroutineManager.Destroy();
            _profileManager.UnloadAllProfiles();
            _saveProfileStateDebounced.Flush();
            _wireToolManager.Unload();
            UnityEngine.Object.Destroy(_immortalProtection);
            _isLoaded = false;
        }
        private void OnNewSave() {
            _profileStateData.Reset();
        }
        private void OnPluginLoaded(Plugin plugin) {
            // Check whether initialized to detect only late (re)loads.
            // Note: We are not dynamically subscribing to OnPluginLoaded since that interferes with [PluginReference] for some reason.
            if (_serverInitialized && plugin == MonumentFinder) {
                StartupRoutine();
            }
        }
        private void OnPluginUnloaded(Plugin plugin) {
            if (plugin.Name == Name) return;
            _customAddonManager.UnregisterAllForPlugin(plugin);
        }
        private void OnEntitySpawned(CargoShip cargoShip) {
            var cargoShipMonument = new DynamicMonument(cargoShip, isMobile : true);
            _coroutineManager.StartCoroutine(_profileManager.PartialLoadForLateMonumentRoutine(cargoShipMonument));
        }
        // This hook is exposed by plugin: Remover Tool (RemoverTool).
        private object canRemove(BasePlayer player, BaseEntity entity) {
            if (_entityTracker.IsMonumentEntity(entity)) return False;
            return null;
        }
        private object CanChangeGrade(BasePlayer player, BuildingBlock block, BuildingGrade.Enum grade) {
            if (_entityTracker.IsMonumentEntity(block) && !HasAdminPermission(player)) return False;
            return null;
        }
        private object CanUpdateSign(BasePlayer player, ISignage signage) {
            if (_entityTracker.IsMonumentEntity(signage as BaseEntity) && !HasAdminPermission(player)) {
                ChatMessage(player, LangEntry.ErrorNoPermission);
                return False;
            }
            return null;
        }
        private void OnSignUpdated(ISignage signage, BasePlayer player) {
            if (!_entityTracker.IsMonumentEntity(signage as BaseEntity)) return;
            var component = MonumentEntityComponent.GetForEntity(signage.NetworkID);
            if (component == null) return;
            var adapter = component.Adapter as SignAdapter;
            if (adapter == null) return;
            var controller = adapter.Controller as SignController;
            if (controller == null) return;
            controller.UpdateSign(signage.GetTextureCRCs());
        }
        // This hook is exposed by plugin: Sign Arist (SignArtist).
        private void OnImagePost(BasePlayer player, string url, bool raw, ISignage signage, uint textureIndex = 0) {
            SignController controller;
            if (!_entityTracker.IsMonumentEntity(signage as BaseEntity, out controller)) return;
            if (controller.EntityData.SignArtistImages == null) {
                controller.EntityData.SignArtistImages = new SignArtistImage[signage.TextureCount];
            }
            else if (controller.EntityData.SignArtistImages.Length < signage.TextureCount) {
                Array.Resize(ref controller.EntityData.SignArtistImages, signage.TextureCount);
            }
            controller.EntityData.SignArtistImages[textureIndex] = new SignArtistImage {
                Url = url, Raw = raw,
            }
            ;
            _profileStore.Save(controller.Profile);
        }
        private object OnSprayRemove(SprayCanSpray spray, BasePlayer player) {
            if (_entityTracker.IsMonumentEntity(spray)) return False;
            return null;
        }
        private void OnEntityScaled(BaseEntity entity, float scale) {
            EntityController controller;
            if (!_entityTracker.IsMonumentEntity(entity, out controller) || controller.EntityData.Scale == scale) return;
            controller.EntityData.Scale = scale;
            controller.StartHandleChangesRoutine();
            _profileStore.Save(controller.Profile);
        }
        // This hook is exposed by plugin: Telekinesis.
        private BaseEntity OnTelekinesisFindFailed(BasePlayer player) {
            if (!HasAdminPermission(player)) return null;
            return FindAdapter<EntityAdapter>(player).Adapter?.Entity;
        }
        // This hook is exposed by plugin: Telekinesis.
        private object CanStartTelekinesis(BasePlayer player, BaseEntity moveEntity) {
            if (_entityTracker.IsMonumentEntity(moveEntity) && !HasAdminPermission(player)) return False;
            return null;
        }
        // This hook is exposed by plugin: Telekinesis.
        private void OnTelekinesisStarted(BasePlayer player, BaseEntity moveEntity, BaseEntity rotateEntity) {
            if (_entityTracker.IsMonumentEntity(moveEntity)) {
                _adapterDisplayManager.ShowAllRepeatedly(player);
            }
            if (GetSpawnPointAdapter(moveEntity) != null) {
                _adapterDisplayManager.ShowAllRepeatedly(player);
                var spawnedVehicleComponent = moveEntity.GetComponent<SpawnedVehicleComponent>();
                if (spawnedVehicleComponent != null) {
                    spawnedVehicleComponent.CancelInvoke(spawnedVehicleComponent.CheckPositionTracked);
                }
            }
        }
        // This hook is exposed by plugin: Telekinesis.
        private void OnTelekinesisStopped(BasePlayer player, BaseEntity moveEntity, BaseEntity rotateEntity) {
            EntityAdapter adapter;
            EntityController controller;
            int adapterCount;
            string profileName;
            var spawnPointAdapter = GetSpawnPointAdapter(moveEntity);
            if (spawnPointAdapter != null) {
                var moveEntityTransform = moveEntity.transform;
                var moveEntityPosition = moveEntityTransform.position;
                if (!spawnPointAdapter.Monument.IsInBounds(moveEntityPosition)) return;
                var localPosition = spawnPointAdapter.Monument.InverseTransformPoint(moveEntityPosition);
                spawnPointAdapter.SpawnPointData.Position = localPosition;
                spawnPointAdapter.SpawnPointData.RotationAngles = (Quaternion.Inverse(spawnPointAdapter.Monument.Rotation) * moveEntityTransform.rotation).eulerAngles;
                spawnPointAdapter.SpawnPointData.SnapToTerrain = IsOnTerrain(moveEntityPosition);
                _profileStore.Save(spawnPointAdapter.Profile);
                var spawnGroupController = spawnPointAdapter.Controller as SpawnGroupController;
                spawnGroupController.UpdateSpawnGroups();
                adapterCount = spawnGroupController.Adapters.Count;
                profileName = spawnPointAdapter.Profile.Name;
            }
            else if (_entityTracker.IsMonumentEntity(moveEntity, out adapter, out controller)) {
                if (!adapter.TrySaveAndApplyChanges()) return;
                adapterCount = controller.Adapters.Count;
                profileName = controller.Profile.Name;
            }
            else return;
            if (player != null) {
                _adapterDisplayManager.ShowAllRepeatedly(player);
                ChatMessage(player, LangEntry.SaveSuccess, adapterCount, profileName);
            }
        }
        // This hook is exposed by plugin: Custom Vending Setup (CustomVendingSetup).
        private Dictionary<string, object> OnCustomVendingSetupDataProvider(NPCVendingMachine vendingMachine) {
            EntityController controller;
            if (!_entityTracker.IsMonumentEntity(vendingMachine, out controller)) return null;
            var vendingProfile = controller.EntityData.VendingProfile;
            if (vendingProfile == null) {
                // Check if there's one to be migrated.
                var migratedVendingProfile = MigrateVendingProfile(vendingMachine);
                if (migratedVendingProfile != null) {
                    controller.EntityData.VendingProfile = migratedVendingProfile;
                    _profileStore.Save(controller.Profile);
                    LogWarning($"Successfully migrated vending machine settings from CustomVendingSetup to MonumentAddons profile '{controller.Profile.Name}'.");
                }
            }
            return controller.GetVendingDataProvider();
        }
#endregion
#region Dependencies
        private bool CheckDependencies() {
            if (MonumentFinder == null) {
                LogError("MonumentFinder is not loaded, get it at https://umod.org.");
                return false;
            }
            return true;
        }
        private float GetEntityScale(BaseEntity entity) {
            if (EntityScaleManager == null) return 1;
            return Convert.ToSingle(EntityScaleManager?.Call("API_GetScale", entity));
        }
        private bool TryScaleEntity(BaseEntity entity, float scale) {
            var result = EntityScaleManager?.Call("API_ScaleEntity", entity, scale);
            return result is bool && (bool)result;
        }
        private void SkinSign(ISignage signage, SignArtistImage[] signArtistImages) {
            if (SignArtist == null) return;
            var apiName = signage is Signage ? "API_SkinSign" : signage is PhotoFrame ? "API_SkinPhotoFrame" : signage is CarvablePumpkin ? "API_SkinPumpkin" : null;
            if (apiName == null) {
                LogError($"Unrecognized sign type: {signage.GetType()}");
                return;
            }
            for (uint textureIndex = 0; textureIndex < signArtistImages.Length; textureIndex++) {
                var imageInfo = signArtistImages[textureIndex];
                if (imageInfo == null) continue;
                SignArtist.Call(apiName, null, signage, imageInfo.Url, imageInfo.Raw, textureIndex);
            }
        }
        private JObject MigrateVendingProfile(NPCVendingMachine vendingMachine) {
            return CustomVendingSetup?.Call("API_MigrateVendingProfile", vendingMachine) as JObject;
        }
        private void RefreshVendingProfile(NPCVendingMachine vendingMachine) {
            CustomVendingSetup?.Call("API_RefreshDataProvider", vendingMachine);
        }
        private static class PasteUtils {
            private static readonly string[] CopyPasteArgs = {
                "stability", "false", "checkplaced", "false",
            }
            ;
            private static VersionNumber _requiredVersion = new VersionNumber(4, 1, 32);
            public static bool IsCopyPasteCompatible(Plugin copyPaste) {
                return copyPaste != null && copyPaste.Version >= _requiredVersion;
            }
            public static bool DoesPasteExist(string filename) {
                return Interface.Oxide.DataFileSystem.ExistsDatafile("copypaste/" + filename);
            }
            public static Action PasteWithCancelCallback(Plugin copyPaste, PasteData pasteData, Vector3 position, float yRotation, Action<BaseEntity> onEntityPasted, Action onPasteCompleted) {
                if (copyPaste == null) return null;
                var result = copyPaste.Call("TryPasteFromVector3Cancellable", position, yRotation, pasteData.Filename, CopyPasteArgs, onPasteCompleted, onEntityPasted);
                if (!(result is ValueTuple<object, Action>)) {
                    LogError($"CopyPaste returned an unexpected response for paste \"{pasteData.Filename}\": {result}. Is CopyPaste up-to-date?");
                    return null;
                }
                var pasteResult = (ValueTuple<object, Action>)result;
                if (!true.Equals(pasteResult.Item1)) {
                    LogError($"CopyPaste returned an unexpected response for paste \"{pasteData.Filename}\": {pasteResult.Item1}.");
                    return null;
                }
                return pasteResult.Item2;
            }
        }
#endregion
#region Commands
        private enum PuzzleOption {
            PlayersBlockReset, PlayerDetectionRadius, SecondsBetweenResets,
        }
        private enum SpawnGroupOption {
            Name, MaxPopulation, RespawnDelayMin, RespawnDelayMax, SpawnPerTickMin, SpawnPerTickMax, InitialSpawn, PreventDuplicates, PauseScheduleWhileFull, RespawnWhenNearestPuzzleResets,
        }
        private enum SpawnPointOption {
            Exclusive, SnapToGround, CheckSpace, RandomRotation, RandomRadius, PlayerDetectionRadius,
        }
        [Command("maspawn")]
        private void CommandSpawn(IPlayer player, string cmd, string[] args) {
            ProfileController profileController;
            string prefabName;
            Vector3 position;
            BaseMonument monument;
            CustomAddonDefinition addonDefinition;
            ulong skinId;
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player) || !VerifyMonumentFinderLoaded(player) || !VerifyProfileSelected(player, out profileController) || !VerifyValidPrefabOrDeployable(player, args, out prefabName, out addonDefinition, out skinId) || !VerifyHitPosition(player, out position) || !VerifyAtMonument(player, position, out monument)) return;
            Vector3 localPosition;
            Vector3 localRotationAngles;
            bool isOnTerrain;
            DetermineLocalTransformData(position, basePlayer, monument, out localPosition, out localRotationAngles, out isOnTerrain);
            BaseData addonData;
            if (prefabName != null) {
                // Found a valid prefab name.
                var shortPrefabName = GetShortName(prefabName);
                if (shortPrefabName == "big_wheel") {
                    localRotationAngles.y -= 90;
                    localRotationAngles.z = 270;
                }
                else if (shortPrefabName == "boatspawner") {
                    if (position.y == TerrainMeta.WaterMap.GetHeight(position)) {
                        // Set the boatspawner to -1.5 like the vanilla ones.
                        localPosition.y -= 1.5f;
                    }
                }
                else if (shortPrefabName == "spray.decal") {
                    localRotationAngles.x += 270;
                    localRotationAngles.y -= 90;
                }
                var entityData = new EntityData {
                    Id = Guid.NewGuid(), Skin = skinId, PrefabName = prefabName, Position = localPosition, RotationAngles = localRotationAngles, SnapToTerrain = isOnTerrain,
                }
                ;
                if (shortPrefabName.StartsWith("generator.static")) {
                    entityData.Puzzle = new PuzzleData {
                        PlayersBlockReset = true, PlayerDetectionRadius = 30, SecondsBetweenResets = 1800,
                    }
                    ;
                }
                addonData = entityData;
            }
            else {
                // Found a custom addon definition.
                addonData = new CustomAddonData {
                    Id = Guid.NewGuid(), AddonName = addonDefinition.AddonName, Position = localPosition, RotationAngles = localRotationAngles, SnapToTerrain = isOnTerrain,
                }
                ;
            }
            var matchingMonuments = GetMonumentsByAliasOrShortName(monument.AliasOrShortName);
            profileController.Profile.AddData(monument.AliasOrShortName, addonData);
            _profileStore.Save(profileController.Profile);
            profileController.SpawnNewData(addonData, matchingMonuments);
            ReplyToPlayer(player, LangEntry.SpawnSuccess, matchingMonuments.Count, profileController.Profile.Name, monument.AliasOrShortName);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("masave")]
        private void CommandSave(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            EntityAdapter adapter;
            EntityController controller;
            if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            if (!adapter.TrySaveAndApplyChanges()) {
                ReplyToPlayer(player, LangEntry.SaveNothingToDo);
                return;
            }
            ReplyToPlayer(player, LangEntry.SaveSuccess, controller.Adapters.Count, controller.Profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("makill")]
        private void CommandKill(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            BaseController controller;
            TransformAdapter adapter;
            if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            // Capture adapter count before killing the controller.
            var numAdapters = controller.Adapters.Count;
            string monumentAliasOrShortName;
            controller.Profile.RemoveData(adapter.Data, out monumentAliasOrShortName);
            var profile = controller.Profile;
            _profileStore.Save(profile);
            var profileController = controller.ProfileController;
            var killRoutine = controller.Kill(adapter.Data);
            if (killRoutine != null) {
                profileController.StartCallbackRoutine(killRoutine, profileController.SetupIO);
            }
            var spawnGroupData = controller.Data as SpawnGroupData;
            var spawnPointData = adapter.Data as SpawnPointData;
            if (spawnGroupData != null && spawnPointData != null) {
                _undoManager.AddUndo(basePlayer, new UndoKillSpawnPoint(this, profileController, monumentAliasOrShortName, spawnGroupData, spawnPointData));
            }
            else {
                _undoManager.AddUndo(basePlayer, new UndoKill(this, profileController, monumentAliasOrShortName, controller.Data));
            }
            ReplyToPlayer(player, LangEntry.KillSuccess, GetAddonName(player, adapter.Data), numAdapters, profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("maundo")]
        private void CommandUndo(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            if (!_undoManager.TryUndo(basePlayer)) {
                ReplyToPlayer(player, LangEntry.UndoNotFound);
                _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
            }
        }
        [Command("masetid")]
        private void CommandSetId(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            if (args.Length < 1 || !ComputerStation.IsValidIdentifier(args[0])) {
                ReplyToPlayer(player, LangEntry.CCTVSetIdSyntax, cmd);
                return;
            }
            CCTVController controller;
            if (!VerifyLookingAtAdapter(player, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            if (controller.EntityData.CCTV == null) {
                controller.EntityData.CCTV = new CCTVInfo();
            }
            var hadIdentifier = !string.IsNullOrEmpty(controller.EntityData.CCTV.RCIdentifier);
            controller.EntityData.CCTV.RCIdentifier = args[0];
            _profileStore.Save(controller.Profile);
            controller.StartHandleChangesRoutine();
            ReplyToPlayer(player, LangEntry.CCTVSetIdSuccess, args[0], controller.Adapters.Count, controller.Profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer, immediate : hadIdentifier);
        }
        [Command("masetdir")]
        private void CommandSetDirection(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            CCTVEntityAdapter adapter;
            CCTVController controller;
            if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            var cctv = adapter.Entity as CCTV_RC;
            var direction = Vector3Ex.Direction(basePlayer.eyes.position, cctv.transform.position);
            direction = cctv.transform.InverseTransformDirection(direction);
            var lookAngles = BaseMountable.ConvertVector(Quaternion.LookRotation(direction).eulerAngles);
            if (controller.EntityData.CCTV == null) {
                controller.EntityData.CCTV = new CCTVInfo();
            }
            controller.EntityData.CCTV.Pitch = lookAngles.x;
            controller.EntityData.CCTV.Yaw = lookAngles.y;
            _profileStore.Save(controller.Profile);
            controller.StartHandleChangesRoutine();
            ReplyToPlayer(player, LangEntry.CCTVSetDirectionSuccess, controller.Adapters.Count, controller.Profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("maskull")]
        private void CommandSkull(IPlayer player, string cmd, string[] args) {
            if (player.IsServer || !VerifyHasPermission(player)) return;
            EntityController controller;
            EntityAdapter adapter;
            if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            var skullTrophy = adapter.Entity as SkullTrophy;
            if (skullTrophy == null) {
                ReplyToPlayer(player, LangEntry.ErrorNoSuitableAddonFound);
                return;
            }
            if (args.Length == 0) {
                ReplyToPlayer(player, LangEntry.SkullNameSyntax, cmd);
                return;
            }
            var skullName = args[0];
            var updatedSkullName = controller.EntityData.SkullName != skullName;
            controller.EntityData.SkullName = skullName;
            _profileStore.Save(controller.Profile);
            controller.StartHandleChangesRoutine();
            ReplyToPlayer(player, LangEntry.SkullNameSetSuccess, skullName, controller.Adapters.Count, controller.Profile.Name);
            var basePlayer = player.Object as BasePlayer;
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer, immediate : !updatedSkullName);
        }
        [Command("maskin")]
        private void CommandSkin(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            EntityAdapter adapter;
            EntityController controller;
            if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            if (args.Length == 0) {
                ReplyToPlayer(player, LangEntry.SkinGet, adapter.Entity.skinID, cmd);
                return;
            }
            ulong skinId;
            if (!ulong.TryParse(args[0], out skinId)) {
                ReplyToPlayer(player, LangEntry.SkinSetSyntax, cmd);
                return;
            }
            string alternativeShortName;
            if (IsRedirectSkin(skinId, out alternativeShortName)) {
                ReplyToPlayer(player, LangEntry.SkinErrorRedirect, skinId, alternativeShortName);
                return;
            }
            var updatedExistingSkin = (controller.EntityData.Skin == 0) != (skinId == 0);
            controller.EntityData.Skin = skinId;
            _profileStore.Save(controller.Profile);
            controller.StartHandleChangesRoutine();
            ReplyToPlayer(player, LangEntry.SkinSetSuccess, skinId, controller.Adapters.Count, controller.Profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer, immediate : !updatedExistingSkin);
        }
        private void AddProfileDescription(StringBuilder sb, IPlayer player, ProfileController profileController) {
            foreach (var summaryEntry in GetProfileSummary(player, profileController.Profile)) {
                sb.AppendLine(GetMessage(player.Id, LangEntry.ProfileDescribeItem, summaryEntry.AddonType, summaryEntry.AddonName, summaryEntry.Count, summaryEntry.MonumentName));
            }
        }
        [Command("macardlevel")]
        private void CommandLevel(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            EntityAdapter adapter;
            EntityController controller;
            if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            var cardReader = adapter.Entity as CardReader;
            if ((object)cardReader == null) {
                ReplyToPlayer(player, LangEntry.ErrorNoSuitableAddonFound);
                return;
            }
            int accessLevel;
            if (args.Length < 1 || !int.TryParse(args[0], result : out accessLevel) || accessLevel < 1 || accessLevel > 3) {
                ReplyToPlayer(player, LangEntry.CardReaderSetLevelSyntax, cmd);
                return;
            }
            if (cardReader.accessLevel != accessLevel) {
                adapter.EntityData.CardReaderLevel = (ushort)accessLevel;
                _profileStore.Save(controller.Profile);
                controller.StartHandleChangesRoutine();
            }
            ReplyToPlayer(player, LangEntry.CardReaderSetLevelSuccess, adapter.EntityData.CardReaderLevel);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("mapuzzle")]
        private void CommandPuzzle(IPlayer player, string cmd, string[] args) {
            BasePlayer basePlayer;
            if (!VerifyPlayer(player, out basePlayer) || !VerifyHasPermission(player)) return;
            if (args.Length == 0) {
                SubCommandPuzzleHelp(player, cmd);
                return;
            }
            switch (args[0].ToLower()) {
                case "reset" : {
                    EntityAdapter adapter;
                    EntityController controller;
                    if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound)) return;
                    var ioEntity = adapter.Entity as IOEntity;
                    var puzzleReset = ioEntity != null ? FindConnectedPuzzleReset(ioEntity) : null;
                    if (puzzleReset == null) {
                        ReplyToPlayer(player, LangEntry.PuzzleNotConnected, _uniqueNameRegistry.GetUniqueShortName(adapter.Entity.PrefabName));
                        return;
                    }
                    puzzleReset.DoReset();
                    puzzleReset.ResetTimer();
                    ReplyToPlayer(player, LangEntry.PuzzleResetSuccess);
                    break;
                }
                case "add" : case "remove" : {
                    var isAdd = args[0] == "add";
                    if (args.Length < 2) {
                        ReplyToPlayer(player, isAdd ? LangEntry.PuzzleAddSpawnGroupSyntax : LangEntry.PuzzleRemoveSpawnGroupSyntax, cmd);
                        return;
                    }
                    EntityAdapter adapter;
                    EntityController controller;
                    PuzzleReset puzzleReset;
                    if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound) || !VerifyEntityComponent(player, adapter.Entity, out puzzleReset, LangEntry.PuzzleNotPresent)) return;
                    SpawnGroupController spawnGroupController;
                    if (!VerifySpawnGroupFound(player, args[1], adapter.Monument, out spawnGroupController)) return;
                    var spawnGroupData = spawnGroupController.SpawnGroupData;
                    var spawnGroupId = spawnGroupData.Id;
                    var puzzleData = controller.EntityData.EnsurePuzzleData(puzzleReset);
                    if (!isAdd) {
                        puzzleData.RemoveSpawnGroupId(spawnGroupId);
                    }
                    else if (!puzzleData.HasSpawnGroupId(spawnGroupId)) {
                        puzzleData.AddSpawnGroupId(spawnGroupId);
                    }
                    controller.StartHandleChangesRoutine();
                    _profileStore.Save(controller.Profile);
                    ReplyToPlayer(player, isAdd ? LangEntry.PuzzleAddSpawnGroupSuccess : LangEntry.PuzzleRemoveSpawnGroupSuccess, spawnGroupData.Name);
                    _adapterDisplayManager.ShowAllRepeatedly(basePlayer, immediate : false);
                    break;
                }
                case "set" : {
                    if (args.Length < 3) {
                        var sb = new StringBuilder();
                        sb.AppendLine(GetMessage(player.Id, LangEntry.ErrorSetSyntaxGeneric, cmd));
                        sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleSetHelpMaxPlayersBlockReset));
                        sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleSetHelpPlayerDetectionRadius));
                        sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleSetHelpSecondsBetweenResets));
                        player.Reply(sb.ToString());
                        return;
                    }
                    PuzzleOption puzzleOption;
                    if (!VerifyValidEnumValue(player, args[1], out puzzleOption)) return;
                    EntityAdapter adapter;
                    EntityController controller;
                    PuzzleReset puzzleReset;
                    if (!VerifyLookingAtAdapter(player, out adapter, out controller, LangEntry.ErrorNoSuitableAddonFound) || !VerifyEntityComponent(player, adapter.Entity, out puzzleReset, LangEntry.PuzzleNotPresent)) return;
                    var puzzleData = controller.EntityData.EnsurePuzzleData(puzzleReset);
                    object setValue = args[2];
                    var showImmediate = true;
                    switch (puzzleOption) {
                        case PuzzleOption.PlayersBlockReset : {
                            bool playerBlockReset;
                            if (!VerifyValidBool(player, args[2], out playerBlockReset, LangEntry.ErrorSetSyntax, cmd, PuzzleOption.PlayersBlockReset)) return;
                            puzzleData.PlayersBlockReset = playerBlockReset;
                            setValue = playerBlockReset;
                            showImmediate = false;
                            break;
                        }
                        case PuzzleOption.PlayerDetectionRadius : {
                            float playerDetectionRadius;
                            if (!VerifyValidFloat(player, args[2], out playerDetectionRadius, LangEntry.ErrorSetSyntax, cmd, PuzzleOption.PlayerDetectionRadius)) return;
                            puzzleData.PlayersBlockReset = true;
                            puzzleData.PlayerDetectionRadius = playerDetectionRadius;
                            setValue = playerDetectionRadius;
                            break;
                        }
                        case PuzzleOption.SecondsBetweenResets : {
                            float secondsBetweenResets;
                            if (!VerifyValidFloat(player, args[2], out secondsBetweenResets, LangEntry.ErrorSetSyntax, cmd, PuzzleOption.SecondsBetweenResets)) return;
                            puzzleData.SecondsBetweenResets = secondsBetweenResets;
                            setValue = secondsBetweenResets;
                            break;
                        }
                    }
                    controller.StartHandleChangesRoutine();
                    _profileStore.Save(controller.Profile);
                    ReplyToPlayer(player, LangEntry.PuzzleSetSuccess, puzzleOption, setValue);
                    _adapterDisplayManager.ShowAllRepeatedly(basePlayer, immediate : showImmediate);
                    break;
                }
                default : {
                    SubCommandPuzzleHelp(player, cmd);
                    break;
                }
            }
        }
        private void SubCommandPuzzleHelp(IPlayer player, string cmd) {
            var sb = new StringBuilder();
            sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleHelpHeader, cmd));
            sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleHelpReset, cmd));
            sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleHelpSet, cmd));
            sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleHelpAdd, cmd));
            sb.AppendLine(GetMessage(player.Id, LangEntry.PuzzleHelpRemove, cmd));
            player.Reply(sb.ToString());
        }
        [Command("maprofile")]
        private void CommandProfile(IPlayer player, string cmd, string[] args) {
            if (!_serverInitialized) return;
            if (!player.IsServer && !VerifyHasPermission(player)) return;
            if (args.Length == 0) {
                SubCommandProfileHelp(player);
                return;
            }
            var basePlayer = player.Object as BasePlayer;
            switch (args[0].ToLower()) {
                case "list" : {
                    var profileList = ProfileInfo.GetList(_data, _profileManager);
                    if (profileList.Count == 0) {
                        ReplyToPlayer(player, LangEntry.ProfileListEmpty);
                        return;
                    }
                    var playerProfileName = player.IsServer ? null : _data.GetSelectedProfileName(player.Id);
                    profileList = profileList .OrderByDescending(profile => profile.Enabled && profile.Name == playerProfileName) .ThenByDescending(profile => profile.Enabled) .ThenBy(profile => profile.Name) .ToList();
                    var sb = new StringBuilder();
                    sb.AppendLine(GetMessage(player.Id, LangEntry.ProfileListHeader));
                    foreach (var profile in profileList) {
                        var messageName = profile.Enabled && profile.Name == playerProfileName ? LangEntry.ProfileListItemSelected : profile.Enabled ? LangEntry.ProfileListItemEnabled : LangEntry.ProfileListItemDisabled;
                        sb.AppendLine(GetMessage(player.Id, messageName, profile.Name, GetAuthorSuffix(player, profile.Profile?.Author)));
                    }
                    player.Reply(sb.ToString());
                    break;
                }
                case "describe" : {
                    ProfileController controller;
                    if (!VerifyProfile(player, args, out controller, LangEntry.ProfileDescribeSyntax)) return;
                    if (controller.Profile.IsEmpty()) {
                        ReplyToPlayer(player, LangEntry.ProfileEmpty, controller.Profile.Name);
                        return;
                    }
                    var sb = new StringBuilder();
                    sb.AppendLine(GetMessage(player.Id, LangEntry.ProfileDescribeHeader, controller.Profile.Name));
                    AddProfileDescription(sb, player, controller);
                    player.Reply(sb.ToString());
                    if (!player.IsServer) {
                        _adapterDisplayManager.SetPlayerProfile(basePlayer, controller);
                        _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
                    }
                    break;
                }
                case "select" : {
                    if (player.IsServer) return;
                    if (args.Length <= 1) {
                        ReplyToPlayer(player, LangEntry.ProfileSelectSyntax);
                        return;
                    }
                    ProfileController controller;
                    if (!VerifyProfile(player, args, out controller, LangEntry.ProfileSelectSyntax)) return;
                    var profile = controller.Profile;
                    var profileName = profile.Name;
                    _data.SetProfileSelected(player.Id, profileName);
                    var wasEnabled = controller.IsEnabled;
                    if (wasEnabled) {
                        // Only save if the profile is not enabled, since enabling it will already save the main data file.
                        _data.Save();
                    }
                    else {
                        Profile newProfileData;
                        if (!VerifyCanLoadProfile(player, profileName, out newProfileData)) return;
                        controller.Enable(newProfileData);
                    }
                    ReplyToPlayer(player, wasEnabled ? LangEntry.ProfileSelectSuccess : LangEntry.ProfileSelectEnableSuccess, profileName);
                    _adapterDisplayManager.SetPlayerProfile(basePlayer, controller);
                    _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
                    break;
                }
                case "create" : {
                    if (args.Length < 2) {
                        ReplyToPlayer(player, LangEntry.ProfileCreateSyntax);
                        return;
                    }
                    var newName = DynamicConfigFile.SanitizeName(args[1]);
                    if (string.IsNullOrWhiteSpace(newName)) {
                        ReplyToPlayer(player, LangEntry.ProfileCreateSyntax);
                        return;
                    }
                    if (!VerifyProfileNameAvailable(player, newName)) return;
                    var controller = _profileManager.CreateProfile(newName, basePlayer?.displayName);
                    if (!player.IsServer) {
                        _data.SetProfileSelected(player.Id, newName);
                    }
                    _data.SetProfileEnabled(newName);
                    ReplyToPlayer(player, LangEntry.ProfileCreateSuccess, controller.Profile.Name);
                    break;
                }
                case "rename" : {
                    if (args.Length < 2) {
                        ReplyToPlayer(player, LangEntry.ProfileRenameSyntax);
                        return;
                    }
                    ProfileController controller;
                    if (args.Length == 2) {
                        controller = player.IsServer ? null : _profileManager.GetPlayerProfileController(player.Id);
                        if (controller == null) {
                            ReplyToPlayer(player, LangEntry.ProfileRenameSyntax);
                            return;
                        }
                    }
                    else if (!VerifyProfileExists(player, args[1], out controller)) return;
                    string newName = DynamicConfigFile.SanitizeName(args.Length == 2 ? args[1] : args[2]);
                    if (string.IsNullOrWhiteSpace(newName)) {
                        ReplyToPlayer(player, LangEntry.ProfileRenameSyntax);
                        return;
                    }
                    if (!VerifyProfileNameAvailable(player, newName)) return;
                    // Cache the actual old name in case it was case-insensitive matched.
                    var actualOldName = controller.Profile.Name;
                    controller.Rename(newName);
                    ReplyToPlayer(player, LangEntry.ProfileRenameSuccess, actualOldName, controller.Profile.Name);
                    if (!player.IsServer) {
                        _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
                    }
                    break;
                }
                case "reload" : {
                    ProfileController controller;
                    if (!VerifyProfile(player, args, out controller, LangEntry.ProfileReloadSyntax)) return;
                    if (!controller.IsEnabled) {
                        ReplyToPlayer(player, LangEntry.ProfileNotEnabled, controller.Profile.Name);
                        return;
                    }
                    Profile newProfileData;
                    if (!VerifyCanLoadProfile(player, controller.Profile.Name, out newProfileData)) return;
                    controller.Reload(newProfileData);
                    ReplyToPlayer(player, LangEntry.ProfileReloadSuccess, controller.Profile.Name);
                    if (!player.IsServer) {
                        _adapterDisplayManager.SetPlayerProfile(basePlayer, controller);
                        _adapterDisplayManager.Show
// ... [Code preview truncated due to length. Full source in attached file] ...

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