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

FREE MonumentAddons : 0.18.4 0.18.4

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Facepunch;
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.Runtime.Serialization;
using System.Text.RegularExpressions;
using System.Text;
using UnityEngine;
using static IOEntity;
using static WireTool;
using Component = UnityEngine.Component;
using HumanNPCGlobal = global : : HumanNPC;
using SkullTrophyGlobal = global : : SkullTrophy;
using CustomInitializeCallback = System.Func<BasePlayer, string[], object>;
using CustomInitializeCallbackV2 = System.Func<BasePlayer, string[], System.ValueTuple<bool, object>>;
using CustomEditCallback = System.Func<BasePlayer, string[], UnityEngine.Component, Newtonsoft.Json.Linq.JObject, System.ValueTuple<bool, object>>;
using CustomSpawnCallback = System.Func<UnityEngine.Vector3, UnityEngine.Quaternion, Newtonsoft.Json.Linq.JObject, UnityEngine.Component>;
using CustomSpawnCallbackV2 = System.Func<System.Guid, UnityEngine.Component, UnityEngine.Vector3, UnityEngine.Quaternion, Newtonsoft.Json.Linq.JObject, UnityEngine.Component>;
using CustomCheckSpaceCallback = System.Func<UnityEngine.Vector3, UnityEngine.Quaternion, Newtonsoft.Json.Linq.JObject, bool>;
using CustomKillCallback = System.Action<UnityEngine.Component>;
using CustomUnloadCallback = System.Action<UnityEngine.Component>;
using CustomUpdateCallback = System.Action<UnityEngine.Component, Newtonsoft.Json.Linq.JObject>;
using CustomUpdateCallbackV2 = System.Func<UnityEngine.Component, Newtonsoft.Json.Linq.JObject, UnityEngine.Component>;
using CustomDisplayCallback = System.Action<UnityEngine.Component, Newtonsoft.Json.Linq.JObject, System.Text.StringBuilder>;
using CustomDisplayCallbackV2 = System.Action<UnityEngine.Component, Newtonsoft.Json.Linq.JObject, BasePlayer, System.Text.StringBuilder, float>;
using CustomSetDataCallback = System.Action<UnityEngine.Component, object>;
using Tuple1 = System.ValueTuple<object>;
using Tuple2 = System.ValueTuple<object, object>;
using Tuple3 = System.ValueTuple<object, object, object>;
using Tuple4 = System.ValueTuple<object, object, object, object>;
namespace Oxide.Plugins {
    [Info("Monument Addons", "WhiteThunder", "0.18.4")]
    [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 CargoShipPrefab = "assets/content/vehicles/boats/cargoship/cargoshiptest.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 | Rust.Layers.Mask.Vehicle_World;
        private static readonly Dictionary<string, string> JsonRequestHeaders = new Dictionary<string, string> {
            {
                "Content-Type", "application/json"
            }
        }
        ;
        private static readonly Dictionary<string, string> OfficialProfileNames = new string[] {
            "BarnAirwolf", "CargoShipCCTV", "FishingVillageAirwolf", "MonumentCooking", "MonumentLifts", "MonumentsRecycler", "OilRigSharks", "OutpostAirwolf", "OutpostExtended", "SafeZoneRecyclers", "TrainStationCCTV",
        }
        .ToDictionary(name => name, name => name, StringComparer.OrdinalIgnoreCase);
        private readonly HookCollection _dynamicMonumentHooks;
        private readonly ProfileStore _profileStore = new ProfileStore();
        private readonly OriginalProfileStore _originalProfileStore = new OriginalProfileStore();
        private readonly ProfileManager _profileManager;
        private readonly CoroutineManager _coroutineManager = new CoroutineManager();
        private readonly AddonComponentTracker _componentTracker = new AddonComponentTracker();
        private readonly AdapterListenerManager _adapterListenerManager;
        private readonly ControllerFactory _controllerFactory;
        private readonly CustomAddonManager _customAddonManager;
        private readonly CustomMonumentManager _customMonumentManager;
        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 ValueRotator<Color> _colorRotator = new(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 True = true;
        private readonly object False = false;
        private ItemDefinition _waterDefinition;
        private ProtectionProperties _immortalProtection;
        private ActionDebounced _saveProfileStateDebounced;
        private StringBuilder _sb = new StringBuilder();
        private HashSet<string> _deployablePrefabs = new();
        private BaseEntity[] _entityBuffer = new BaseEntity[32];
        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);
            _customMonumentManager = new CustomMonumentManager(this);
            _controllerFactory = new ControllerFactory(this);
            _monumentHelper = new MonumentHelper(this);
            _wireToolManager = new WireToolManager(this, _profileStore);
            _saveProfileStateDebounced = new ActionDebounced(timer, 1, () => {
                if (!_isLoaded) return;
                _profileStateData.Save();
            }
            );
            _dynamicMonumentHooks = new HookCollection(this, new[] {
                nameof(OnEntitySpawned)
            }
            , () => _profileManager.HasAnyEnabledDynamicMonuments );
        }
#endregion
#region Hooks
        private void Init() {
            _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);
            _dynamicMonumentHooks.Unsubscribe();
            _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();
            }
            _deployablePrefabs = DetermineAllDeployablePrefabs();
            _profileManager.ProfileStatusChanged += (_, _, _) => _dynamicMonumentHooks.Refresh();
            _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);
            _customMonumentManager.UnregisterAllForPlugin(plugin);
        }
        private void OnEntitySpawned(BaseEntity entity) {
            if (!IsDynamicMonument(entity)) return;
            var entityForClosure = entity;
            NextTick(() => {
                if (ExposedHooks.OnDynamicMonument(entityForClosure) is false) return;
                var dynamicMonument = new DynamicMonument(entityForClosure);
                _coroutineManager.StartCoroutine(_profileManager.PartialLoadForLateMonumentRoutine(dynamicMonument));
            }
            );
        }
        // This hook is exposed by plugin: Remover Tool (RemoverTool).private object canRemove(BasePlayer player, BaseEntity entity)
        {
            if (_componentTracker.IsAddonComponent(entity)) return False;
            return null;
        }
        private object CanChangeGrade(BasePlayer player, BuildingBlock block, BuildingGrade.Enum grade) {
            if (_componentTracker.IsAddonComponent(block) && !HasAdminPermission(player)) return False;
            return null;
        }
        private object CanUpdateSign(BasePlayer player, ISignage signage) {
            if (_componentTracker.IsAddonComponent(signage as BaseEntity) && !HasAdminPermission(player)) {
                ChatMessage(player, LangEntry.ErrorNoPermission);
                return False;
            }
            return null;
        }
        private void OnSignUpdated(ISignage signage, BasePlayer player) {
            if (!_componentTracker.IsAddonComponent(signage as BaseEntity, out SignController controller)) 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)
        {
            if (!_componentTracker.IsAddonComponent(signage as BaseEntity, out SignController 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 (_componentTracker.IsAddonComponent(spray)) return False;
            return null;
        }
        private void OnEntityScaled(BaseEntity entity, float scale) {
            if (!_componentTracker.IsAddonComponent(entity, out EntityController controller) || controller.EntityData.Scale == scale) return;
            controller.EntityData.Scale = scale;
            controller.StartUpdateRoutine();
            _profileStore.Save(controller.Profile);
        }
        // This hook is exposed by plugin: Telekinesis.private Component OnTelekinesisFindFailed(BasePlayer player)
        {
            if (!HasAdminPermission(player)) return null;
            return FindAdapter<TransformAdapter>(player).Adapter?.Component;
        }
        // This hook is exposed by plugin: Telekinesis.private Tuple<Component, Component> OnTelekinesisStart(BasePlayer player, BaseEntity entity)
        {
            if (!_componentTracker.IsAddonComponent(entity, out PasteAdapter adapter, out PasteController _)) return null;
            return new Tuple<Component, Component>(adapter.Component, adapter.Component);
        }
        // This hook is exposed by plugin: Telekinesis.private object CanStartTelekinesis(BasePlayer player, Component moveComponent, Component rotateComponent)
        {
            if (IsTransformAddon(moveComponent, out _) && !HasAdminPermission(player)) return False;
            return null;
        }
        // This hook is exposed by plugin: Telekinesis.private void OnTelekinesisStarted(BasePlayer player, Component moveComponent, Component rotateComponent)
        {
            if (!IsTransformAddon(moveComponent, out var adapter, out var controller) || controller is not IUpdateableController) return;
            if (adapter.Component == moveComponent || adapter.Component == rotateComponent) {
                _adapterDisplayManager.SetPlayerMovingAdapter(player, adapter);
            }
            _adapterDisplayManager.ShowAllRepeatedly(player);
            if (moveComponent is BaseEntity moveEntity && IsSpawnPointEntity(moveEntity)) {
                _adapterDisplayManager.ShowAllRepeatedly(player);
                var spawnedVehicleComponent = moveComponent.GetComponent<SpawnedVehicleComponent>();
                if (spawnedVehicleComponent != null) {
                    spawnedVehicleComponent.CancelInvoke(spawnedVehicleComponent.CheckPositionTracked);
                }
            }
        }
        // This hook is exposed by plugin: Telekinesis.private void OnTelekinesisStopped(BasePlayer player, Component moveComponent, Component rotateComponent)
        {
            if (!IsTransformAddon(moveComponent, out TransformAdapter transformAdapter, out BaseController controller) || controller is not IUpdateableController updateableController) return;
            if (player != null) {
                _adapterDisplayManager.SetPlayerMovingAdapter(player, null);
            }
            if (!transformAdapter.TryRecordUpdates(moveComponent.transform, rotateComponent.transform)) return;
            if (moveComponent is CustomSpawnPoint spawnPoint) {
                spawnPoint.MoveSpawnedInstances();
            }
            updateableController.StartUpdateRoutine();
            _profileStore.Save(controller.Profile);
            if (player != null) {
                _adapterDisplayManager.ShowAllRepeatedly(player);
                ChatMessage(player, LangEntry.SaveSuccess, controller.Adapters.Count, controller.Profile.Name);
            }
        }
        // This hook is exposed by plugin: Custom Vending Setup (CustomVendingSetup).private Dictionary<string, object> OnCustomVendingSetupDataProvider(NPCVendingMachine vendingMachine)
        {
            if (!_componentTracker.IsAddonComponent(vendingMachine, out EntityController 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) {
            return EntityScaleManager?.Call("API_ScaleEntity", entity, scale) is true;
        }
        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 args = CopyPasteArgs;
                if (pasteData.Args is {
                    Length : > 0
                }
                ) {
                    args = args.Concat(pasteData.Args).ToArray();
                }
                var result = copyPaste.Call("TryPasteFromVector3Cancellable", position, yRotation, pasteData.Filename, args, 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 API
        [HookMethod(nameof(API_IsMonumentEntity))]
        public object API_IsMonumentEntity(BaseEntity entity) {
            return ObjectCache.Get(_componentTracker.IsAddonComponent(entity));
        }
        [HookMethod(nameof(API_GetMonumentEntityGuid))]
        public object API_GetMonumentEntityGuid(BaseEntity entity) {
            if (!_componentTracker.IsAddonComponent(entity)) return null;
            var adapter = AddonComponent.GetForComponent(entity).Adapter;
            if (adapter == null) return null;
            return ObjectCache.Get(adapter.Data.Id);
        }
#endregion
#region Exposed Hooks
        private static class ExposedHooks {
            public static void OnMonumentAddonsInitialized() {
                Interface.CallHook("OnMonumentAddonsInitialized");
            }
            public static void OnMonumentEntitySpawned(BaseEntity entity, Component monument, Guid guid) {
                Interface.CallHook("OnMonumentEntitySpawned", entity, monument, ObjectCache.Get(guid));
            }
            public static void OnMonumentPrefabCreated(GameObject gameObject, Component monument, Guid guid) {
                Interface.CallHook("OnMonumentPrefabCreated", gameObject, monument, ObjectCache.Get(guid));
            }
            public static object OnDynamicMonument(BaseEntity entity) {
                return Interface.CallHook("OnDynamicMonument", entity);
            }
        }
#endregion
#region Commands
        private enum PuzzleOption {
            PlayersBlockReset, PlayerDetectionRadius, SecondsBetweenResets,
        }
        private enum SpawnGroupOption {
            Name, Color, 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) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyMonumentFinderLoaded(player) || !VerifyProfileSelected(player, out var profileController) || !VerifyValidEntityPrefabOrDeployable(player, args, out var prefabName, out var addonDefinition, out var skinId) || !VerifyLookingAtMonumentPosition(player, out var position, out var monument)) return;
            DetermineLocalTransformData(position, basePlayer, monument, out var localPosition, out var localRotationAngles, out var 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 = _config.AddonDefaults.Puzzles.ApplyTo(new PuzzleData());
                }
                addonData = entityData;
            }
            else {
                // Found a custom addon definition.if (!addonDefinition.TryInitialize(basePlayer, args.Skip(1).ToArray(), out var pluginData))
                return;
                addonData = new CustomAddonData {
                    Id = Guid.NewGuid(), AddonName = addonDefinition.AddonName, Position = localPosition, RotationAngles = localRotationAngles, SnapToTerrain = isOnTerrain,
                }
                .SetData(pluginData);
            }
            var matchingMonuments = GetMonumentsByIdentifier(monument.UniqueName);
            profileController.Profile.AddData(monument.UniqueName, addonData);
            _profileStore.Save(profileController.Profile);
            profileController.SpawnNewData(addonData, matchingMonuments);
            ReplyToPlayer(player, LangEntry.SpawnSuccess, matchingMonuments.Count, profileController.Profile.Name, monument.UniqueDisplayName);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
            if (addonData is not CustomAddonData && ShouldRecommendSpawnPoints(prefabName)) {
                ReplyToPlayer(player, LangEntry.WarningRecommendSpawnPoint);
            }
        }
        [Command("maedit")]
        private void CommandEdit(IPlayer player, string cmd, string[] args) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out CustomAddonAdapter adapter, out CustomAddonController controller, LangEntry.ErrorNoCustomAddonFound)) return;
            if (args.Length == 0) {
                ReplyToPlayer(player, LangEntry.EditSynax);
                return;
            }
            var addonDefinition = adapter.AddonDefinition;
            var addonName = addonDefinition.AddonName;
            if (addonName != args[0]) {
                ReplyToPlayer(player, LangEntry.EditErrorNoMatch, args[0]);
                return;
            }
            if (!addonDefinition.SupportsEditing) {
                ReplyToPlayer(player, LangEntry.EditErrorNotEditable, addonName);
                return;
            }
            if (!addonDefinition.TryEdit(basePlayer, args.Skip(1).ToArray(), adapter.Component, adapter.CustomAddonData.GetSerializedData(), out var data)) return;
            addonDefinition.SetData(_profileStore, controller, data);
            ReplyToPlayer(player, LangEntry.EditSuccess, addonName);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("maprefab")]
        private void CommandPrefab(IPlayer player, string cmd, string[] args) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyMonumentFinderLoaded(player) || !VerifyProfileSelected(player, out var profileController) || !VerifyValidModderPrefab(player, args, out var prefabName) || !VerifyLookingAtMonumentPosition(player, out var position, out var monument)) return;
            if (FindPrefabBaseEntity(prefabName) != null) {
                ReplyToPlayer(player, LangEntry.PrefabErrorIsEntity, prefabName);
                return;
            }
            DetermineLocalTransformData(position, basePlayer, monument, out var localPosition, out var localRotationAngles, out var isOnTerrain);
            var prefabData = new PrefabData {
                Id = Guid.NewGuid(), PrefabName = prefabName, Position = localPosition, RotationAngles = localRotationAngles, SnapToTerrain = isOnTerrain,
            }
            ;
            var matchingMonuments = GetMonumentsByIdentifier(monument.UniqueName);
            profileController.Profile.AddData(monument.UniqueName, prefabData);
            _profileStore.Save(profileController.Profile);
            profileController.SpawnNewData(prefabData, matchingMonuments);
            ReplyToPlayer(player, LangEntry.PrefabSuccess, matchingMonuments.Count, profileController.Profile.Name, monument.UniqueDisplayName);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("masave")]
        private void CommandSave(IPlayer player, string cmd, string[] args) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            if (!adapter.TryRecordUpdates()) {
                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) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out TransformAdapter adapter, out BaseController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            // Capture adapter count before killing the controller.var numAdapters = controller.Adapters.Count;
            controller.Profile.RemoveData(adapter.Data, out var monumentIdentifier);
            _dynamicMonumentHooks.Refresh();
            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);
            }
            if (controller.Data is SpawnGroupData spawnGroupData && adapter.Data is SpawnPointData spawnPointData) {
                _undoManager.AddUndo(basePlayer, new UndoKillSpawnPoint(this, profileController, monumentIdentifier, spawnGroupData, spawnPointData));
            }
            else {
                _undoManager.AddUndo(basePlayer, new UndoKill(this, profileController, monumentIdentifier, 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) {
            if (!VerifyPlayer(player, out var 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) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player)) return;
            if (args.Length < 1 || !ComputerStation.IsValidIdentifier(args[0])) {
                ReplyToPlayer(player, LangEntry.CCTVSetIdSyntax, cmd);
                return;
            }
            if (!VerifyLookingAtAdapter(player, out CCTVController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            controller.EntityData.CCTV ??= new CCTVInfo();
            var hadIdentifier = !string.IsNullOrEmpty(controller.EntityData.CCTV.RCIdentifier);
            controller.EntityData.CCTV.RCIdentifier = args[0];
            _profileStore.Save(controller.Profile);
            controller.StartUpdateRoutine();
            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) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out CCTVEntityAdapter adapter, out CCTVController 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);
            controller.EntityData.CCTV ??= new CCTVInfo();
            controller.EntityData.CCTV.Pitch = lookAngles.x;
            controller.EntityData.CCTV.Yaw = lookAngles.y;
            _profileStore.Save(controller.Profile);
            controller.StartUpdateRoutine();
            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 (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            var skullTrophy = adapter.Entity as SkullTrophyGlobal;
            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.StartUpdateRoutine();
            ReplyToPlayer(player, LangEntry.SkullNameSetSuccess, skullName, controller.Adapters.Count, controller.Profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer, immediate : !updatedSkullName);
        }
        [Command("matrophy")]
        private void CommandTrophy(IPlayer player, string cmd, string[] args) {
            T GetSubEntity<T>(Item item) where T : BaseEntity {
                var entityId = item.instanceData?.subEntity ?? new NetworkableId(0);
                if (entityId.Value == 0) return null;
                return BaseNetworkable.serverEntities.Find(entityId) as T;
            }
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            var huntingTrophy = adapter.Entity as HuntingTrophy;
            if (huntingTrophy == null) {
                ReplyToPlayer(player, LangEntry.ErrorNoSuitableAddonFound);
                return;
            }
            var heldItem = basePlayer.GetActiveItem();
            var headEntity = heldItem != null ? GetSubEntity<HeadEntity>(heldItem) : null;
            if (headEntity == null) {
                ReplyToPlayer(player, LangEntry.SetHeadNoHeadItem);
                return;
            }
            if (!huntingTrophy.CanSubmitHead(headEntity)) {
                ReplyToPlayer(player, LangEntry.SetHeadMismatch);
                return;
            }
            controller.EntityData.HeadData = HeadData.FromHeadEntity(headEntity);
            _profileStore.Save(controller.Profile);
            controller.StartUpdateRoutine();
            ReplyToPlayer(player, LangEntry.SetHeadSuccess, controller.Adapters.Count, controller.Profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("maskin")]
        private void CommandSkin(IPlayer player, string cmd, string[] args) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            if (args.Length == 0) {
                ReplyToPlayer(player, LangEntry.SkinGet, adapter.Entity.skinID, cmd);
                return;
            }
            if (!ulong.TryParse(args[0], out var skinId)) {
                ReplyToPlayer(player, LangEntry.SkinSetSyntax, cmd);
                return;
            }
            if (IsRedirectSkin(skinId, out var 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.StartUpdateRoutine();
            ReplyToPlayer(player, LangEntry.SkinSetSuccess, skinId, controller.Adapters.Count, controller.Profile.Name);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer, immediate : !updatedExistingSkin);
        }
        [Command("maflag")]
        private void CommandFlag(IPlayer player, string cmd, string[] args) {
            if (!VerifyPlayer(player, out _) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            if (args.Length == 0) {
                var notAplicableMessage = GetMessage(player.Id, LangEntry.NotApplicable);
                var currentFlags = adapter.Entity.flags == 0 ? notAplicableMessage : adapter.Entity.flags.ToString();
                var enabledFlags = adapter.EntityData.EnabledFlags == 0 ? notAplicableMessage : adapter.EntityData.EnabledFlags.ToString();
                var disabledFlags = adapter.EntityData.DisabledFlags == 0 ? notAplicableMessage : adapter.EntityData.DisabledFlags.ToString();
                ReplyToPlayer(player, LangEntry.FlagsGet, currentFlags, enabledFlags, disabledFlags);
                return;
            }
            if (!Enum.TryParse<BaseEntity.Flags>(args[0], ignoreCase : true, result : out var flag)) {
                ReplyToPlayer(player, LangEntry.FlagsSetSyntax, cmd);
                return;
            }
            var hasFlag = adapter.Entity.HasFlag(flag) ? true : adapter.EntityData.HasFlag(flag);
            hasFlag = hasFlag switch {
                true => false, false => null, null => true
            }
            ;
            adapter.EntityData.SetFlag(flag, hasFlag);
            _profileStore.Save(controller.Profile);
            controller.StartUpdateRoutine();
            ReplyToPlayer(player, hasFlag switch {
                true => LangEntry.FlagsEnableSuccess, false => LangEntry.FlagsDisableSuccess, null => LangEntry.FlagsUnsetSuccess
            }
            , flag);
        }
        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) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player) || !VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound)) return;
            var cardReader = adapter.Entity as CardReader;
            if ((object)cardReader == null) {
                ReplyToPlayer(player, LangEntry.ErrorNoSuitableAddonFound);
                return;
            }
            if (args.Length < 1 || !int.TryParse(args[0], result : out var 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.StartUpdateRoutine();
            }
            ReplyToPlayer(player, LangEntry.CardReaderSetLevelSuccess, adapter.EntityData.CardReaderLevel);
            _adapterDisplayManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("mapuzzle")]
        private void CommandPuzzle(IPlayer player, string cmd, string[] args) {
            if (!VerifyPlayer(player, out var basePlayer) || !VerifyHasPermission(player)) return;
            if (args.Length == 0) {
                SubCommandPuzzleHelp(player, cmd);
                return;
            }
            var subCommandLower = args[0].ToLower();
            switch (subCommandLower) {
                case "reset" : {
                    if (!VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController _, 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 = subCommandLower == "add";
                    if (args.Length < 2) {
                        ReplyToPlayer(player, isAdd ? LangEntry.PuzzleAddSpawnGroupSyntax : LangEntry.PuzzleRemoveSpawnGroupSyntax, cmd);
                        return;
                    }
                    if (!VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound) || !VerifyEntityComponent(player, adapter.Entity, out PuzzleReset puzzleReset, LangEntry.PuzzleNotPresent)) return;
                    if (!VerifySpawnGroupFound(player, args[1], adapter.Monument, out var 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.StartUpdateRoutine();
                    _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) {
                        _sb.Clear();
                        _sb.AppendLine(GetMessage(player.Id, LangEntry.ErrorSetSyntaxGeneric, cmd, subCommandLower));
                        _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;
                    }
                    if (!VerifyValidEnumValue(player, args[1], out PuzzleOption puzzleOption)) return;
                    if (!VerifyLookingAtAdapter(player, out EntityAdapter adapter, out EntityController controller, LangEntry.ErrorNoSuitableAddonFound) || !VerifyEntityComponent(player, adapter.Entity, out PuzzleReset puzzleReset, LangEntry.PuzzleNotPresent)) return;
                    var puzzleData = controller.EntityData.EnsurePuzzleData(puzzleReset);
                    object setValue = args[2];
                    var showImmediate = true;
                    switch (puzzleOption) {
                        case PuzzleOption.PlayersBlockReset : {
                            if (!VerifyValidBool(player, args[2], out var playerBlockReset, LangEntry.ErrorSetSyntax.Bind(cmd, PuzzleOption.PlayersBlockReset))) return;
                            puzzleData.PlayersBlockReset = playerBlockReset;
                            setValue = playerBlockReset;
                            showImmediate = false;
                            break;
                        }
                        case PuzzleOption.PlayerDetectionRadius : {
                            if (!VerifyValidFloat(player, args[2], out var playerDetectionRadius, LangEntry.ErrorSetSyntax.Bind(cmd, PuzzleOption.PlayerDetectionRadius))) return;
                            puzzleData.PlayersBlockReset = true;
                            puzzleData.PlayerDetectionRadius = playerDetectionRadius;
                            setValue = playerDetectionRadius;
                            break;
                        }
                        case PuzzleOption.SecondsBetweenResets : {
                            if (!VerifyValidFloat(player, args[2], out var secondsBetweenResets, LangEntry.ErrorSetSyntax.Bind(cmd, PuzzleOption.SecondsBetweenResets))) return;
                            puzzleData.SecondsBetweenResets = secondsBetweenResets;
                            setValue = secondsBetweenResets;
                            break;
                        }
                    }
                    controller.StartUpdateRoutine();
                    _profileStore.Save(controller.Profile);
                    ReplyToPlayer(player, LangEntry.PuzzleSetSuccess, puzzleOption, se
// ... [Code preview truncated due to length. Full source in attached file] ...

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