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

FREE AutomatedWorkcarts : 0.32.0 0.32.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEngine;
using static BaseEntity;
using static TrainCar;
using static TrainEngine;
using static TrainTrackSpline;
namespace Oxide.Plugins {
    [Info("Automated Workcarts", "WhiteThunder", "0.32.0")]
    [Description("Automates workcarts with NPC conductors.")]
    internal class AutomatedWorkcarts : CovalencePlugin {
#region Fields
        [PluginReference]
        private Plugin CargoTrainEvent;
        private static AutomatedWorkcarts _pluginInstance;
        private const string PermissionToggle = "automatedworkcarts.toggle";
        private const string PermissionManageTriggers = "automatedworkcarts.managetriggers";
        private const string ClassicWorkcartPrefab = "assets/content/vehicles/workcart/workcart.entity.prefab";
        private const string ShopkeeperPrefab = "assets/prefabs/npc/bandit/shopkeepers/bandit_shopkeeper.prefab";
        private const string GenericMapMarkerPrefab = "assets/prefabs/tools/map/genericradiusmarker.prefab";
        private const string VendingMapMarkerPrefab = "assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab";
        private const string BradleyExplosionEffectPrefab = "assets/prefabs/npc/m2bradley/effects/bradley_explosion.prefab";
        private const string IdPlaceholder = "$id";
        private static readonly FieldInfo TrainCouplingIsValidField = typeof(TrainCoupling).GetField("isValid", BindingFlags.NonPublic | BindingFlags.Instance) ?? typeof(TrainCoupling).GetField("isValid", BindingFlags.Public | BindingFlags.Instance);
        private static readonly object False = false;
        private static readonly Regex IdRegex = new Regex("\\$id", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        private readonly BasePlayer[] _playerQueryResults = new BasePlayer[64];
        private Configuration _pluginConfig;
        private StoredPluginData _pluginData;
        private StoredTunnelData _tunnelData;
        private StoredMapData _mapData;
        private readonly SpawnedTrainCarTracker _spawnedTrainCarTracker = new SpawnedTrainCarTracker();
        private TriggerManager _triggerManager;
        private TrainManager _trainManager;
        private Coroutine _startupCoroutine;
#endregion
#region Hooks
        private void Init() {
            _pluginInstance = this;
            _pluginData = StoredPluginData.Load();
            _tunnelData = StoredTunnelData.Load();
            _trainManager = new TrainManager(_pluginConfig, _pluginData, _spawnedTrainCarTracker);
            _triggerManager = new TriggerManager(_pluginConfig, _trainManager, _tunnelData);
            permission.RegisterPermission(PermissionToggle, this);
            permission.RegisterPermission(PermissionManageTriggers, this);
            Unsubscribe(nameof(OnEntitySpawned));
            if (!_pluginConfig.GenericMapMarker.Enabled) {
                Unsubscribe(nameof(OnPlayerConnected));
            }
        }
        private void OnServerInitialized() {
            if (!_pluginConfig.EnableTerrainCollision) {
                foreach (var entity in BaseNetworkable.serverEntities) {
                    var trainCar = entity as TrainCar;
                    if (trainCar != null) {
                        EnableTerrainCollision(trainCar, false);
                    }
                }
                Subscribe(nameof(OnEntitySpawned));
            }
            _tunnelData.MigrateTriggers();
            _mapData = StoredMapData.Load();
            _triggerManager.SetMapData(_mapData);
            _startupCoroutine = ServerMgr.Instance.StartCoroutine(DoStartupRoutine());
        }
        private void Unload() {
            if (!_pluginConfig.EnableTerrainCollision) {
                foreach (var entity in BaseNetworkable.serverEntities) {
                    var trainCar = entity as TrainCar;
                    if (trainCar != null) {
                        EnableTerrainCollision(trainCar, true);
                    }
                }
            }
            if (_startupCoroutine != null) ServerMgr.Instance.StopCoroutine(_startupCoroutine);
            OnServerSave();
            _triggerManager.DestroyAll();
            _trainManager.Unload();
            _pluginInstance = null;
        }
        private void OnServerSave() {
            if (_trainManager.UpdateTrainEngineData()) {
                _pluginData.Save();
            }
            else {
                _pluginData.SaveIfDirty();
            }
        }
        private void OnNewSave() {
            _pluginData = StoredPluginData.Clear();
        }
        private void OnPlayerConnected(BasePlayer player) {
            if (player.IsReceivingSnapshot) {
                timer.Once(1f, () => OnPlayerConnected(player));
                return;
            }
            _trainManager.ResendAllGenericMarkers();
        }
        private void OnEntitySpawned(TrainCar trainCar) {
            EnableTerrainCollision(trainCar, false);
        }
        private object OnTrainCarUncouple(TrainCar trainCar, BasePlayer player) {
            // Disallow uncoupling train cars from automated trains.return _trainManager.HasTrainController(trainCar)
            ? False : null;
        }
#endregion
#region Commands
        [Command("aw.toggle")]
        private void CommandAutomateTrain(IPlayer player, string cmd, string[] args) {
            if (player.IsServer || !VerifyPermission(player, PermissionToggle)) return;
            var basePlayer = player.Object as BasePlayer;
            var trainCar = GetTrainCarWhereAiming(basePlayer);
            if (trainCar == null) {
                ReplyToPlayer(player, Lang.ErrorNoWorkcartFound);
                return;
            }
            var trainController = _trainManager.GetTrainController(trainCar);
            if (trainController == null) {
                var leadTrainEngine = GetLeadTrainEngine(trainCar);
                if (leadTrainEngine == null) {
                    ReplyToPlayer(player, Lang.ErrorNoWorkcart);
                    return;
                }
                if (IsTrainOwned(trainCar)) {
                    ReplyToPlayer(player, Lang.ErrorWorkcartOwned);
                    return;
                }
                if (!_trainManager.CanHaveMoreConductors(trainCar)) {
                    ReplyToPlayer(player, Lang.ErrorMaxConductors, _trainManager.CountedConductors, _pluginConfig.MaxConductors);
                    return;
                }
                TrainEngineData trainEngineData = null;
                if (args.Length > 0) {
                    var routeName = GetRouteNameFromArg(player, args[0], requirePrefix : false);
                    if (!string.IsNullOrWhiteSpace(routeName)) {
                        trainEngineData = new TrainEngineData {
                            Route = routeName
                        }
                        ;
                    }
                }
                if (_trainManager.TryCreateTrainController(leadTrainEngine, trainEngineData : trainEngineData)) {
                    var baseMessage = trainEngineData != null ? GetMessage(player, Lang.ToggleOnWithRouteSuccess, trainEngineData.Route) : GetMessage(player, Lang.ToggleOnSuccess);
                    player.Reply(baseMessage + " " + GetConductorCountMessage(player));
                    if (player.HasPermission(PermissionManageTriggers)) {
                        if (trainEngineData?.Route != null) _triggerManager.SetPlayerDisplayedRoute(basePlayer, trainEngineData.Route);
                        _triggerManager.ShowAllRepeatedly(basePlayer);
                    }
                }
                else {
                    ReplyToPlayer(player, Lang.ErrorAutomateBlocked);
                }
            }
            else {
                _trainManager.KillTrainController(trainCar);
                player.Reply(GetMessage(player, Lang.ToggleOffSuccess) + " " + GetConductorCountMessage(player));
            }
        }
        [Command("aw.resetall")]
        private void CommandResetTrains(IPlayer player, string cmd, string[] args) {
            if (!player.IsServer && !VerifyPermission(player, PermissionToggle)) return;
            var trainCount = _trainManager.ResetAll();
            ReplyToPlayer(player, Lang.ResetAllSuccess, trainCount);
        }
        [Command("aw.addtrigger", "awt.add")]
        private void CommandAddTrigger(IPlayer player, string cmd, string[] args) {
            if (player.IsServer || !VerifyPermission(player, PermissionManageTriggers)) return;
            if (!_pluginConfig.EnableMapTriggers) {
                ReplyToPlayer(player, Lang.ErrorMapTriggersDisabled);
                return;
            }
            Vector3 trackPosition;
            if (!TryGetTrackPosition(player.Object as BasePlayer, out trackPosition)) {
                ReplyToPlayer(player, Lang.ErrorNoTrackFound);
                return;
            }
            var triggerData = new TriggerData() {
                Position = trackPosition
            }
            ;
            AddTriggerShared(player, cmd, args, triggerData);
        }
        [Command("aw.addtunneltrigger", "awt.addt")]
        private void CommandAddTunnelTrigger(IPlayer player, string cmd, string[] args) {
            if (player.IsServer || !VerifyPermission(player, PermissionManageTriggers)) return;
            Vector3 trackPosition;
            if (!TryGetTrackPosition(player.Object as BasePlayer, out trackPosition)) {
                ReplyToPlayer(player, Lang.ErrorNoTrackFound);
                return;
            }
            DungeonCellWrapper dungeonCellWrapper;
            if (!VerifySupportedNearbyTrainTunnel(player, trackPosition, out dungeonCellWrapper)) return;
            if (!_pluginConfig.IsTunnelTypeEnabled(dungeonCellWrapper.TunnelType)) {
                ReplyToPlayer(player, Lang.ErrorTunnelTypeDisabled, dungeonCellWrapper.TunnelType);
                return;
            }
            var triggerData = new TriggerData() {
                TunnelType = dungeonCellWrapper.TunnelType.ToString(), Position = dungeonCellWrapper.InverseTransformPoint(trackPosition),
            }
            ;
            AddTriggerShared(player, cmd, args, triggerData, dungeonCellWrapper);
        }
        private void AddTriggerShared(IPlayer player, string cmd, string[] args, TriggerData triggerData, DungeonCellWrapper dungeonCellWrapper = null) {
            foreach (var arg in args) {
                if (!VerifyValidArgAndModifyTrigger(player, cmd, arg, triggerData, Lang.AddTriggerSyntax)) return;
            }
            if (!triggerData.IsSpawner && !triggerData.AddConductor && !triggerData.Destroy && triggerData.GetTrackSelectionInstruction() == null && triggerData.GetSpeedInstruction() == null && triggerData.GetDirectionInstruction() == null) {
                triggerData.Speed = EngineSpeeds.Zero.ToString();
            }
            var basePlayer = player.Object as BasePlayer;
            if (triggerData.IsSpawner) {
                var rotation = Quaternion.Euler(basePlayer.viewAngles);
                if (dungeonCellWrapper != null) {
                    rotation *= Quaternion.Inverse(dungeonCellWrapper.Rotation);
                }
                triggerData.RotationAngle = rotation.eulerAngles.y % 360;
            }
            _triggerManager.AddTrigger(triggerData);
            if (triggerData.Route != null) _triggerManager.SetPlayerDisplayedRoute(basePlayer, triggerData.Route);
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.AddTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.updatetrigger", "awt.update")]
        private void CommandUpdateTrigger(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.UpdateTriggerSyntax, out triggerData, out optionArgs)) return;
            if (optionArgs.Length == 0) {
                ReplyToPlayer(player, Lang.UpdateTriggerSyntax, cmd, GetTriggerOptions(player));
                return;
            }
            var newTriggerData = triggerData.Clone();
            foreach (var arg in optionArgs) {
                if (!VerifyValidArgAndModifyTrigger(player, cmd, arg, newTriggerData, Lang.UpdateTriggerSyntax)) return;
            }
            _triggerManager.UpdateTrigger(triggerData, newTriggerData);
            var basePlayer = player.Object as BasePlayer;
            if (triggerData.Route != null) _triggerManager.SetPlayerDisplayedRoute(basePlayer, triggerData.Route);
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.UpdateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.replacetrigger", "awt.replace")]
        private void CommandReplaceTrigger(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.UpdateTriggerSyntax, out triggerData, out optionArgs)) return;
            if (optionArgs.Length == 0) {
                ReplyToPlayer(player, Lang.UpdateTriggerSyntax, cmd, GetTriggerOptions(player));
                return;
            }
            var newTriggerData = new TriggerData();
            foreach (var arg in optionArgs) {
                if (!VerifyValidArgAndModifyTrigger(player, cmd, arg, newTriggerData, Lang.UpdateTriggerSyntax)) return;
            }
            _triggerManager.UpdateTrigger(triggerData, newTriggerData);
            var basePlayer = player.Object as BasePlayer;
            if (triggerData.Route != null) _triggerManager.SetPlayerDisplayedRoute(basePlayer, triggerData.Route);
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.UpdateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.enabletrigger", "awt.enable")]
        private void CommandEnableTrigger(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.SimpleTriggerSyntax, out triggerData, out optionArgs)) return;
            var newTriggerData = triggerData.Clone();
            newTriggerData.Enabled = true;
            _triggerManager.UpdateTrigger(triggerData, newTriggerData);
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.UpdateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.disabletrigger", "awt.disable")]
        private void CommandDisableTrigger(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.SimpleTriggerSyntax, out triggerData, out optionArgs)) return;
            var newTriggerData = triggerData.Clone();
            newTriggerData.Enabled = false;
            _triggerManager.UpdateTrigger(triggerData, newTriggerData);
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.UpdateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.movetrigger", "awt.move")]
        private void CommandMoveTrigger(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.SimpleTriggerSyntax, out triggerData, out optionArgs)) return;
            Vector3 trackPosition;
            if (!VerifyTrackPosition(player, out trackPosition)) return;
            if (triggerData.TriggerType == TrainTriggerType.Tunnel) {
                DungeonCellWrapper dungeonCellWrapper;
                if (!VerifySupportedNearbyTrainTunnel(player, trackPosition, out dungeonCellWrapper)) return;
                if (dungeonCellWrapper.TunnelType != triggerData.GetTunnelType()) {
                    ReplyToPlayer(player, Lang.ErrorUnsupportedTunnel);
                    return;
                }
                trackPosition = dungeonCellWrapper.InverseTransformPoint(trackPosition);
            }
            _triggerManager.MoveTrigger(triggerData, trackPosition);
            var basePlayer = player.Object as BasePlayer;
            if (triggerData.Route != null) _triggerManager.SetPlayerDisplayedRoute(basePlayer, triggerData.Route);
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.MoveTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.removetrigger", "awt.remove")]
        private void CommandRemoveTrigger(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.SimpleTriggerSyntax, out triggerData, out optionArgs)) return;
            _triggerManager.RemoveTrigger(triggerData);
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.RemoveTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.rotatetrigger", "awt.rotate")]
        private void CommandSetTriggerRotation(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.SimpleTriggerSyntax, out triggerData, out optionArgs)) return;
            var basePlayer = player.Object as BasePlayer;
            var playerPosition = basePlayer.transform.position;
            var triggerInstance = _triggerManager.FindNearestTrigger(playerPosition, triggerData);
            var rotation = Quaternion.Euler(basePlayer.viewAngles);
            var tunnelTriggerInstance = triggerInstance as TunnelTriggerInstance;
            if (tunnelTriggerInstance != null) {
                rotation *= Quaternion.Inverse(tunnelTriggerInstance.DungeonCellWrapper.Rotation);
            }
            _triggerManager.RotateTrigger(triggerData, rotation.eulerAngles.y % 360);
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.RotateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.respawntrigger", "awt.respawn")]
        private void CommandRespawnTrigger(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.SimpleTriggerSyntax, out triggerData, out optionArgs)) return;
            if (!triggerData.IsSpawner) {
                ReplyToPlayer(player, Lang.ErrorRequiresSpawnTrigger);
                return;
            }
            if (!triggerData.Enabled) {
                ReplyToPlayer(player, Lang.ErrorTriggerDisabled);
                return;
            }
            _triggerManager.RespawnTrigger(triggerData);
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.ShowAllRepeatedly(basePlayer);
        }
        [Command("aw.addtriggercommand", "awt.addcommand", "awt.addcmd")]
        private void CommandAddCommand(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.AddCommandSyntax, out triggerData, out optionArgs)) return;
            if (optionArgs.Length < 1) {
                ReplyToPlayer(player, Lang.AddCommandSyntax, cmd);
                return;
            }
            var quotedCommands = optionArgs.Select(command => command.Contains(" ") ? $"\"{command}\"" : command).ToArray();
            _triggerManager.AddTriggerCommand(triggerData, string.Join(" ", quotedCommands));
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.UpdateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.removetriggercommand", "awt.removecommand", "awt.removecmd")]
        private void CommandRemoveCommand(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.RemoveCommandSyntax, out triggerData, out optionArgs)) return;
            int commandIndex;
            if (optionArgs.Length < 1 || !int.TryParse(optionArgs[0], out commandIndex)) {
                ReplyToPlayer(player, Lang.RemoveCommandSyntax, cmd);
                return;
            }
            if (commandIndex < 1 || commandIndex > triggerData.Commands.Count) {
                ReplyToPlayer(player, Lang.RemoveCommandErrorIndex, commandIndex);
                return;
            }
            _triggerManager.RemoveTriggerCommand(triggerData, commandIndex - 1);
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.UpdateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.settriggertrain", "awt.train")]
        private void CommandTriggerTrain(IPlayer player, string cmd, string[] args) {
            TriggerData triggerData;
            string[] optionArgs;
            if (!VerifyCanModifyTrigger(player, cmd, args, Lang.RemoveCommandSyntax, out triggerData, out optionArgs)) return;
            var trainCarAliases = new List<string>();
            foreach (var arg in optionArgs) {
                var trainCarPrefab = TrainCarPrefab.FindPrefab(arg);
                if (trainCarPrefab == null) {
                    ReplyToPlayer(player, Lang.ErrorUnrecognizedTrainCar, arg);
                    return;
                }
                trainCarAliases.Add(trainCarPrefab.TrainCarAlias);
            }
            var newTriggerData = triggerData.Clone();
            newTriggerData.TrainCars = trainCarAliases.ToArray();
            _triggerManager.UpdateTrigger(triggerData, newTriggerData);
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, Lang.UpdateTriggerSuccess, GetTriggerPrefix(player, triggerData), triggerData.Id);
        }
        [Command("aw.showtriggers", "awt.show")]
        private void CommandShowStops(IPlayer player, string cmd, string[] args) {
            if (player.IsServer || !VerifyPermission(player, PermissionManageTriggers) || !VerifyAnyTriggers(player)) return;
            int duration = 60;
            string routeName = null;
            foreach (var arg in args) {
                if (duration == 60) {
                    int argIntValue;
                    if (int.TryParse(arg, out argIntValue)) {
                        duration = argIntValue;
                        continue;
                    }
                }
                if (routeName == null) {
                    var routeNameArg = GetRouteNameFromArg(player, arg, requirePrefix : false);
                    if (!string.IsNullOrWhiteSpace(routeNameArg)) routeName = routeNameArg;
                }
            }
            var basePlayer = player.Object as BasePlayer;
            _triggerManager.SetPlayerDisplayedRoute(basePlayer, routeName);
            _triggerManager.ShowAllRepeatedly(basePlayer, duration);
            if (routeName != null) ReplyToPlayer(player, Lang.ShowTriggersWithRouteSuccess, routeName, FormatTime(duration));
            else ReplyToPlayer(player, Lang.ShowTriggersSuccess, FormatTime(duration));
        }
