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

FREE MLRSDriveable : 1.2.0 1.2.0

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("MLRSDriveable", "YourName", "1.2.0")]
    [Description("Позволяет игрокам ездить на MLRS. Использует подтверждённые методы API.")]
    public class MLRSDriveable : RustPlugin
    {
        private const string PermUse   = "mlrsdriveable.use";
        private const string PermSpawn = "mlrsdriveable.spawn";
        private const string PermAdmin = "mlrsdriveable.admin";

        // prefab подтверждён авто-определением
        private const string MLRSPrefab = "assets/content/vehicles/mlrs/mlrs.entity.prefab";

        // Словари: кто в каком MLRS едет
        private readonly Dictionary<ulong, MLRS> _drivingPlayers = new Dictionary<ulong, MLRS>();
        private readonly Dictionary<NetworkableId, BasePlayer> _mlrsDrivers = new Dictionary<NetworkableId, BasePlayer>();

        #region Инициализация

        void Init()
        {
            permission.RegisterPermission(PermUse,   this);
            permission.RegisterPermission(PermSpawn, this);
            permission.RegisterPermission(PermAdmin, this);
        }

        void Unload()
        {
            foreach (var pair in new Dictionary<ulong, MLRS>(_drivingPlayers))
            {
                BasePlayer player = null;
                foreach (var p in BasePlayer.activePlayerList)
                    if (p.userID == pair.Key) { player = p; break; }
                if (player != null)
                    ExitMLRS(player, pair.Value);
            }
            _drivingPlayers.Clear();
            _mlrsDrivers.Clear();
        }

        #endregion

        #region Hooks

        void OnEntityKill(MLRS mlrs)
        {
            if (mlrs == null) return;
            if (_mlrsDrivers.TryGetValue(mlrs.net.ID, out var driver))
            {
                _drivingPlayers.Remove(driver.userID);
                _mlrsDrivers.Remove(mlrs.net.ID);
                SendReply(driver, lang.GetMessage("MLRSDestroyed", this, driver.UserIDString));
            }
        }

        object OnPlayerInput(BasePlayer player, InputState input)
        {
            if (player == null || input == null) return null;
            if (_drivingPlayers.ContainsKey(player.userID))
                HandleDriving(player, input);
            return null;
        }

        #endregion

        #region Команды

        [ChatCommand("mlrs")]
        void CmdMLRS(BasePlayer player, string cmd, string[] args)
        {
            if (!permission.UserHasPermission(player.UserIDString, PermUse))
            {
                SendReply(player, lang.GetMessage("NoPermission", this, player.UserIDString));
                return;
            }

            string sub = args.Length > 0 ? args[0].ToLower() : "";
            switch (sub)
            {
                case "enter": case "войти":
                    TryEnterNearestMLRS(player);
                    break;

                case "exit": case "выйти":
                    TryExitMLRS(player);
                    break;

                case "spawn": case "спавн":
                    if (permission.UserHasPermission(player.UserIDString, PermSpawn))
                        SpawnMLRS(player);
                    else
                        SendReply(player, lang.GetMessage("NoPermission", this, player.UserIDString));
                    break;

                default:
                    SendReply(player, lang.GetMessage("Help", this, player.UserIDString));
                    break;
            }
        }

        #endregion

        #region Посадка / Высадка

        void TryEnterNearestMLRS(BasePlayer player)
        {
            if (_drivingPlayers.ContainsKey(player.userID))
            {
                SendReply(player, lang.GetMessage("AlreadyDriving", this, player.UserIDString));
                return;
            }

            var mlrs = FindNearestMLRS(player.transform.position, 5f);
            if (mlrs == null)
            {
                SendReply(player, lang.GetMessage("NoMLRSNearby", this, player.UserIDString));
                return;
            }
            if (_mlrsDrivers.ContainsKey(mlrs.net.ID))
            {
                SendReply(player, lang.GetMessage("MLRSOccupied", this, player.UserIDString));
                return;
            }

            EnterMLRS(player, mlrs);
        }

        void TryExitMLRS(BasePlayer player)
        {
            if (!_drivingPlayers.TryGetValue(player.userID, out var mlrs))
            {
                SendReply(player, lang.GetMessage("NotDriving", this, player.UserIDString));
                return;
            }
            ExitMLRS(player, mlrs);
        }

        void EnterMLRS(BasePlayer player, MLRS mlrs)
        {
            _drivingPlayers[player.userID]  = mlrs;
            _mlrsDrivers[mlrs.net.ID]       = player;

            try
            {
                // MLRS сам является BaseMountable — MountPlayer(BasePlayer, Vector3)
                mlrs.MountPlayer(player);
                Puts($"[MLRSDriveable] {player.displayName} сел в MLRS через MountPlayer");
            }
            catch (Exception ex)
            {
                Puts($"[MLRSDriveable] MountPlayer ошибка: {ex.Message} — fallback");
                FallbackEnter(player, mlrs);
            }

            SendReply(player, lang.GetMessage("Entered",  this, player.UserIDString));
            SendReply(player, lang.GetMessage("Controls", this, player.UserIDString));
        }

        void FallbackEnter(BasePlayer player, MLRS mlrs)
        {
            // Позиция в кабине: чуть вперёд и выше центра MLRS
            Vector3 seatPos = mlrs.transform.position
                            + mlrs.transform.forward * 0.5f
                            + Vector3.up * 2.3f;

            try
            {
                player.transform.SetParent(mlrs.transform);
                player.MovePosition(seatPos, true);   // true = forceUpdateTriggers
                Puts($"[MLRSDriveable] Fallback посадка: {player.displayName} → {seatPos}");
            }
            catch (Exception ex)
            {
                Puts($"[MLRSDriveable] Fallback ошибка: {ex.Message}");
                player.transform.position = seatPos;
            }
        }

        void ExitMLRS(BasePlayer player, MLRS mlrs)
        {
            if (player == null) return;

            _drivingPlayers.Remove(player.userID);
            if (mlrs != null) _mlrsDrivers.Remove(mlrs.net.ID);

            try
            {
                // DismountPlayer подтверждён авто-определением
                mlrs?.DismountPlayer(player);
                Puts($"[MLRSDriveable] {player.displayName} вышел через DismountPlayer");
            }
            catch (Exception ex)
            {
                Puts($"[MLRSDriveable] DismountPlayer ошибка: {ex.Message} — fallback");
                FallbackExit(player, mlrs);
            }

            SendReply(player, lang.GetMessage("Exited", this, player.UserIDString));
        }

        void FallbackExit(BasePlayer player, MLRS mlrs)
        {
            try { player.transform.SetParent(null); } catch { }

            if (mlrs != null)
            {
                Vector3 exitPos = mlrs.transform.position + mlrs.transform.right * 3f + Vector3.up * 0.5f;
                try { player.MovePosition(exitPos, true); }
                catch { player.transform.position = exitPos; }
            }
        }

        #endregion

        #region Движение

        void HandleDriving(BasePlayer player, InputState input)
        {
            if (!_drivingPlayers.TryGetValue(player.userID, out var mlrs)) return;
            if (mlrs == null || mlrs.IsDestroyed) { ExitMLRS(player, null); return; }

            // E — выйти
            if (input.WasJustPressed(BUTTON.USE))
            {
                ExitMLRS(player, mlrs);
                return;
            }

            bool w = input.IsDown(BUTTON.FORWARD);
            bool s = input.IsDown(BUTTON.BACKWARD);
            bool a = input.IsDown(BUTTON.LEFT);
            bool d = input.IsDown(BUTTON.RIGHT);

            if (!w && !s && !a && !d) return;

            float speed    = 5f;   // м/с
            float rotSpeed = 45f;  // градусов/с

            // Rigidbody не найден — двигаем через transform
            if (w) mlrs.transform.position += mlrs.transform.forward * speed * Time.deltaTime;
            if (s) mlrs.transform.position -= mlrs.transform.forward * speed * Time.deltaTime;
            if (a) mlrs.transform.Rotate(Vector3.up, -rotSpeed * Time.deltaTime, Space.World);
            if (d) mlrs.transform.Rotate(Vector3.up,  rotSpeed * Time.deltaTime, Space.World);

            // Синхронизируем позицию со всеми клиентами
            mlrs.SendNetworkUpdateImmediate();

            // Обновляем позицию игрока вместе с машиной
            if (player.HasParent()) return; // уже прикреплён через MountPlayer — не нужно
            Vector3 newSeat = mlrs.transform.position + mlrs.transform.forward * 0.5f + Vector3.up * 2.3f;
            try { player.MovePosition(newSeat, false); } catch { }
        }

        #endregion

        #region Спавн

        void SpawnMLRS(BasePlayer player)
        {
            Vector3    pos = player.transform.position + player.transform.forward * 6f;
            Quaternion rot = Quaternion.Euler(0, player.transform.eulerAngles.y, 0);

            var ent = GameManager.server.CreateEntity(MLRSPrefab, pos, rot);
            if (ent == null)
            {
                SendReply(player, lang.GetMessage("SpawnFailed", this, player.UserIDString));
                Puts($"[MLRSDriveable] CreateEntity вернул null для prefab: {MLRSPrefab}");
                return;
            }

            ent.Spawn();
            SendReply(player, lang.GetMessage("Spawned", this, player.UserIDString));
            Puts($"[MLRSDriveable] {player.displayName} заспавнил MLRS на {pos}");
        }

        #endregion

        #region Хелперы

        MLRS FindNearestMLRS(Vector3 pos, float radius)
        {
            MLRS nearest  = null;
            float minDist = float.MaxValue;

            foreach (var entity in BaseNetworkable.serverEntities)
            {
                var mlrs = entity as MLRS;
                if (mlrs == null) continue;
                float dist = Vector3.Distance(pos, mlrs.transform.position);
                if (dist < radius && dist < minDist) { minDist = dist; nearest = mlrs; }
            }
            return nearest;
        }

        #endregion

        #region Локализация

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["NoPermission"]   = "❌ Нет прав для этой команды.",
                ["Help"]           = "📋 /mlrs enter — сесть  |  /mlrs exit — выйти  |  /mlrs spawn — заспавнить",
                ["NoMLRSNearby"]   = "❌ Нет MLRS рядом (радиус 5м).",
                ["MLRSOccupied"]   = "❌ Этот MLRS уже занят.",
                ["AlreadyDriving"] = "❌ Ты уже управляешь MLRS. Используй /mlrs exit.",
                ["NotDriving"]     = "❌ Ты не управляешь MLRS.",
                ["Entered"]        = "✅ Ты сел в MLRS!",
                ["Controls"]       = "🎮 W/S — движение  |  A/D — поворот  |  E — выйти",
                ["Exited"]         = "✅ Ты вышел из MLRS.",
                ["MLRSDestroyed"]  = "💥 MLRS уничтожен!",
                ["Spawned"]        = "✅ MLRS заспавнен перед тобой!",
                ["SpawnFailed"]    = "❌ Не удалось заспавнить MLRS. Проверь консоль.",
            }, this, "ru");

            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["NoPermission"]   = "❌ You don't have permission.",
                ["Help"]           = "📋 /mlrs enter — mount  |  /mlrs exit — dismount  |  /mlrs spawn — spawn",
                ["NoMLRSNearby"]   = "❌ No MLRS nearby (5m radius).",
                ["MLRSOccupied"]   = "❌ This MLRS is already occupied.",
                ["AlreadyDriving"] = "❌ You are already driving an MLRS. Use /mlrs exit.",
                ["NotDriving"]     = "❌ You are not driving an MLRS.",
                ["Entered"]        = "✅ You entered the MLRS!",
                ["Controls"]       = "🎮 W/S — move  |  A/D — turn  |  E — exit",
                ["Exited"]         = "✅ You exited the MLRS.",
                ["MLRSDestroyed"]  = "💥 Your MLRS was destroyed!",
                ["Spawned"]        = "✅ MLRS spawned in front of you!",
                ["SpawnFailed"]    = "❌ Failed to spawn MLRS. Check console.",
            }, this, "en");
        }

        #endregion
    }
}

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