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

FREE SpawnModularCar : 5.3.0 5.3.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Rust;
using Rust.Modular;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System.Text;

namespace Oxide.Plugins
{
    [Info("Spawn Modular Car", "WhiteThunder", "5.3.0")]
    [Description("Allows players to spawn modular cars.")]
    internal class SpawnModularCar : CovalencePlugin
    {
        #region Fields

        [PluginReference]
        private readonly Plugin MonumentFinder, VehicleDeployedLocks;

        private static SpawnModularCar _pluginInstance;
        private static Configuration _pluginConfig;

        private PluginData _pluginData;
        private CommonPresets _commonPresets;

        private const string DefaultPresetName = "default";
        private const int PresetMaxLength = 30;

        private const string PermissionSpawnSockets2 = "spawnmodularcar.spawn.2";
        private const string PermissionSpawnSockets3 = "spawnmodularcar.spawn.3";
        private const string PermissionSpawnSockets4 = "spawnmodularcar.spawn.4";

        private const string PermissionEnginePartsTier1 = "spawnmodularcar.engineparts.tier1";
        private const string PermissionEnginePartsTier2 = "spawnmodularcar.engineparts.tier2";
        private const string PermissionEnginePartsTier3 = "spawnmodularcar.engineparts.tier3";

        private const string PermissionFix = "spawnmodularcar.fix";
        private const string PermissionFetch = "spawnmodularcar.fetch";
        private const string PermissionDespawn = "spawnmodularcar.despawn";
        private const string PermissionAutoFuel = "spawnmodularcar.autofuel";
        private const string PermissionAutoCodeLock = "spawnmodularcar.autocodelock";
        private const string PermissionAutoKeyLock = "spawnmodularcar.autokeylock";
        private const string PermissionAutoStartEngine = "spawnmodularcar.autostartengine";
        private const string PermissionAutoFillTankers = "spawnmodularcar.autofilltankers";
        private const string PermissionGiveCar = "spawnmodularcar.givecar";

        private const string PermissionPresets = "spawnmodularcar.presets";
        private const string PermissionPresetLoad = "spawnmodularcar.presets.load";
        private const string PermissionCommonPresets = "spawnmodularcar.presets.common";
        private const string PermissionManageCommonPresets = "spawnmodularcar.presets.common.manage";

        private const string PrefabSockets2 = "assets/content/vehicles/modularcar/2module_car_spawned.entity.prefab";
        private const string PrefabSockets3 = "assets/content/vehicles/modularcar/3module_car_spawned.entity.prefab";
        private const string PrefabSockets4 = "assets/content/vehicles/modularcar/4module_car_spawned.entity.prefab";

        private const string ItemDropPrefab = "assets/prefabs/misc/item drop/item_drop.prefab";

        private const string RepairEffectPrefab = "assets/bundled/prefabs/fx/build/promote_toptier.prefab";
        private const string TankerFilledEffectPrefab = "assets/prefabs/food/water jug/effects/water-jug-fill-container.prefab";

        // These layers are used to preventing spawning inside walls or players.private const int BoxcastLayers = Layers.Mask.Default
            + Layers.Mask.Deployed
            + Layers.Mask.Player_Server
            + Layers.Mask.AI
            + Layers.Mask.Vehicle_Detailed
            + Layers.Mask.Vehicle_World
            + Layers.Mask.World
            + Layers.Mask.Construction
            + Layers.Mask.Tree;

        // These layers are used to find a surface to spawn on.private const int RaycastLayers = Layers.Mask.Default
            + Layers.Mask.Terrain
            + Layers.World
            + Layers.Mask.Construction;

        private static readonly Vector3 ShortCarExtents = new(1, 1.1f, 1.5f);
        private static readonly Vector3 MediumCarExtents = new(1, 1.1f, 2.3f);
        private static readonly Vector3 LongCarExtents = new(1, 1.1f, 3);

        private static readonly Vector3 ShortCarFrontLeft = new(ShortCarExtents.x, 0, ShortCarExtents.z);
        private static readonly Vector3 ShortCarFrontRight = new(-ShortCarExtents.x, 0, ShortCarExtents.z);
        private static readonly Vector3 ShortCarBackLeft = new(ShortCarExtents.x, 0, -ShortCarExtents.z);
        private static readonly Vector3 ShortCarBackRight = new(-ShortCarExtents.x, 0, -ShortCarExtents.z);

        private static readonly Vector3 MediumCarFrontLeft = new(MediumCarExtents.x, 0, MediumCarExtents.z);
        private static readonly Vector3 MediumCarFrontRight = new(-MediumCarExtents.x, 0, MediumCarExtents.z);
        private static readonly Vector3 MediumCarBackLeft = new(MediumCarExtents.x, 0, -MediumCarExtents.z);
        private static readonly Vector3 MediumCarBackRight = new(-MediumCarExtents.x, 0, -MediumCarExtents.z);

        private static readonly Vector3 LongCarFrontLeft = new(LongCarExtents.x, 0, LongCarExtents.z);
        private static readonly Vector3 LongCarFrontRight = new(-LongCarExtents.x, 0, LongCarExtents.z);
        private static readonly Vector3 LongCarBackLeft = new(LongCarExtents.x, 0, -LongCarExtents.z);
        private static readonly Vector3 LongCarBackRight = new(-LongCarExtents.x, 0, -LongCarExtents.z);

