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

FREE HighJump : 1.0.2 1.0.2

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

namespace Oxide.Plugins
{
    [Info("HighJump", "NINJA WORKS", "1.0.2")]
    public class HighJump : RustPlugin
    {
        #region Constants

        private const bool DEBUG_MODE = false;

        private const float DOUBLE_JUMP_WINDOW = 0.4f;
        private const float GROUND_CHECK_DISTANCE = 0.5f;
        private const float JUMP_COOLDOWN = 0.3f;
        private const float CEILING_CHECK_DISTANCE = 2.0f;
        private const float GRAVITY = 20f;
        private const float CEILING_CHECK_RADIUS = 0.3f;
        private const float CEILING_CHECK_MARGIN = 0.5f;
        private const float CEILING_SAFE_MARGIN = 0.2f;
        private const float PLAYER_HEAD_OFFSET = 1.5f;
        private const float STUCK_CHECK_HEIGHT = 0.9f;
        private const float STUCK_CHECK_RADIUS = 0.4f;
        private const float SAFE_POS_RAY_START = 2f;
        private const float SAFE_POS_RAY_DISTANCE = 10f;
        private const float GROUND_OFFSET = 0.1f;
        private const float BOOSTER_SPAWN_HEIGHT = 500f;
        private const float FALL_DAMAGE_IMMUNITY_DURATION = 5f;
        private const float MAX_SAFE_FALL_HEIGHT = 20f;

        private const string PERM_USE = "HighJump.use";
        private const string PERM_VIP1 = "HighJump.vip1";
        private const string PERM_VIP2 = "HighJump.vip2";
        private const string PERM_VIP3 = "HighJump.vip3";

        private static int _physicsLayerMask = -1;
        private static int PhysicsLayerMask
        {
            get
            {
                if (_physicsLayerMask == -1)
                {
                    _physicsLayerMask = LayerMask.GetMask("Terrain", "World", "Construction", "Default");
                }
                return _physicsLayerMask;
            }
        }

        #endregion

        #region Configuration

        private ConfigData config;

        private class ConfigData
        {
            [JsonProperty("Double Jump Calorie Cost")]
            public float DoubleJumpCalorieCost { get; set; } = 1f;

            [JsonProperty("Jump Force - Use Permission")]
            public float JumpForceUse { get; set; } = 14f;

            [JsonProperty("Jump Force - VIP1 Permission")]
            public float JumpForceVip1 { get; set; } = 17f;

            [JsonProperty("Jump Force - VIP2 Permission")]
            public float JumpForceVip2 { get; set; } = 20f;

            [JsonProperty("Jump Force - VIP3 Permission")]
            public float JumpForceVip3 { get; set; } = 23f;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<ConfigData>();
                if (config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            config = new ConfigData();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(config);
        }

        #endregion