#endregion
#region API
        [HookMethod("API_AutomateWorkcart")]
        private bool API_AutomateWorkcart(TrainEngine trainEngine) {
            return _trainManager.HasTrainController(trainEngine) ? true : _trainManager.TryCreateTrainController(trainEngine);
        }
        [HookMethod("API_StopAutomatingWorkcart")]
        private void API_StopAutomatingWorkcart(TrainEngine trainEngine, bool immediate = false) {
            _trainManager.KillTrainController(trainEngine);
        }
        [HookMethod("API_IsWorkcartAutomated")]
        private bool API_IsWorkcartAutomated(TrainEngine trainEngine) {
            return _trainManager.HasTrainController(trainEngine);
        }
        [HookMethod("API_GetAutomatedWorkcarts")]
        private TrainEngine[] API_GetAutomatedWorkcarts() {
            return _trainManager.GetAutomatedTrainEngines();
        }
#endregion
#region Exposed Hooks
        private static class ExposedHooks {
            public static object OnWorkcartAutomationStart(TrainEngine trainEngine) {
                return Interface.CallHook("OnWorkcartAutomationStart", trainEngine);
            }
            public static void OnWorkcartAutomationStarted(TrainEngine trainEngine) {
                Interface.CallHook("OnWorkcartAutomationStarted", trainEngine);
            }
            public static void OnWorkcartAutomationStopped(TrainEngine trainEngine) {
                Interface.CallHook("OnWorkcartAutomationStopped", trainEngine);
            }
        }