        private static readonly float ForwardRaycastDistance = 1.5f + ShortCarExtents.x;
        private const float DownwardRaycastDistance = 4;

        private readonly RaycastHit[] _raycastBuffer = new RaycastHit[1];

        private readonly Dictionary<string, PlayerConfig> _playerConfigsMap = new();

        #endregion

        #region Hooks

        private void Init()
        {
            _pluginInstance = this;

            _pluginData = PluginData.LoadData();
            _commonPresets = CommonPresets.LoadData(_pluginData);

            MigrateConfig();

            permission.RegisterPermission(PermissionSpawnSockets2, this);
            permission.RegisterPermission(PermissionSpawnSockets3, this);
            permission.RegisterPermission(PermissionSpawnSockets4, this);

            permission.RegisterPermission(PermissionEnginePartsTier1, this);
            permission.RegisterPermission(PermissionEnginePartsTier2, this);
            permission.RegisterPermission(PermissionEnginePartsTier3, this);

            permission.RegisterPermission(PermissionFix, this);
            permission.RegisterPermission(PermissionFetch, this);
            permission.RegisterPermission(PermissionDespawn, this);
            permission.RegisterPermission(PermissionAutoFuel, this);
            permission.RegisterPermission(PermissionAutoCodeLock, this);
            permission.RegisterPermission(PermissionAutoKeyLock, this);
            permission.RegisterPermission(PermissionAutoStartEngine, this);
            permission.RegisterPermission(PermissionAutoFillTankers, this);
            permission.RegisterPermission(PermissionGiveCar, this);

            permission.RegisterPermission(PermissionPresets, this);
            permission.RegisterPermission(PermissionPresetLoad, this);
            permission.RegisterPermission(PermissionCommonPresets, this);
            permission.RegisterPermission(PermissionManageCommonPresets, this);
        }

        private void OnServerInitialized()
        {
            if (_pluginConfig.HasMonumentRestriction && MonumentFinder == null)
            {
                LogWarning("The Monument Finder plugin is not loaded, so monument restrictions will not work.If you don't want monument restrictions, set \"DisallowedMonuments\": [] in the config to stop seeing this warning.");
            }
        }

        private void Unload()
        {
            _pluginInstance = null;
            _pluginConfig = null;
        }

        private void OnNewSave(string filename)
        {
            _pluginData.PlayerCars.Clear();
            _pluginData.Cooldowns.ClearAll();
            _pluginData.SaveData();
        }

        private void OnEntityKill(ModularCar car)
        {
            if (!IsPlayerCar(car))
                return;

            var userId = _pluginData.PlayerCars.FirstOrDefault(x => x.Value == car.net.ID.Value).Key;
            var player = BasePlayer.Find(userId);

            if (player != null)
                ChatMessage(player, "Generic.Info.CarDestroyed");

            _pluginData.UnregisterCar(userId);
        }

        private void OnEngineStarted(ModularCar car, BasePlayer player)
        {
            if (car == null
                || car.OwnerID == 0
                || !_pluginData.PlayerCars.ContainsValue(car.net.ID.Value)
                || !permission.UserHasPermission(car.OwnerID.ToString(), PermissionAutoStartEngine))
                return;

            if (car.engineController.IsStarting)
            {
                car.CancelInvoke(car.engineController.FinishStartingEngine);
                car.engineController.FinishStartingEngine();
            }
        }

        #endregion

        #region API

        private static class ApiParser
        {
            public static string CodeLockField = "CodeLock";
            public static string KeyLockField = "KeyLock";
            public static string EnginePartsTierField = "EnginePartsTier";
            public static string FreshWaterAmountField = "FreshWaterAmount";
            public static string FuelAmountField = "FuelAmount";
            public static string ModulesField = "Modules";

            public static bool TryParseOptions(Dictionary<string, object> options, out PresetCarOptions presetOptions)
            {
                var codeLock = BoolOption(options, CodeLockField);
                var keyLock = BoolOption(options, KeyLockField);
                var enginePartsTier = IntOption(options, EnginePartsTierField);
                var freshWaterAmount = IntOption(options, FreshWaterAmountField);
                var fuelAmount = IntOption(options, FuelAmountField);
                var moduleIDs = ParseModulesOption(options);

                presetOptions = null;

                if (moduleIDs == null)
                {
                    _pluginInstance.LogError($"[API] '{ApiParser.ModulesField}' field is missing or unrecognizable.");
                    return false;
                }

                if (moduleIDs.Length is < 2 or > 4)
                {
                    _pluginInstance.LogError($"[API] Requested a car with {moduleIDs.Length} sockets, but only 2-4 sockets is supported.");
                    return false;
                }

                presetOptions = new PresetCarOptions
                {
                    CodeLock = codeLock,
                    KeyLock = keyLock,
                    EnginePartsTier = enginePartsTier,
                    FreshWaterAmount = freshWaterAmount,
                    FuelAmount = fuelAmount,
                    NormalizedModuleIDs = moduleIDs
                };
                return true;
            }

            private static bool BoolOption(Dictionary<string, object> options, string name)
            {
                return options.TryGetValue(name, out var value) && value is true;
            }