        #region Localization

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["NoData"] = "<color=#ff6666>No position data available.</color>",
                ["JumpingCannotUse"] = "<color=#ff6666>Cannot use while jumping.</color>",
                ["NoValidPosition"] = "<color=#ff6666>No resettable position available. Use double jump first.</color>",
                ["PositionReset"] = "<color=#66ff66>Returned to position before double jump.</color>"
            }, this, "en");
        }

        private string Lang(string key, string userId = null) => lang.GetMessage(key, this, userId);

        #endregion

        #region Data

        private class JumpData
        {
            public float JumpTime;
            public bool CanDoubleJump;
            public float LastDoubleJumpTime;
            public bool IsJumping;
            public float DoubleJumpTime;
            public float DoubleJumpStartHeight;
            public float DoubleJumpPeakHeight;
            public Vector3 PreJumpPosition;
            public bool HasValidPreJumpPosition;
            public bool FallDamageImmune;
            public bool HasPermission;
            public float JumpForce;
        }

        private Dictionary<ulong, JumpData> playerJumpData = new Dictionary<ulong, JumpData>();
        private HashSet<JumpBooster> activeJumpBoosters = new HashSet<JumpBooster>();
        private HashSet<string> pluginPermissions = new HashSet<string> { PERM_USE, PERM_VIP1, PERM_VIP2, PERM_VIP3 };
        
        private HashSet<ulong> jumpButtonHeld = new HashSet<ulong>();

        #endregion

        #region Hooks

        private void Init()
        {
            permission.RegisterPermission(PERM_USE, this);
            permission.RegisterPermission(PERM_VIP1, this);
            permission.RegisterPermission(PERM_VIP2, this);
            permission.RegisterPermission(PERM_VIP3, this);
        }

        private void Unload()
        {
            foreach (var booster in activeJumpBoosters.ToArray())
            {
                if (booster != null)
                {
                    booster.Cleanup();
                }
            }
            activeJumpBoosters.Clear();
            playerJumpData.Clear();
            jumpButtonHeld.Clear();
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (player == null) return;

            var data = new JumpData();
            UpdatePermissionCache(player, data, "OnPlayerConnected");
            playerJumpData[player.userID] = data;
        }

        private void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player == null) return;

            playerJumpData.Remove(player.userID);
            jumpButtonHeld.Remove(player.userID);
        }

        private void OnServerInitialized()
        {
            foreach (var player in BasePlayer.activePlayerList)
            {
                if (!playerJumpData.ContainsKey(player.userID))
                {
                    var data = new JumpData();
                    UpdatePermissionCache(player, data, "OnServerInitialized");
                    playerJumpData[player.userID] = data;
                }
            }
        }

        private object OnPlayerLand(BasePlayer player, float num)
        {
            if (player == null) return null;

            if (playerJumpData.TryGetValue(player.userID, out JumpData data))
            {
                if (data.FallDamageImmune)
                {
                    float timeSinceDoubleJump = Time.realtimeSinceStartup - data.DoubleJumpTime;
                    float landingHeight = player.transform.position.y;
                    float fallDistance = data.DoubleJumpPeakHeight - landingHeight;

                    data.FallDamageImmune = false;

                    if (timeSinceDoubleJump <= FALL_DAMAGE_IMMUNITY_DURATION &&
                        fallDistance <= MAX_SAFE_FALL_HEIGHT &&
                        landingHeight >= data.DoubleJumpStartHeight - 3f)
                    {
                        player.fallVelocity = 0f;
                        return false;
                    }
                }
            }
            return null;
        }

        private object OnPlayerInput(BasePlayer player, InputState input)
        {
            if (input == null || player == null) return null;
            
            // Early filter
            if (!input.IsDown(BUTTON.JUMP) && !input.WasDown(BUTTON.JUMP))
            {
		///Puts("return");
                return null;
            }

            if (player.IsDead() || player.IsWounded() || player.isMounted || player.IsSleeping()) return null;

            ulong playerId = player.userID;
            bool isJumpPressed = input.IsDown(BUTTON.JUMP);
            
            if (!isJumpPressed)
            {
                jumpButtonHeld.Remove(playerId);
		///Puts("Remove");
                return null;
            }
            
            if (jumpButtonHeld.Contains(playerId))
            {
                return null;
            }

            jumpButtonHeld.Add(playerId);

            if (!playerJumpData.TryGetValue(playerId, out JumpData data))
            {
                data = new JumpData();
                UpdatePermissionCache(player, data, "OnPlayerInput (new data)");
                playerJumpData[playerId] = data;
            }

            if (!data.HasPermission) return null;
            if (data.IsJumping) return null;

            if (IsGrounded(player))
            {
                data.JumpTime = Time.realtimeSinceStartup;
                data.CanDoubleJump = true;
                data.FallDamageImmune = false;
            }
            else
            {
                if (data.CanDoubleJump)
                {
                    float currentTime = Time.realtimeSinceStartup;
                    float timeSinceJump = currentTime - data.JumpTime;
                    float timeSinceLastDouble = currentTime - data.LastDoubleJumpTime;

                    if (timeSinceJump <= DOUBLE_JUMP_WINDOW && timeSinceLastDouble > JUMP_COOLDOWN)
                    {
                        if (HasCeilingAbove(player))
                        {
                            return null;
                        }

                        if (player.metabolism.calories.value >= config.DoubleJumpCalorieCost)
                        {
                            player.metabolism.calories.Subtract(config.DoubleJumpCalorieCost);

                            data.PreJumpPosition = player.transform.position;
                            data.HasValidPreJumpPosition = true;

                            PerformDoubleJump(player, data, data.JumpForce);
                            data.CanDoubleJump = false;
                            data.LastDoubleJumpTime = currentTime;
                        }
                    }
                }
            }

            return null;
        }

        #endregion

        #region Permission Hooks

        private void OnUserPermissionGranted(string playerId, string perm)
        {
            if (!pluginPermissions.Contains(perm)) return;

            var player = BasePlayer.Find(playerId);
            if (player == null) return;

            if (playerJumpData.TryGetValue(player.userID, out JumpData data))
            {
                UpdatePermissionCache(player, data, $"OnUserPermissionGranted ({perm})");
            }
        }

        private void OnUserPermissionRevoked(string playerId, string perm)
        {
            if (!pluginPermissions.Contains(perm)) return;

            var player = BasePlayer.Find(playerId);
            if (player == null) return;

            if (playerJumpData.TryGetValue(player.userID, out JumpData data))
            {
                UpdatePermissionCache(player, data, $"OnUserPermissionRevoked ({perm})");
            }
        }

        private void OnGroupPermissionGranted(string group, string perm)
        {
            if (!pluginPermissions.Contains(perm)) return;

            if (DEBUG_MODE)
                Puts($"[Permission] Group '{group}' granted permission '{perm}', refreshing affected players");

            RefreshAllPlayersInGroup(group);
        }

        private void OnGroupPermissionRevoked(string group, string perm)
        {
            if (!pluginPermissions.Contains(perm)) return;

            if (DEBUG_MODE)
                Puts($"[Permission] Group '{group}' revoked permission '{perm}', refreshing affected players");

            RefreshAllPlayersInGroup(group);
        }

        private void OnUserGroupAdded(string playerId, string group)
        {
            var player = BasePlayer.Find(playerId);
            if (player == null) return;

            if (playerJumpData.TryGetValue(player.userID, out JumpData data))
            {
                UpdatePermissionCache(player, data, $"OnUserGroupAdded ({group})");
            }
        }

        private void OnUserGroupRemoved(string playerId, string group)
        {
            var player = BasePlayer.Find(playerId);
            if (player == null) return;

            if (playerJumpData.TryGetValue(player.userID, out JumpData data))
            {
                UpdatePermissionCache(player, data, $"OnUserGroupRemoved ({group})");
            }
        }

        #endregion

        #region Chat Commands

        [ChatCommand("posreset")]
        private void CmdPosReset(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;

            if (!playerJumpData.TryGetValue(player.userID, out JumpData data))
            {
                player.ChatMessage(Lang("NoData", player.UserIDString));
                return;
            }

            if (data.IsJumping)
            {
                player.ChatMessage(Lang("JumpingCannotUse", player.UserIDString));
                return;
            }

            if (!data.HasValidPreJumpPosition)
            {
                player.ChatMessage(Lang("NoValidPosition", player.UserIDString));
                return;
            }

            Vector3 targetPos = data.PreJumpPosition;

            if (Physics.Raycast(targetPos + Vector3.up * 2f, Vector3.down, out RaycastHit hit, 5f, PhysicsLayerMask))
            {
                targetPos = hit.point + Vector3.up * GROUND_OFFSET;
            }

            player.Teleport(targetPos);
            player.SendNetworkUpdateImmediate();
            player.ChatMessage(Lang("PositionReset", player.UserIDString));
        }

        #endregion

        #region Helper Methods

        private void UpdatePermissionCache(BasePlayer player, JumpData data, string source)
        {
            string id = player.UserIDString;
            string grantedPerm = null;

            data.HasPermission = false;
            data.JumpForce = config.JumpForceUse;

            if (permission.UserHasPermission(id, PERM_VIP3))
            {
                data.HasPermission = true;
                data.JumpForce = config.JumpForceVip3;
                grantedPerm = PERM_VIP3;
            }
            else if (permission.UserHasPermission(id, PERM_VIP2))
            {
                data.HasPermission = true;
                data.JumpForce = config.JumpForceVip2;
                grantedPerm = PERM_VIP2;
            }
            else if (permission.UserHasPermission(id, PERM_VIP1))
            {
                data.HasPermission = true;
                data.JumpForce = config.JumpForceVip1;
                grantedPerm = PERM_VIP1;
            }
            else if (permission.UserHasPermission(id, PERM_USE))
            {
                data.HasPermission = true;
                data.JumpForce = config.JumpForceUse;
                grantedPerm = PERM_USE;
            }

            if (DEBUG_MODE)
            {
                if (data.HasPermission)
                    Puts($"[Permission] {player.displayName} ({id}) - Source: {source} - HasPermission: true, Permission: {grantedPerm}, JumpForce: {data.JumpForce}");
                else
                    Puts($"[Permission] {player.displayName} ({id}) - Source: {source} - HasPermission: false");
            }
        }

        private void RefreshAllPlayersInGroup(string group)
        {
            foreach (var player in BasePlayer.activePlayerList)
            {
                if (permission.UserHasGroup(player.UserIDString, group))
                {
                    if (playerJumpData.TryGetValue(player.userID, out JumpData data))
                    {
                        UpdatePermissionCache(player, data, $"RefreshAllPlayersInGroup ({group})");
                    }
                }
            }
        }

        private bool IsGrounded(BasePlayer player)
        {
            if (player == null) return false;

            Vector3 position = player.transform.position + Vector3.up * 0.1f;

            if (Physics.Raycast(position, Vector3.down, GROUND_CHECK_DISTANCE + 0.1f, PhysicsLayerMask))
            {
                return true;
            }

            return player.IsOnGround();
        }

        private bool HasCeilingAbove(BasePlayer player)
        {
            if (player == null) return false;

            Vector3 position = player.transform.position + Vector3.up * 1.8f;

            if (Physics.Raycast(position, Vector3.up, out RaycastHit hit, CEILING_CHECK_DISTANCE, PhysicsLayerMask))
            {
                return true;
            }

            return false;
        }

        private void PerformDoubleJump(BasePlayer player, JumpData data, float jumpForce)
        {
            if (player == null) return;

            data.DoubleJumpStartHeight = player.transform.position.y;
            data.DoubleJumpPeakHeight = player.transform.position.y;
            data.DoubleJumpTime = Time.realtimeSinceStartup;
            data.FallDamageImmune = true;
            data.IsJumping = true;
            player.fallVelocity = 0f;

            JumpBooster.Create(this, player, data, jumpForce);
        }

        private void RegisterJumpBooster(JumpBooster booster)
        {
            if (booster != null)
            {
                activeJumpBoosters.Add(booster);
            }
        }

        private void UnregisterJumpBooster(JumpBooster booster)
        {
            if (booster != null)
            {
                activeJumpBoosters.Remove(booster);
            }
        }

        #endregion

        #region JumpBooster Class

        private class JumpBooster : FacepunchBehaviour
        {
            private HighJump plugin;
            private BasePlayer player;
            private JumpData jumpData;
            private BaseEntity boosterEntity;
            private Rigidbody rb;
            private float currentVelocity;

            public static void Create(HighJump plugin, BasePlayer player, JumpData data, float force)
            {
                Vector3 spawnPosition = player.transform.position + Vector3.up * BOOSTER_SPAWN_HEIGHT;

                var entity = GameManager.server.CreateEntity(
                    "assets/prefabs/misc/item drop/item_drop.prefab",
                    spawnPosition,
                    Quaternion.identity
                ) as DroppedItemContainer;

                if (entity == null)
                {
                    data.IsJumping = false;
                    return;
                }

                entity.enableSaving = false;
                entity.Spawn();

                Rigidbody rb = entity.GetComponent<Rigidbody>();
                if (rb == null)
                {
                    entity.Kill();
                    data.IsJumping = false;
                    return;
                }

                rb.isKinematic = true;
                rb.useGravity = false;

                player.SetParent(entity, true, true);

                JumpBooster booster = entity.gameObject.AddComponent<JumpBooster>();
                booster.plugin = plugin;
                booster.player = player;
                booster.jumpData = data;
                booster.boosterEntity = entity;
                booster.rb = rb;
                booster.currentVelocity = force;

                plugin.RegisterJumpBooster(booster);
            }

            private void FixedUpdate()
            {
                if (boosterEntity == null || boosterEntity.IsDestroyed || player == null || player.IsDead())
                {
                    Cleanup();
                    return;
                }

                float deltaTime = Time.fixedDeltaTime;
                currentVelocity -= GRAVITY * deltaTime;

                if (player.transform.position.y > jumpData.DoubleJumpPeakHeight)
                {
                    jumpData.DoubleJumpPeakHeight = player.transform.position.y;
                }

                if (currentVelocity > 0)
                {
                    Vector3 playerPos = player.transform.position;
                    float moveDistance = currentVelocity * deltaTime;

                    Vector3 rayOrigin = playerPos + Vector3.up * PLAYER_HEAD_OFFSET;

                    if (Physics.SphereCast(rayOrigin, CEILING_CHECK_RADIUS, Vector3.up, out RaycastHit ceilingHit, moveDistance + CEILING_CHECK_MARGIN, PhysicsLayerMask))
                    {
                        float safeDistance = Mathf.Max(0f, ceilingHit.distance - CEILING_SAFE_MARGIN);
                        if (safeDistance > 0.01f)
                        {
                            boosterEntity.transform.position += Vector3.up * safeDistance;
                        }

                        currentVelocity = 0f;
                        CleanupSafe();
                        return;
                    }

                    boosterEntity.transform.position += Vector3.up * moveDistance;
                }
                else
                {
                    Cleanup();
                }
            }

            private void CleanupSafe()
            {
                enabled = false;
                plugin?.UnregisterJumpBooster(this);

                if (player != null && !player.IsDead())
                {
                    Vector3 playerPos = player.transform.position;

                    if (playerPos.y > jumpData.DoubleJumpPeakHeight)
                    {
                        jumpData.DoubleJumpPeakHeight = playerPos.y;
                    }

                    player.SetParent(null, true, true);

                    Vector3 safePos = playerPos;

                    if (Physics.CheckSphere(playerPos + Vector3.up * STUCK_CHECK_HEIGHT, STUCK_CHECK_RADIUS, PhysicsLayerMask))
                    {
                        if (Physics.Raycast(playerPos + Vector3.up * SAFE_POS_RAY_START, Vector3.down, out RaycastHit groundHit, SAFE_POS_RAY_DISTANCE, PhysicsLayerMask))
                        {
                            safePos = groundHit.point + Vector3.up * GROUND_OFFSET;
                        }
                    }

                    player.Teleport(safePos);
                    player.fallVelocity = 0f;
                    player.SendNetworkUpdateImmediate();
                }

                if (jumpData != null)
                {
                    jumpData.IsJumping = false;
                }

                KillEntity();
            }

            public void Cleanup()
            {
                enabled = false;
                plugin?.UnregisterJumpBooster(this);

                if (player != null && !player.IsDead())
                {
                    if (player.transform.position.y > jumpData.DoubleJumpPeakHeight)
                    {
                        jumpData.DoubleJumpPeakHeight = player.transform.position.y;
                    }

                    player.SetParent(null, true, true);
                    player.fallVelocity = 0f;
                    player.SendNetworkUpdateImmediate();
                }

                if (jumpData != null)
                {
                    jumpData.IsJumping = false;
                }

                KillEntity();
            }

            private void KillEntity()
            {
                if (boosterEntity != null && !boosterEntity.IsDestroyed)
                {
                    var entityToKill = boosterEntity;
                    boosterEntity = null;

                    plugin?.NextTick(() =>
                    {
                        if (entityToKill != null && !entityToKill.IsDestroyed)
                        {
                            entityToKill.Kill();
                        }
                    });
                }

                Destroy(this);
            }

            private void OnDestroy()
            {
                plugin?.UnregisterJumpBooster(this);

                if (jumpData != null)
                {
                    jumpData.IsJumping = false;
                }
            }
        }

        #endregion
    }
}

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