#endregion
#region Dependencies
        private bool IsCargoTrain(TrainEngine trainEngine) {
            var result = CargoTrainEvent?.Call("IsTrainSpecial", trainEngine.net.ID);
            return result is bool && (bool)result;
        }
#endregion
#region Helper Methods - Command Checks
        private bool VerifyPermission(IPlayer player, string permissionName) {
            if (player.HasPermission(permissionName)) return true;
            ReplyToPlayer(player, Lang.ErrorNoPermission);
            return false;
        }
        private bool VerifyAnyTriggers(IPlayer player) {
            if (_mapData.MapTriggers.Count > 0 || _tunnelData.TunnelTriggers.Count > 0) return true;
            ReplyToPlayer(player, Lang.ErrorNoTriggers);
            return false;
        }
        private bool VerifyTriggerExists(IPlayer player, int triggerId, TrainTriggerType triggerType, out TriggerData triggerData) {
            triggerData = _triggerManager.FindTrigger(triggerId, triggerType);
            if (triggerData != null) return true;
            _triggerManager.ShowAllRepeatedly(player.Object as BasePlayer);
            ReplyToPlayer(player, Lang.ErrorTriggerNotFound, GetTriggerPrefix(player, triggerType), triggerId);
            return false;
        }
        private bool VerifyTrackPosition(IPlayer player, out Vector3 trackPosition) {
            if (TryGetTrackPosition(player.Object as BasePlayer, out trackPosition)) return true;
            ReplyToPlayer(player, Lang.ErrorNoTrackFound);
            return false;
        }
        private bool IsTriggerArg(IPlayer player, string arg, out int triggerId, out TrainTriggerType triggerType) {
            triggerType = TrainTriggerType.Map;
            triggerId = 0;
            if (arg.StartsWith("#")) arg = arg.Substring(1);
            if (arg.Length <= 1) return false;
            var triggerPrefix = arg.Substring(0, 1).ToLower();
            var triggerIdString = arg.Substring(1).ToLower();
            if (!int.TryParse(triggerIdString, out triggerId)) return false;
            if (triggerPrefix == GetTriggerPrefix(player, TrainTriggerType.Tunnel).ToLower()) {
                triggerType = TrainTriggerType.Tunnel;
                return true;
            }
            else if (triggerPrefix == GetTriggerPrefix(player, TrainTriggerType.Map).ToLower()) {
                triggerType = TrainTriggerType.Map;
                return true;
            }
            return false;
        }
        private bool VerifyTriggerWhereAiming(IPlayer player, string cmd, string[] args, string errorMessageName, out TriggerData triggerData, out string[] optionArgs) {
            var basePlayer = player.Object as BasePlayer;
            optionArgs = args;
            triggerData = null;
            triggerData = _triggerManager.FindNearestTriggerWhereAiming(basePlayer);
            if (triggerData != null) return true;
            _triggerManager.ShowAllRepeatedly(basePlayer);
            ReplyToPlayer(player, errorMessageName, cmd, GetTriggerOptions(player));
            return false;
        }
        private bool VerifyCanModifyTrigger(IPlayer player, string cmd, string[] args, string errorMessageName, out TriggerData triggerData, out string[] optionArgs) {
            triggerData = null;
            optionArgs = null;
            if (!VerifyPermission(player, PermissionManageTriggers) || !VerifyAnyTriggers(player)) return false;
            int triggerId;
            TrainTriggerType triggerType;
            if (args.Length > 0 && IsTriggerArg(player, args[0], out triggerId, out triggerType)) {
                optionArgs = args.Skip(1).ToArray();
                return VerifyTriggerExists(player, triggerId, triggerType, out triggerData);
            }
            if (player.IsServer) {
                // Server commands must specify a trigger id.ReplyToPlayer(player, errorMessageName, cmd, GetTriggerOptions(player));
                return false;
            }
            return VerifyTriggerWhereAiming(player, cmd, args, errorMessageName, out triggerData, out optionArgs);
        }
        private bool VerifySupportedNearbyTrainTunnel(IPlayer player, Vector3 trackPosition, out DungeonCellWrapper dungeonCellWrapper) {
            dungeonCellWrapper = FindNearestDungeonCell(trackPosition);
            if (dungeonCellWrapper == null || dungeonCellWrapper.TunnelType == TunnelType.Unsupported) {
                ReplyToPlayer(player, Lang.ErrorUnsupportedTunnel);
                return false;
            }
            return true;
        }
        private string GetRouteNameFromArg(IPlayer player, string routeName, bool requirePrefix = true) {
            if (routeName.StartsWith("@")) return routeName.Substring(1);
            return requirePrefix ? null : routeName;
        }
        private bool VerifyValidArgAndModifyTrigger(IPlayer player, string cmd, string arg, TriggerData triggerData, string errorMessageName) {
            var argLower = arg.ToLower();
            if (argLower == "start" || argLower == "conductor") {
                triggerData.AddConductor = true;
                return true;
            }
            if (argLower.StartsWith("brake")) {
                triggerData.Brake = true;
                return true;
            }
            if (argLower.StartsWith("destroy")) {
                triggerData.Destroy = true;
                return true;
            }
            if (argLower.StartsWith("enable")) {
                triggerData.Enabled = true;
                return true;
            }
            if (argLower.StartsWith("disable")) {
                triggerData.Enabled = false;
                return true;
            }
            var prefab = TrainCarPrefab.FindPrefab(argLower);
            if (prefab != null) {
                if (triggerData.TrainCars == null) {
                    triggerData.TrainCars = new string[] {
                        prefab.TrainCarAlias
                    }
                    ;
                }
                else {
                    var length = triggerData.TrainCars.Length;
                    Array.Resize(ref triggerData.TrainCars, length + 1);
                    triggerData.TrainCars[length] = prefab.TrainCarAlias;
                }
                return true;
            }
            float stopDuration;
            if (float.TryParse(arg, out stopDuration)) {
                triggerData.StopDuration = stopDuration;
                return true;
            }
            var routeName = GetRouteNameFromArg(player, arg, requirePrefix : true);
            if (!string.IsNullOrWhiteSpace(routeName)) {
                triggerData.Route = routeName;
                return true;
            }
            SpeedInstruction speedInstruction;
            if (Enum.TryParse<SpeedInstruction>(arg, true, out speedInstruction)) {
                var speedString = speedInstruction.ToString();
                // If zero speed is already set, assume this is the departure speed.if (triggerData.Speed == SpeedInstruction.Zero.ToString())
                triggerData.DepartureSpeed = speedString;
                else triggerData.Speed = speedString;
                return true;
            }
            DirectionInstruction directionInstruction;
            if (Enum.TryParse<DirectionInstruction>(arg, true, out directionInstruction)) {
                triggerData.Direction = directionInstruction.ToString();
                return true;
            }
            TrackSelectionInstruction trackSelectionInstruction;
            if (Enum.TryParse<TrackSelectionInstruction>(arg, true, out trackSelectionInstruction)) {
                triggerData.TrackSelection = trackSelectionInstruction.ToString();
                return true;
            }
            ReplyToPlayer(player, errorMessageName, cmd, GetTriggerOptions(player));
            return false;
        }