            private static int IntOption(Dictionary<string, object> options, string name)
            {
                return options.TryGetValue(name, out var value) && value is int i
                    ? i
                    : 0;
            }

            public static int[] ParseModulesOption(Dictionary<string, object> options)
            {
                if (!options.ContainsKey(ModulesField))
                    return null;

                if (options[ModulesField] is not object[] moduleArray)
                    return null;

                return _pluginInstance.ValidateModules(moduleArray);
            }
        }

        private ModularCar API_SpawnPreset(Dictionary<string, object> options, BasePlayer player, Vector3 position, Quaternion rotation)
        {
            if (!ApiParser.TryParseOptions(options, out var presetOptions))
                return null;

            if (SpawnWasBlocked(player))
                return null;

            if (position == Vector3.zero && player != null)
                DetermineCarPositionAndRotation(player, presetOptions.Length, out position, out rotation);

            return SpawnCar(presetOptions, position, rotation, player, shouldTrackCar: false);
        }

        private ModularCar API_SpawnNamedPreset(string presetName, BasePlayer player, Vector3 position, Quaternion rotation)
        {
            var presetOptions = _pluginConfig.FindPreset(presetName)?.Options;
            if (presetOptions == null)
            {
                LogError($"[API] Server preset '{presetName}' not found.");
                return null;
            }

            if (presetOptions.Length is < 2 or > 4)
            {
                LogError($"[API] Requested a car with {presetOptions.Length} sockets, but only 2-4 sockets is supported.");
                return null;
            }

            if (SpawnWasBlocked(player))
                return null;

            if (position == Vector3.zero && player != null)
                DetermineCarPositionAndRotation(player, presetOptions.Length, out position, out rotation);

            return SpawnCar(presetOptions, position, rotation, player, shouldTrackCar: false);
        }

        private ModularCar API_SpawnPresetCar(BasePlayer player, Dictionary<string, object> options, Action<ModularCar> onReady = null)
        {
            if (!ApiParser.TryParseOptions(options, out var presetOptions))
                return null;

            if (SpawnWasBlocked(player))
                return null;

            if (!TryGetIdealCarPositionAndRotation(player, presetOptions.Length, out var spawnPosition, out var rotation))
            {
                spawnPosition = GetFixedCarPosition(player);
                rotation = GetRelativeCarRotation(player);
            }

            var car = SpawnCar(presetOptions, spawnPosition, rotation, player, shouldTrackCar: false);
            if (car != null)
            {
                // Note: Consumers no longer need to use this callback since this plugin now forces synchronous module registration.onReady?.Invoke(car);
            }

            return car;
        }

        #endregion

        #region Commands

        [Command("givecar")]
        private void SpawnCarServerCommand(IPlayer player, string cmd, string[] args)
        {
            if (!player.IsServer && !VerifyPermissionAny(player, PermissionGiveCar))
                return;

            if (args.Length < 2)
            {
                ReplyToPlayer(player, "Command.Give.Error.Syntax");
                return;
            }

            var playerNameOrIdArg = args[0];
            var presetNameArg = args[1];

            var targetPlayer = BasePlayer.Find(playerNameOrIdArg);
            if (targetPlayer == null)
            {
                ReplyToPlayer(player, "Command.Give.Error.PlayerNotFound", playerNameOrIdArg);
                return;
            }

            var preset = _pluginConfig.FindPreset(presetNameArg);
            if (preset == null)
            {
                ReplyToPlayer(player, "Generic.Error.PresetNotFound", presetNameArg);
                return;
            }

            var carOptions = preset.Options;
            if (carOptions.Length < 2)
            {
                ReplyToPlayer(player, "Command.Give.Error.PresetTooFewModules", preset.Name, carOptions.Length);
                return;
            }
            if (carOptions.Length > 4)
            {
                ReplyToPlayer(player, "Command.Give.Error.PresetTooManyModules", preset.Name, carOptions.Length);
                return;
            }

            if (!TryGetIdealCarPositionAndRotation(targetPlayer, preset.Options.Length, out var spawnPosition, out var rotation))
            {
                spawnPosition = GetFixedCarPosition(targetPlayer);
                rotation = GetRelativeCarRotation(targetPlayer);
            }

            var car = SpawnCar(carOptions, spawnPosition, rotation, targetPlayer, shouldTrackCar: false);
            if (car != null)
            {
                ReplyToPlayer(player, "Command.Give.Success", targetPlayer.displayName, preset.Name);
            }
        }

        [Command("mycar")]
        private void MyCarCommand(IPlayer player, string cmd, string[] args)
        {
            if (player.IsServer)
                return;

            var basePlayer = player.Object as BasePlayer;
            if (!basePlayer.CanInteract())
                return;

            if (args.Length == 0)
            {
                SubCommand_SpawnCar(player, args);
                return;
            }

            switch (args[0].ToLower())
            {
                case "help":
                    SubCommand_Help(player, args.Skip(1).ToArray());
                    return;

                case "list":
                    SubCommand_ListPresets(player, args.Skip(1).ToArray());
                    return;

                case "save":
                    SubCommand_SavePreset(player, args.Skip(1).ToArray());
                    return;

                case "update":
                    SubCommand_UpdatePreset(player, args.Skip(1).ToArray());
                    return;

                case "load":
                    SubCommand_LoadPreset(player, args.Skip(1).ToArray());
                    return;

                case "rename":
                    SubCommand_RenamePreset(player, args.Skip(1).ToArray());
                    return;

                case "delete":
                    SubCommand_DeletePreset(player, args.Skip(1).ToArray());
                    return;

                case "fix":
                    SubCommand_FixCar(player, args.Skip(1).ToArray());
                    return;

                case "fetch":
                    SubCommand_FetchCar(player, args.Skip(1).ToArray());
                    return;

                case "destroy":
                    SubCommand_DestroyCar(player, args.Skip(1).ToArray());
                    return;

                case "autocodelock":
                    SubCommand_ToggleAutoCodeLock(player, args.Skip(1).ToArray());
                    return;

                case "autokeylock":
                    SubCommand_ToggleAutoKeyLock(player, args.Skip(1).ToArray());
                    return;

                case "autofilltankers":
                    SubCommand_ToggleAutoFillTankers(player, args.Skip(1).ToArray());
                    return;

                case "common":
                    SubCommand_CommonPreset(player, args.Skip(1).ToArray());
                    return;

                default:
                    SubCommand_SpawnCar(player, args);
                    return;
            }
        }

        private void SubCommand_CommonPreset(IPlayer player, string[] args)
        {
            if (args.Length == 0)
            {
                ReplyToPlayer(player, "Command.Common.Error.Syntax");
                return;
            }

            switch (args[0].ToLower())
            {
                case "list":
                    SubCommand_Common_ListPresets(player, args.Skip(1).ToArray());
                    return;

                case "load":
                    SubCommand_Common_LoadPreset(player, args.Skip(1).ToArray());
                    return;

                case "save":
                    SubCommand_Common_SavePreset(player, args.Skip(1).ToArray());
                    return;

                case "update":
                    SubCommand_Common_UpdatePreset(player, args.Skip(1).ToArray());
                    return;

                case "rename":
                    SubCommand_Common_RenamePreset(player, args.Skip(1).ToArray());
                    return;

                case "delete":
                    SubCommand_Common_DeletePreset(player, args.Skip(1).ToArray());
                    return;

                default:
                    SubCommand_Common_SpawnCar(player, args);
                    return;
            }
        }

        private void SubCommand_Help(IPlayer player, string[] args)
        {
            var maxAllowedSockets = GetPlayerMaxAllowedCarSockets(player.Id);
            if (maxAllowedSockets == 0)
            {
                ReplyToPlayer(player, "Generic.Error.NoPermission");
                return;
            }

            var canUsePresets = permission.UserHasPermission(player.Id, PermissionPresets);
            var canLoadPresets = permission.UserHasPermission(player.Id, PermissionPresetLoad);

            var sb = new StringBuilder();
            sb.AppendLine(GetMessage(player, "Command.Help"));

            if (canUsePresets)
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Spawn.Basic.PresetsAllowed"));
            }
            else
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Spawn.Basic"));
            }

            sb.AppendLine(GetMessage(player, "Command.Help.Spawn.Sockets"));