#endregion
#region Helper Methods - Coupling
        private static void UpdateAllowedCouplings(TrainCar trainCar, bool allowFront, bool allowRear) {
            var coupling = trainCar.coupling;
            var frontCoupling = coupling.frontCoupling;
            var rearCoupling = coupling.rearCoupling;
            if (trainCar.frontCoupling == null || trainCar.rearCoupling == null) {
                // Some train cars do not allow coupling, such as the classic workcart.return;
            }
            if (!allowFront && frontCoupling.IsCoupled) {
                frontCoupling.Uncouple(reflect : true);
            }
            if (!allowRear && rearCoupling.IsCoupled) {
                rearCoupling.Uncouple(reflect : true);
            }
            if (frontCoupling.isValid != allowFront) {
                TrainCouplingIsValidField.SetValue(frontCoupling, allowFront);
            }
            if (rearCoupling.isValid != allowRear) {
                TrainCouplingIsValidField.SetValue(rearCoupling, allowRear);
            }
        }
        private static void DisableTrainCoupling(CompleteTrain completeTrain) {
            var firstTrainCar = completeTrain.trainCars.FirstOrDefault();
            var lastTrainCar = completeTrain.trainCars.LastOrDefault();
            if (firstTrainCar == null || lastTrainCar == null) return;
            UpdateAllowedCouplings(firstTrainCar, firstTrainCar.coupling.IsFrontCoupled, firstTrainCar.coupling.IsRearCoupled);
            if (lastTrainCar != firstTrainCar) {
                UpdateAllowedCouplings(lastTrainCar, lastTrainCar.coupling.IsFrontCoupled, lastTrainCar.coupling.IsRearCoupled);
            }
        }
        private static void EnableTrainCoupling(CompleteTrain completeTrain) {
            var firstTrainCar = completeTrain.trainCars.FirstOrDefault();
            var lastTrainCar = completeTrain.trainCars.LastOrDefault();
            if (firstTrainCar == null || lastTrainCar == null) return;
            UpdateAllowedCouplings(firstTrainCar, allowFront : true, allowRear : true);
            if (lastTrainCar != firstTrainCar) {
                UpdateAllowedCouplings(lastTrainCar, allowFront : true, allowRear : true);
            }
        }