            if (permission.UserHasPermission(player.Id, PermissionFix))
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Fix"));
            }

            if (permission.UserHasPermission(player.Id, PermissionFetch))
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Fetch"));
            }

            if (permission.UserHasPermission(player.Id, PermissionDespawn))
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Destroy"));
            }

            if (canUsePresets)
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Section.PersonalPresets"));
                sb.AppendLine(GetMessage(player, "Command.Help.ListPresets"));
                sb.AppendLine(GetMessage(player, "Command.Help.Spawn.Preset"));

                if (canLoadPresets)
                {
                    sb.AppendLine(GetMessage(player, "Command.Help.LoadPreset"));
                }

                sb.AppendLine(GetMessage(player, "Command.Help.SavePreset"));
                sb.AppendLine(GetMessage(player, "Command.Help.UpdatePreset"));
                sb.AppendLine(GetMessage(player, "Command.Help.RenamePreset"));
                sb.AppendLine(GetMessage(player, "Command.Help.DeletePreset"));
            }

            if (permission.UserHasPermission(player.Id, PermissionCommonPresets))
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Section.CommonPresets"));
                sb.AppendLine(GetMessage(player, "Command.Help.Common.ListPresets"));
                sb.AppendLine(GetMessage(player, "Command.Help.Common.Spawn"));

                if (canLoadPresets)
                {
                    sb.AppendLine(GetMessage(player, "Command.Help.Common.LoadPreset"));
                }

                if (permission.UserHasPermission(player.Id, PermissionManageCommonPresets))
                {
                    sb.AppendLine(GetMessage(player, "Command.Help.Common.SavePreset"));
                    sb.AppendLine(GetMessage(player, "Command.Help.Common.UpdatePreset"));
                    sb.AppendLine(GetMessage(player, "Command.Help.Common.RenamePreset"));
                    sb.AppendLine(GetMessage(player, "Command.Help.Common.DeletePreset"));
                }
            }

            var canCodeLock = VehicleDeployedLocks != null && permission.UserHasPermission(player.Id, PermissionAutoCodeLock);
            var canKeyLock = permission.UserHasPermission(player.Id, PermissionAutoKeyLock);
            var canFillTankers = permission.UserHasPermission(player.Id, PermissionAutoFillTankers);

            if (canCodeLock || canKeyLock || canFillTankers)
            {
                sb.AppendLine(GetMessage(player, "Command.Help.Section.PersonalSettings"));
            }

            if (canCodeLock)
            {
                sb.AppendLine(GetMessage(player, "Command.Help.ToggleAutoCodeLock",
                    BooleanToLocalizedString(player, GetPlayerConfig(player).Settings.AutoCodeLock)));
            }

            if (canKeyLock)
            {
                sb.AppendLine(GetMessage(player, "Command.Help.ToggleAutoKeyLock",
                    BooleanToLocalizedString(player, GetPlayerConfig(player).Settings.AutoKeyLock)));
            }

            if (canFillTankers)
            {
                sb.AppendLine(GetMessage(player, "Command.Help.ToggleAutoFillTankers",
                    BooleanToLocalizedString(player, GetPlayerConfig(player).Settings.AutoFillTankers)));
            }

            if (permission.UserHasPermission(player.Id, PermissionGiveCar))
            {
                sb.AppendLine("Command.Help.Section.OtherCommands");
                sb.AppendLine(GetMessage(player, "Command.Help.Give"));
            }

            player.Reply(sb.ToString());
        }

        private void SubCommand_SpawnCar(IPlayer player, string[] args)
        {
            var maxAllowedSockets = GetPlayerMaxAllowedCarSockets(player.Id);
            if (maxAllowedSockets == 0)
            {
                ReplyToPlayer(player, "Generic.Error.NoPermission");
                return;
            }

            if (!VerifyHasNoCar(player)
                || !VerifyOffCooldown(player, CooldownType.Spawn)
                || !VerifyLocationNotRestricted(player)
                || !_pluginConfig.CanSpawnBuildingBlocked && !VerifyNotBuildingBlocked(player))
                return;

            // Key binds automatically pass the "True" argument.var wasPassedArgument = args.Length > 0 && args[0] != "True";

            if (wasPassedArgument)
            {
                if (int.TryParse(args[0], out var desiredSockets))
                {
                    if (desiredSockets is < 2 or > 4)
                    {
                        ReplyToPlayer(player, "Command.Spawn.Error.SocketSyntax");
                        return;
                    }

                    if (desiredSockets > maxAllowedSockets)
                    {
                        ReplyToPlayer(player, "Generic.Error.NoPermission");
                        return;
                    }

                    SpawnRandomCarForPlayer(player, desiredSockets);
                    return;
                }

                if (!VerifyPermissionAny(player, PermissionPresets))
                    return;

                var presetNameArg = args[0];

                if (!VerifyOnlyOneMatchingPreset(player, GetPlayerConfig(player), presetNameArg, out var preset))
                    return;

                SpawnPresetCarForPlayer(player, preset);
            }
            else
            {
                if (permission.UserHasPermission(player.Id, PermissionPresets))
                {
                    var preset = GetPlayerConfig(player).FindPreset(DefaultPresetName);
                    if (preset != null)
                    {
                        SpawnPresetCarForPlayer(player, preset);
                        return;
                    }
                }

                SpawnRandomCarForPlayer(player, maxAllowedSockets);
            }
        }

        private void SubCommand_Common_SpawnCar(IPlayer player, string[] args)
        {
            var maxAllowedSockets = GetPlayerMaxAllowedCarSockets(player.Id);
            if (maxAllowedSockets == 0)
            {
                ReplyToPlayer(player, "Generic.Error.NoPermission");
                return;
            }

            if (!VerifyPermissionAny(player, PermissionCommonPresets)
                || !VerifyHasNoCar(player)
                || !VerifyOffCooldown(player, CooldownType.Spawn)
                || !VerifyLocationNotRestricted(player)
                || !_pluginConfig.CanSpawnBuildingBlocked && !VerifyNotBuildingBlocked(player))
                return;

            var presetNameArg = args[0];

            if (!VerifyOnlyOneMatchingPreset(player, _commonPresets, presetNameArg, out var preset))
                return;

            SpawnPresetCarForPlayer(player, preset);
        }

        private void SubCommand_FixCar(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionFix))
                return;

            if (!VerifyHasCar(player, out var car)
                || !VerifyOffCooldown(player, CooldownType.Fix)
                || FixMyCarWasBlocked(player.Object as BasePlayer, car))
                return;

            if (car.IsDead())
                ReviveCar(car);

            FixCar(car, GetPlayerAllowedFuel(player.Id), GetPlayerEnginePartsTier(player.Id));
            MaybeFillTankerModules(car, GetPlayerAllowedFreshWater(player.Id));
            _pluginData.StartCooldown(player.Id, CooldownType.Fix);

            MaybePlayCarRepairEffects(car);
            ReplyToPlayer(player, "Command.Fix.Success");
        }

        private void SubCommand_FetchCar(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionFetch))
                return;

            var basePlayer = player.Object as BasePlayer;

            if (!VerifyHasCar(player, out var car)
                || !_pluginConfig.CanFetchOccupied && !VerifyCarNotOccupied(player, car)
                || !VerifyOffCooldown(player, CooldownType.Fetch)
                || !VerifyLocationNotRestricted(player)
                || !_pluginConfig.CanFetchBuildingBlocked && !VerifyNotBuildingBlocked(player)
                || !VerifySufficientSpace(player, car.TotalSockets, out var fetchPosition, out var fetchRotation)
                || FetchMyCarWasBlocked(basePlayer, car))
                return;

            // This is a hacky way to determine that the car is on a lift.if (car.rigidBody.isKinematic && !TryReleaseCarFromLift(car))
            {
                var messages = new List<string> { GetMessage(player, "Command.Fetch.Error.StuckOnLift") };
                if (permission.UserHasPermission(player.Id, PermissionDespawn))
                    messages.Add(GetMessage(player, "Command.Fetch.Error.StuckOnLift.Help"));

                player.Reply(string.Join(" ", messages));
                return;
            }

            if (_pluginConfig.DismountPlayersOnFetch)
            {
                DismountAllPlayersFromCar(car);
            }

            // Temporarily clear max angular velocity to prevent the car from unexpectedly spinning when teleporting really far.var maxAngularVelocity = car.rigidBody.maxAngularVelocity;
            car.rigidBody.maxAngularVelocity = 0;

            car.transform.SetPositionAndRotation(fetchPosition, fetchRotation);
            car.SetVelocity(Vector3.zero);
            car.SetAngularVelocity(Vector3.zero);
            car.UpdateNetworkGroup();
            car.SendNetworkUpdateImmediate();
            timer.Once(1f, () =>
            {
                if (car != null)
                {
                    car.rigidBody.maxAngularVelocity = maxAngularVelocity;
                }
            });

            _pluginData.StartCooldown(player.Id, CooldownType.Fetch);
            ReplyToPlayer(player, "Command.Fetch.Success");
        }

        private void SubCommand_DestroyCar(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionDespawn))
                return;

            var basePlayer = player.Object as BasePlayer;

            if (!VerifyHasCar(player, out var car)
                || !_pluginConfig.CanDespawnOccupied && !VerifyCarNotOccupied(player, car)
                || DestroyMyCarWasBlocked(basePlayer, car))
                return;

            var extractedEngineParts = ExtractEnginePartsAboveTierAndDeleteRest(car, GetPlayerEnginePartsTier(player.Id));

            car.Kill();

            if (extractedEngineParts.Count > 0)
            {
                GiveItemsToPlayerOrDrop(basePlayer, extractedEngineParts);
                ReplyToPlayer(player, "Generic.Info.PartsRecovered");
            }
        }

        private void SubCommand_ListPresets(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionPresets))
                return;

            var config = GetPlayerConfig(player);
            if (config.Presets.Count == 0)
            {
                ReplyToPlayer(player, "Generic.Error.NoPresets");
                return;
            }

            var presetList = config.Presets.Select(p => p).ToList();
            presetList.Sort(SortPresetNames);

            var sb = new StringBuilder();
            sb.AppendLine(GetMessage(player, "Command.List"));

            foreach (var preset in presetList)
            {
                sb.AppendLine(GetMessage(player, "Command.List.Item", preset.Name, preset.NumSockets));
            }

            player.Reply(sb.ToString());
        }

        private void SubCommand_Common_ListPresets(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionCommonPresets))
                return;

            if (_commonPresets.Presets.Count == 0)
            {
                ReplyToPlayer(player, "Generic.Error.NoCommonPresets");
                return;
            }

            var maxAllowedSockets = GetPlayerMaxAllowedCarSockets(player.Id);

            var presetList = _commonPresets.Presets.Where(p => p.NumSockets <= maxAllowedSockets).ToList();
            presetList.Sort(SortPresetNames);

            var sb = new StringBuilder();
            sb.AppendLine(GetMessage(player, "Command.Common.List"));

            foreach (var preset in presetList)
            {
                sb.AppendLine(GetMessage(player, "Command.List.Item", preset.Name, preset.NumSockets));
            }

            player.Reply(sb.ToString());
        }

        private void SubCommand_SavePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionPresets))
                return;

            if (!VerifyHasCar(player, out var car))
                return;

            var presetNameArg = args.Length == 0 ? DefaultPresetName : args[0];

            var presetManager = GetPlayerConfig(player);
            if (!VerifyNoMatchingPreset(player, presetManager, presetNameArg))
                return;

            if (presetManager.Presets.Count >= _pluginConfig.MaxPresetsPerPlayer)
            {
                ReplyToPlayer(player, "Command.SavePreset.Error.TooManyPresets", _pluginConfig.MaxPresetsPerPlayer);
                return;
            }

            SavePreset(player, presetManager, presetNameArg, car);
        }

        private void SubCommand_Common_SavePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionManageCommonPresets))
                return;

            if (args.Length == 0)
            {
                ReplyToPlayer(player, "Command.Common.SavePreset.Error.Syntax");
                return;
            }

            var presetNameArg = args[0];

            if (!VerifyHasCar(player, out var car)
                || !VerifyNoMatchingPreset(player, _commonPresets, presetNameArg))
                return;

            SavePreset(player, _commonPresets, presetNameArg, car);
        }

        private void SavePreset(IPlayer player, SimplePresetManager presetManager, string presetNameArg, ModularCar car)
        {
            if (presetNameArg.Length > PresetMaxLength)
            {
                ReplyToPlayer(player, "Generic.Error.PresetNameLength", PresetMaxLength);
                return;
            }

            presetManager.SavePreset(SimplePreset.FromCar(car, presetNameArg));
            ReplyToPlayer(player, "Command.SavePreset.Success", presetNameArg);
        }

        private void SubCommand_UpdatePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionPresets))
                return;

            var presetNameArg = args.Length == 0 ? DefaultPresetName : args[0];
            UpdatePreset(player, GetPlayerConfig(player), presetNameArg);
        }

        private void SubCommand_Common_UpdatePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionManageCommonPresets))
                return;

            if (args.Length == 0)
            {
                ReplyToPlayer(player, "Command.Common.UpdatePreset.Error.Syntax");
                return;
            }

            UpdatePreset(player, _commonPresets, args[0]);
        }

        private void UpdatePreset(IPlayer player, SimplePresetManager presetManager, string presetNameArg)
        {
            if (!VerifyHasCar(player, out var car))
                return;

            if (!VerifyHasPreset(player, presetManager, presetNameArg, out var preset))
                return;

            presetManager.UpdatePreset(SimplePreset.FromCar(car, preset.Name));
            ReplyToPlayer(player, "Command.UpdatePreset.Success", preset.Name);
        }

        private void SubCommand_LoadPreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionPresetLoad))
                return;

            var presetNameArg = args.Length == 0 ? DefaultPresetName : args[0];
            LoadPreset(player, GetPlayerConfig(player.Id), presetNameArg);
        }

        private void SubCommand_Common_LoadPreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionPresetLoad)
                || !VerifyPermissionAny(player, PermissionCommonPresets))
                return;

            if (args.Length == 0)
            {
                ReplyToPlayer(player, "Command.Common.LoadPreset.Error.Syntax");
                return;
            }

            var presetNameArg = args[0];
            LoadPreset(player, _commonPresets, presetNameArg);
        }

        private void LoadPreset(IPlayer player, SimplePresetManager presetManager, string presetNameArg)
        {
            var basePlayer = player.Object as BasePlayer;

            if (!VerifyHasCar(player, out var car)
                || !VerifyCarNotOccupied(player, car)
                || !VerifyOffCooldown(player, CooldownType.Load)
                || LoadMyCarPresetWasBlocked(basePlayer, car))
                return;

            if (!VerifyOnlyOneMatchingPreset(player, presetManager, presetNameArg, out var preset))
                return;

            var presetNumSockets = preset.NumSockets;
            if (presetNumSockets > GetPlayerMaxAllowedCarSockets(player.Id))
            {
                ReplyToPlayer(player, "Generic.Error.NoPermissionToPresetSocketCount", preset.Name, preset.NumSockets);
                return;
            }

            if (presetNumSockets != car.TotalSockets)
            {
                ReplyToPlayer(player, "Command.LoadPreset.Error.SocketCount", preset.Name, presetNumSockets, car.TotalSockets);
                return;
            }

            if (car.IsDead())
            {
                ReviveCar(car);
            }

            var wasEngineOn = car.IsOn();
            var enginePartsTier = GetPlayerEnginePartsTier(player.Id);
            var extractedEngineParts = ExtractEnginePartsAboveTierAndDeleteRest(car, enginePartsTier);
            UpdateCarModules(car, preset.ModuleIDs);
            _pluginData.StartCooldown(player.Id, CooldownType.Load);

            NextTick(() =>
            {
                var wereExtraParts = false;

                if (extractedEngineParts.Count > 0)
                {
                    var remainingEngineParts = AddEngineItemsAndReturnRemaining(car, extractedEngineParts);
                    if (remainingEngineParts.Count > 0)
                    {
                        wereExtraParts = true;
                        GiveItemsToPlayerOrDrop(basePlayer, remainingEngineParts);
                    }
                }

                FixCar(car, GetPlayerAllowedFuel(player.Id), enginePartsTier);

                // Restart the engine if it turned off during the brief moment it had no engine or no parts.if (wasEngineOn && !car.IsOn() && car.engineController.CanRunEngine())
                    car.engineController.FinishStartingEngine();

                MaybeFillTankerModules(car, GetPlayerAllowedFreshWater(player.Id));

                if (car.CarLock.HasALock && !car.CarLock.CanHaveALock())
                {
                    car.RemoveLock();
                }

                MaybePlayCarRepairEffects(car);

                var chatMessages = new List<string>() { GetMessage(player, "Command.LoadPreset.Success", preset.Name) };
                if (wereExtraParts)
                    chatMessages.Add(GetMessage(player, "Generic.Info.PartsRecovered"));

                player.Reply(string.Join(" ", chatMessages));
            });
        }

        private void SubCommand_RenamePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionPresets))
                return;

            if (args.Length < 2)
            {
                ReplyToPlayer(player, "Command.RenamePreset.Error.Syntax");
                return;
            }

            RenamePreset(player, GetPlayerConfig(player), args[0], args[1]);
        }

        private void SubCommand_Common_RenamePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionManageCommonPresets))
                return;

            if (args.Length < 2)
            {
                ReplyToPlayer(player, "Command.Common.RenamePreset.Error.Syntax");
                return;
            }

            RenamePreset(player, _commonPresets, args[0], args[1]);
        }

        private void RenamePreset(IPlayer player, SimplePresetManager presetManager, string oldName, string newName)
        {
            if (!VerifyHasPreset(player, presetManager, oldName, out var preset))
                return;

            // Cache actual old preset name since matching is case-insensitive.var actualOldPresetName = preset.Name;

            var existingPresetWithNewName = presetManager.FindPreset(newName);

            if (newName.Length > PresetMaxLength)
            {
                ReplyToPlayer(player, "Generic.Error.PresetNameLength", PresetMaxLength);
                return;
            }

            // Allow renaming if just changing case.if (existingPresetWithNewName != null && preset != existingPresetWithNewName)
            {
                ReplyToPlayer(player, "Generic.Error.PresetAlreadyTaken", existingPresetWithNewName.Name);
                return;
            }

            presetManager.RenamePreset(preset, newName);
            ReplyToPlayer(player, "Command.RenamePreset.Success", actualOldPresetName, newName);
        }

        private void SubCommand_DeletePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionPresets))
                return;

            var presetNameArg = args.Length == 0 ? DefaultPresetName : args[0];
            DeletePreset(player, GetPlayerConfig(player), presetNameArg);
        }

        private void SubCommand_Common_DeletePreset(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionManageCommonPresets))
                return;

            if (args.Length == 0)
            {
                ReplyToPlayer(player, "Command.Common.DeletePreset.Error.Syntax");
                return;
            }

            DeletePreset(player, _commonPresets, args[0]);
        }

        private void DeletePreset(IPlayer player, SimplePresetManager presetManager, string presetNameArg)
        {
            if (!VerifyHasPreset(player, presetManager, presetNameArg, out var preset))
                return;

            presetManager.DeletePreset(preset);
            ReplyToPlayer(player, "Command.DeletePreset.Success", preset.Name);
        }

        private void SubCommand_ToggleAutoCodeLock(IPlayer player, string[] args)
        {
            if (VehicleDeployedLocks == null
                || !VerifyPermissionAny(player, PermissionAutoCodeLock))
                return;

            var config = GetPlayerConfig(player);
            config.Settings.AutoCodeLock = !config.Settings.AutoCodeLock;
            config.SaveData();
            ReplyToPlayer(player, "Command.ToggleAutoCodeLock.Success", BooleanToLocalizedString(player, config.Settings.AutoCodeLock));
        }

        private void SubCommand_ToggleAutoKeyLock(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionAutoKeyLock))
                return;

            var config = GetPlayerConfig(player);
            config.Settings.AutoKeyLock = !config.Settings.AutoKeyLock;
            config.SaveData();
            ReplyToPlayer(player, "Command.ToggleAutoKeyLock.Success", BooleanToLocalizedString(player, config.Settings.AutoKeyLock));
        }

        private void SubCommand_ToggleAutoFillTankers(IPlayer player, string[] args)
        {
            if (!VerifyPermissionAny(player, PermissionAutoFillTankers))
                return;

            var config = GetPlayerConfig(player);
            config.Settings.AutoFillTankers = !config.Settings.AutoFillTankers;
            config.SaveData();
            ReplyToPlayer(player, "Command.ToggleAutoFillTankers.Success", BooleanToLocalizedString(player, config.Settings.AutoFillTankers));
        }

        #endregion

        #region Dependencies

        private class MonumentAdapter
        {
            public string ShortName => (string)_monumentInfo["ShortName"];

            private Dictionary<string, object> _monumentInfo;

            public MonumentAdapter(Dictionary<string, object> monumentInfo)
            {
                _monumentInfo = monumentInfo;
            }

            public bool IsInBounds(Vector3 position) =>
                ((Func<Vector3, bool>)_monumentInfo["IsInBounds"]).Invoke(position);
        }

        private MonumentAdapter GetClosestMonument(Vector3 position)
        {
            return MonumentFinder?.Call("API_GetClosest", position) is Dictionary<string, object> dictResult
                ? new MonumentAdapter(dictResult)
                : null;
        }

        #endregion

        #region Helper Methods - Command Checks

        private static bool SpawnWasBlocked(BasePlayer player)
        {
            var hookResult = Interface.CallHook("CanSpawnModularCar", player);
            return hookResult is false;
        }

        private static bool SpawnMyCarWasBlocked(BasePlayer player)
        {
            if (SpawnWasBlocked(player))
                return true;

            var hookResult = Interface.CallHook("CanSpawnMyCar", player);
            return hookResult is false;
        }

        private static bool FetchMyCarWasBlocked(BasePlayer player, ModularCar car)
        {
            return Interface.CallHook("CanFetchMyCar", player, car) is false;
        }

        private static bool FixMyCarWasBlocked(BasePlayer player, ModularCar car)
        {
            return Interface.CallHook("CanFixMyCar", player, car) is false;
        }

        private static bool LoadMyCarPresetWasBlocked(BasePlayer player, ModularCar car)
        {
            return Interface.CallHook("CanLoadMyCarPreset", player, car) is false;
        }

        private static bool DestroyMyCarWasBlocked(BasePlayer player, ModularCar car)
        {
            return Interface.CallHook("CanDestroyMyCar", player, car) is false;
        }

        private static bool HasParent<T>(BasePlayer player) where T : BaseEntity
        {
            v
// ... [Code preview truncated due to length. Full source in attached file] ...

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