#endregion
#region Helper Methods
        private IEnumerator DoStartupRoutine() {
            yield return _triggerManager.CreateAll();
            TrackStart();
            var foundTrainEngineIds = new HashSet<uint>();
            foreach (var entity in BaseNetworkable.serverEntities) {
                var trainEngine = entity as TrainEngine;
                if (trainEngine == null) continue;
                var trainEngineData = _pluginData.GetTrainEngineData(trainEngine.net.ID);
                if (trainEngineData != null) {
                    foundTrainEngineIds.Add(trainEngine.net.ID);
                    timer.Once(UnityEngine.Random.Range(0, 1f), () => {
                        if (trainEngine != null && !IsTrainOwned(trainEngine) && _trainManager.CanHaveMoreConductors(trainEngine) && !_trainManager.HasTrainController(trainEngine)) {
                            _trainManager.TryCreateTrainController(trainEngine, trainEngineData : trainEngineData);
                        }
                    }
                    );
                }
            }
            _pluginData.TrimToTrainEngineIds(foundTrainEngineIds);
            TrackEnd();
        }
        private void EnableTerrainCollision(TrainCar trainCar, bool enabled) {
            Physics.IgnoreCollision(trainCar.frontCollisionTrigger.triggerCollider, TerrainMeta.Collider, !enabled);
            Physics.IgnoreCollision(trainCar.rearCollisionTrigger.triggerCollider, TerrainMeta.Collider, !enabled);
        }
        private bool AutomationWasBlocked(TrainEngine trainEngine) {
            object hookResult = ExposedHooks.OnWorkcartAutomationStart(trainEngine);
            if (hookResult is bool && (bool)hookResult == false) return true;
            if (IsCargoTrain(trainEngine)) return true;
            return false;
        }
        public static void LogInfo(string message) => Interface.Oxide.LogInfo($"[Automated Workcarts] {message}");
        public static void LogError(string message) => Interface.Oxide.LogError($"[Automated Workcarts] {message}");
        public static void LogWarning(string message) => Interface.Oxide.LogWarning($"[Automated Workcarts] {message}");
        private static float GetThrottleFraction(EngineSpeeds throttle) {
            switch (throttle) {
                case EngineSpeeds.Rev_Hi : return -1;
                case EngineSpeeds.Rev_Med : return -0.5f;
                case EngineSpeeds.Rev_Lo : return -0.2f;
                case EngineSpeeds.Fwd_Lo : return 0.2f;
                case EngineSpeeds.Fwd_Med : return 0.5f;
                case EngineSpeeds.Fwd_Hi : return 1;
                default : return 0;
            }
        }
        private static TrainEngine GetLeadTrainEngine(CompleteTrain completeTrain) {
            if (completeTrain.PrimaryTrainCar == completeTrain.trainCars[0]) {
                for (var i = 0; i < completeTrain.trainCars.Count; i++) {
                    var trainEngine = completeTrain.trainCars[i] as TrainEngine;
                    if ((object)trainEngine != null) return trainEngine;
                }
            }
            else {
                for (var i = completeTrain.trainCars.Count - 1; i >= 0; i--) {
                    var trainEngine = completeTrain.trainCars[i] as TrainEngine;
                    if ((object)trainEngine != null) return trainEngine;
                }
            }
            return null;
        }
        private static TrainEngine GetLeadTrainEngine(TrainCar trainCar) {
            var trainEngine = trainCar as TrainEngine;
            if ((trainEngine) != null) return trainEngine;
            return GetLeadTrainEngine(trainCar.completeTrain);
        }
        private static void DetermineTrainCarOrientations(TrainCar trainCar, Vector3 forward, TrainCar otherTrainCar, Vector3 otherForward, out TrainCar forwardTrainCar, out TrainCar backwardTrainCar) {
            var position = trainCar.transform.position;
            var otherPosition = otherTrainCar.transform.position;
            var forwardPosition = position + forward * 100f;
            forwardTrainCar = trainCar;
            backwardTrainCar = otherTrainCar;
            if ((forwardPosition - position).sqrMagnitude > (forwardPosition - otherPosition).sqrMagnitude) {
                forwardTrainCar = otherTrainCar;
                backwardTrainCar = trainCar;
            }
        }
        private static Vector3 GetTrainCarForward(TrainCar trainCar) {
            return trainCar.GetTrackSpeed() >= 0 ? trainCar.transform.forward : -trainCar.transform.forward;
        }
        private static void EnableInvincibility(TrainCar trainCar) {
            trainCar.initialSpawnTime = float.MaxValue;
        }
        private static void DisableInvincibility(TrainCar trainCar) {
            trainCar.initialSpawnTime = Time.time;
        }
        private static void EnableSavingRecursive(BaseEntity entity, bool enableSaving) {
            entity.EnableSaving(enableSaving);
            foreach (var child in entity.children) {
                if (child is BasePlayer) continue;
                EnableSavingRecursive(child, enableSaving);
            }
        }
        private static TrainCar SpawnTrainCar(string prefabName, Vector3 position, Quaternion rotation) {
            var trainCar = GameManager.server.CreateEntity(prefabName, position, rotation) as TrainCar;
            if (trainCar == null) return null;
            // Ensure the train car does not decay for some time.trainCar.lastDecayTick = Time.realtimeSinceStartup;
            trainCar.limitNetworking = true;
            trainCar.EnableSaving(false);
            trainCar.Spawn();
            if (trainCar.IsDestroyed) return null;
            trainCar.Invoke(() => EnableSavingRecursive(trainCar, false), 0);
            return trainCar;
        }
        private static float GetSplineDistance(TrainTrackSpline spline, Vector3 position) {
            float distanceOnSpline;
            spline.GetDistance(position, 1, out distanceOnSpline);
            return distanceOnSpline;
        }
        private static TrainCar AddTrainCar(TrainCar trainCar, string prefabName, TrackSelection trackSelection, bool allowRearCoupling = true) {
            var rearSpline = trainCar.FrontTrackSection;
            var position = trainCar.transform.position;
            var distanceOnSpline = GetSplineDistance(rearSpline, position);
            var askerIsForward = rearSpline.IsForward(trainCar.transform.forward, distanceOnSpline);
            var splineInfo = new SplineInfo {
                Spline = rearSpline, Distance = distanceOnSpline, Ascending = !askerIsForward, IsForward = askerIsForward,
            }
            ;
            var finalDistance = Math.Abs(trainCar.rearCoupling.localPosition.z) + GetTrainCarFrontCouplingOffsetZ(prefabName);
            var spawnDistance = Mathf.Max(finalDistance, 22);
            SplineInfo finalSplineInfo;
            var finalPosition = GetPositionAlongTrack(splineInfo, finalDistance, trackSelection, out finalSplineInfo);
            SplineInfo spawnSplineInfo;
            var resultPosition = GetPositionAlongTrack(finalSplineInfo, spawnDistance - finalDistance, trackSelection, out spawnSplineInfo);
            var resultRotation = GetSplineTangentRotation(spawnSplineInfo.Spline, spawnSplineInfo.Distance, trainCar.transform.rotation);
            var rearTrainCar = SpawnTrainCar(prefabName, resultPosition, resultRotation);
            if (rearTrainCar != null) {
                if (rearTrainCar.FrontTrackSection == null) {
                    rearTrainCar.Kill();
                    return null;
                }
                rearTrainCar.MoveFrontWheelsAlongTrackSpline(rearTrainCar.FrontTrackSection, rearTrainCar.FrontWheelSplineDist, spawnDistance - finalDistance, rearTrainCar.RearTrackSection != rearTrainCar.FrontTrackSection ? rearTrainCar.RearTrackSection : null, trackSelection );
                rearTrainCar.transform.position = finalPosition;
                TryCoupleTrainCars(trainCar, rearTrainCar);
            }
            return rearTrainCar;
        }
        private static void TryCoupleTrainCars(TrainCar front, TrainCar rear) {
            front.coupling.rearCoupling.TryCouple(rear.coupling.frontCoupling, reflect : true);
        }
        private static float GetTrainCarFrontCouplingOffsetZ(string prefabName) {
            var prefab = GameManager.server.FindPrefab(prefabName)?.GetComponent<TrainCar>();
            if (prefab == null) return 0;
            return prefab.frontCoupling.localPosition.z;
        }
        private static ConnectedTrackInfo GetAdjacentTrackInfo(TrainTrackSpline spline, TrainTrackSpline.TrackSelection selection, bool isAscending = true, bool askerIsForward = true) {
            var trackOptions = isAscending ? spline.nextTracks : spline.prevTracks;
            if (trackOptions.Count == 0) return null;
            if (trackOptions.Count == 1) return trackOptions[0];
            switch (selection) {
                case TrainTrackSpline.TrackSelection.Left : return isAscending == askerIsForward ? trackOptions.FirstOrDefault() : trackOptions.LastOrDefault();
                case TrainTrackSpline.TrackSelection.Right : return isAscending == askerIsForward ? trackOptions.LastOrDefault() : trackOptions.FirstOrDefault();
                default : return trackOptions[isAscending ? spline.straightestNextIndex : spline.straightestPrevIndex];
            }
        }
        private static Quaternion GetSplineTangentRotation(TrainTrackSpline spline, float distanceOnSpline, Quaternion approximateRotation) {
            Vector3 tangentDirection;
            spline.GetPositionAndTangent(distanceOnSpline, approximateRotation * Vector3.forward, out tangentDirection);
            return Quaternion.LookRotation(tangentDirection);
        }
        private struct SplineInfo {
            public TrainTrackSpline Spline;
            public float Distance;
            public bool Ascending;
            public bool IsForward;
        }
        private static Vector3 GetPositionAlongTrack(SplineInfo splineInfo, float desiredDistance, TrackSelection trackSelection, out SplineInfo resultSplineInfo, out float remainingDistance) {
            resultSplineInfo = splineInfo;
            remainingDistance = desiredDistance;
            var i = 0;
            while (remainingDistance > 0) {
                if (i++ > 1000) {
                    LogError("Something is wrong.Please contact the plugin developer.");
                    return Vector3.zero;
                }
                var splineLength = resultSplineInfo.Spline.GetLength();
                var newDistanceOnSpline = resultSplineInfo.Ascending ? resultSplineInfo.Distance + remainingDistance : resultSplineInfo.Distance - remainingDistance;
                remainingDistance -= resultSplineInfo.Ascending ? splineLength - resultSplineInfo.Distance : resultSplineInfo.Distance;
                if (newDistanceO
// ... [Code preview truncated due to length. Full source in attached file] ...

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