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

FREE DeployableZipline : 1.5.2 1.5.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
using static BaseEntity;
namespace Oxide.Plugins {
    [Info("Deployable Zipline", "BlackLightning", "1.5.2")]
    public class DeployableZipline : CovalencePlugin {
#region Fields
        [PluginReference]
        private Plugin Economics, NoEscape, ServerRewards;
        private const string DespawnConfigName = "DespawnConfig";
        private const string PermissionProtect = "deployablezipline.protect";
        private const string PermissionBuyTool = "deployablezipline.buy.tool";
        private const string PermissionBuyCable = "deployablezipline.buy.cable";
        private const string TeslaCoilPrefab = "assets/prefabs/deployable/playerioents/teslacoil/teslacoil.deployed.prefab";
        private const string LaunchPointPrefab = "assets/prefabs/building/powerline.zipline/ziplinelaunchpoint.prefab";
        private const string RemoverToolRefundItemName = "ZiplineCable";
        private const int AllowIgnoreLayers = 1 << (int)Rust.Layer.Deployed | 1 << (int)Rust.Layer.Tree;
        private const int MountCheckMask = 1 << (int)Rust.Layer.World | 1 << (int)Rust.Layer.Terrain | 1 << (int)Rust.Layer.Construction | 1 << (int)Rust.Layer.Prevent_Movement;
        private const float LowerSpearOffset = 0.37f;
        private const float UpperSpearOffset = 2.2f;
        private static readonly object False = false;
        private static readonly Vector3 TeslaCoilCableLocalOffset = new Vector3(0, 0.5f, 0);
        private static readonly Vector3 SpearCableLocalOffset = new Vector3(0, 2.6f, 0);
        private static readonly Vector3[] ExtraDismountPositions = {
            new Vector3(0, -1, 0)
        }
        ;
        private delegate void CalculateLinePointsDelegate(ZiplineLaunchPoint launchPoint, List<Vector3> targets, ref List<Vector3> points);
        private static readonly CalculateLinePointsDelegate ZLP_CalculateLinePointsDelegate = (CalculateLinePointsDelegate)Delegate.CreateDelegate(typeof(CalculateLinePointsDelegate), typeof(ZiplineLaunchPoint).GetMethod("CalculateZiplinePoints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
        private static readonly FieldInfo ZLP_LinePointsField = typeof(ZiplineLaunchPoint).GetField("linePoints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        private ItemDefinition _hammerItemDefinition;
        private ItemDefinition _toolgunItemDefinition;
        private ItemDefinition _spearItemDefinition;
        private ItemDefinition _laserSightItemDefinition;
        private ProtectionProperties _immortalProtection;
        private Configuration _config;
        private SavedData _data;
        private ZiplineManager _ziplineManager;
        private ToolSessionManager _toolSessionManager;
        private EconomicsPaymentProvider _economicsPaymentProvider;
        private ServerRewardsPaymentProvider _serverRewardsPaymentProvider;
        private readonly PreferencesManager _preferencesManager = new PreferencesManager();
        private readonly CooldownManager _toolCooldownManager = new CooldownManager();
        private readonly RemovableEntityInfo _removableEntityInfo = new RemovableEntityInfo();
        public DeployableZipline() {
            _economicsPaymentProvider = new EconomicsPaymentProvider(this);
            _serverRewardsPaymentProvider = new ServerRewardsPaymentProvider(this);
        }
#endregion
#region Hooks
        private void Init() {
            _config.Init(this);
            _data = SavedData.Load();
            _ziplineManager = new ZiplineManager(this);
            _toolSessionManager = new ToolSessionManager(this, _ziplineManager, _toolCooldownManager, _config, _data);
            permission.RegisterPermission(PermissionProtect, this);
            permission.RegisterPermission(PermissionBuyTool, this);
            permission.RegisterPermission(PermissionBuyCable, this);
            if (_config.CableItem?.ItemId == 0 || _config.CableItem?.ItemSkinId == 0) {
                Unsubscribe(nameof(CanBeRecycled));
            }
        }
        private void OnServerInitialized() {
        }
        private void OnServerInitialized(bool initial) {
            _hammerItemDefinition = ItemManager.FindItemDefinition("hammer");
            _toolgunItemDefinition = ItemManager.FindItemDefinition("toolgun");
            _spearItemDefinition = ItemManager.FindItemDefinition("speargun.spear");
            _laserSightItemDefinition = ItemManager.FindItemDefinition("weapon.mod.lasersight");
            _immortalProtection = ScriptableObject.CreateInstance<ProtectionProperties>();
            _immortalProtection.name = $"{nameof(DeployableZipline)}Protection";
            _immortalProtection.Add(1);
            _ziplineManager.OnServerInitialized(initial);
            foreach (var player in BasePlayer.activePlayerList) {
                if (player.IsSleeping()) continue;
                OnActiveItemChanged(player, null, player.GetActiveItem());
            }
        }
        private void OnNewSave() {
            _data.Reset();
        }
        private void OnServerSave() {
            _data.SaveIfNeeded();
        }
        private void Unload() {
            _data.SaveIfNeeded();
            _ziplineManager.Unload();
            UnityEngine.Object.Destroy(_immortalProtection);
        }
        private void OnPluginLoaded(Plugin plugin) {
            if (plugin.Name == DespawnConfigName) {
                _ziplineManager.CancelItemDespawn();
            }
        }
        private void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem) {
            if (!_config.ToolItem.ItemMatches(oldItem) && _config.ToolItem.ItemMatches(newItem)) {
                var profile = _config.GetToolProfile(permission, player.UserIDString);
                if (profile == null) {
                    ChatMessage(player, LangEntry.SelectErrorNoPermission);
                    return;
                }
                _toolSessionManager.StartPlayerSession(player, profile);
                var extraInfo = profile.AllowBidirectional ? (_preferencesManager.IsBidirectionalEnabled(player) ? $" {GetMessage(player.UserIDString, LangEntry.SelectInfoBidirectionalEnabled)}" : $" {GetMessage(player.UserIDString, LangEntry.SelectInfoBidirectionalDisabled)}") : string.Empty;
                ChatMessage(player, LangEntry.SelectInfo, extraInfo);
            }
        }
        private object CanCombineDroppedItem(DroppedItem itemEntity, DroppedItem otherItemEntity) {
            var item = itemEntity.item;
            var otherItem = otherItemEntity.item;
            if (item.info == _spearItemDefinition) {
                if (_ziplineManager.HasEntity(itemEntity) || _ziplineManager.HasEntity(otherItemEntity)) return False;
                return null;
            }
            var cableItem = _config.CableItem;
            if (cableItem.ItemId != 0 && cableItem.ItemSkinId != 0) {
                if (item.info.itemid != cableItem.ItemId || otherItem.info.itemid != cableItem.ItemId) return null;
                if ((item.skin == cableItem.ItemSkinId) != (otherItem.skin == cableItem.ItemSkinId)) return False;
                return null;
            }
            return null;
        }
        // Detect when the Spear is picked up.private object OnItemPickup(Item item, BasePlayer player)
        {
            if (item.info != _spearItemDefinition) return null;
            var entity = item.GetWorldEntity() as DroppedItem;
            if (entity == null) return null;
            var controller = _ziplineManager.GetController(entity);
            if (controller == null) return null;
            if (_config.PickupRestrictions.RequireToolToPickUp) {
                var activeItem = player.GetActiveItem();
                var activeItemDefinition = activeItem?.info;
                if (activeItemDefinition != _hammerItemDefinition && activeItemDefinition != _toolgunItemDefinition && !_config.ToolItem.ItemMatches(activeItem)) {
                    ChatMessage(player, LangEntry.PickupErrorToolRequired);
                    return False;
                }
            }
            if (!VerifyCanPickupZiplinePoint(player, entity, controller)) return False;
            GiveRefund(player, controller);
            entity.ClientRPC(null, "PickupSound");
            item.RemoveFromWorld();
            item.Remove();
            player.SignalBroadcast(Signal.Gesture, "pickup_item");
            return False;
        }
        // Detect when the Tesla Coil is picked up.private object CanPickupEntity(BasePlayer player, TeslaCoil entity)
        {
            var controller = _ziplineManager.GetController(entity);
            if (controller == null) return null;
            if (!VerifyCanPickupZiplinePoint(player, entity, controller)) return False;
            GiveRefund(player, controller);
            controller.Kill();
            return False;
        }
        private object CanMountEntity(BasePlayer player, ZiplineMountable ziplineMountable) {
            var mountPosition = ziplineMountable.endPosition;
            var controller = _ziplineManager.GetControllerByLaunchPoint(mountPosition);
            if (controller == null) return null;
            var capsuleHeight = 1.2f;
            var capsuleRadius = 0.4f;
            var pointA = mountPosition - new Vector3(0, capsuleRadius, 0);
            var pointB = mountPosition - new Vector3(0, capsuleRadius + capsuleHeight, 0);
            if (Physics.CheckCapsule(pointA, pointB, capsuleRadius, MountCheckMask, QueryTriggerInteraction.Ignore)) {
                ChatMessage(player, LangEntry.MountErrorNoSpace);
                return False;
            }
            return null;
        }
        private void OnEntityMounted(ZiplineMountable ziplineMountable, BasePlayer player) {
            var mountPosition = ziplineMountable.endPosition;
            bool isForwardLaunchPoint;
            var controller = _ziplineManager.GetControllerByLaunchPoint(mountPosition, out isForwardLaunchPoint);
            if (controller == null) return;
            // Raise the mount anchor so the player is where the mountable is (does not affect visuals).// This reduces the likelihood that they will technically clip into terrain violation.ziplineMountable.mountAnchor.localPosition = ziplineMountable.mountAnchor.localPosition.WithY(0);
            AddDismountPositions(ziplineMountable, ExtraDismountPositions);
            var ignoreColliders = ziplineMountable.ignoreColliders;
            if (ignoreColliders != null) {
                for (var i = ignoreColliders.Count - 1; i >= 0; i--) {
                    var collider = ignoreColliders[i];
                    if (((1 << collider.gameObject.layer) & AllowIgnoreLayers) == 0) {
                        ignoreColliders.RemoveAt(i);
                    }
                }
            }
            var speedProfile = _config.GetSpeedProfile(permission, player.UserIDString);
            if (speedProfile != null) {
                Vector3 startPoint;
                Vector3 endPoint;
                if (isForwardLaunchPoint) {
                    startPoint = controller.Data.StartPoint.Position;
                    endPoint = controller.Data.EndPoint.Position;
                }
                else {
                    startPoint = controller.Data.EndPoint.Position;
                    endPoint = controller.Data.StartPoint.Position;
                }
                var directionalMultiplier = 1f;
                var angle = AngleBetween(startPoint, endPoint);
                if (angle > 0) {
                    var speedPenalty = speedProfile.UphillSpeedPenalty;
                    directionalMultiplier = Mathf.Max(speedPenalty.MinSpeedPercent, 100f - angle * speedPenalty.PercentDecreasePerAngle) / 100f;
                }
                else if (angle < 0) {
                    var speedBonus = speedProfile.DownhillSpeedBonus;
                    directionalMultiplier = Mathf.Min(speedBonus.MaxSpeedPercent, 100f - angle * speedBonus.PercentIncreasePerAngle) / 100f;
                }
                ziplineMountable.MoveSpeed = speedProfile.MoveSpeed * directionalMultiplier;
                ziplineMountable.ForwardAdditive = speedProfile.BonusMoveSpeed * directionalMultiplier;
                ziplineMountable.SpeedUpTime = speedProfile.AccelerationTimeSeconds;
            }
        }
        // Only subscribed while Cable Item is valid and has a skin.private object CanBeRecycled(Item item, Recycler recycler)
        {
            if (item != null && item.skin == _config.CableItem?.ItemSkinId && item.info.Blueprint != null) return False;
            return null;
        }
        // RemoverTool
        private Dictionary<string, object> OnRemovableEntityInfo(BaseEntity entity, BasePlayer player) {
            var controller = _ziplineManager.GetController(entity);
            if (controller == null) return null;
            _removableEntityInfo.SetDisplayName(GetMessage(player.UserIDString, LangEntry.ZiplineName));
            var refundAmount = controller.GetRefundAmount();
            if (refundAmount > 0) {
                var cableName = GetMessage(player.UserIDString, LangEntry.CableName);
                _removableEntityInfo.SetRefund(cableName, refundAmount);
            }
            else {
                _removableEntityInfo.SetNoRefund();
            }
            return _removableEntityInfo.GetDictionary();
        }
        // RemoverTool
        private void OnRemovableEntityGiveRefund(BaseEntity entity, BasePlayer player, string itemName, int amount) {
            if (itemName != RemoverToolRefundItemName) return;
            var controller = _ziplineManager.GetController(entity);
            if (controller == null) return;
            GiveRefund(player, controller);
        }
        // RemoverTool
        private object canRemove(BasePlayer player, BaseEntity entity) {
            var controller = _ziplineManager.GetController(entity);
            if (controller == null) return null;
            if (controller.IsBusy()) return GetMessage(player.UserIDString, LangEntry.PickupErrorGeneric);
            if (controller.Data.Protected && !permission.UserHasPermission(player.UserIDString, PermissionProtect)) return GetMessage(player.UserIDString, LangEntry.ErrorNoPermission);
            if (!_config.PickupRestrictions.AllowPickupWhileBuildingBlockedAtOtherEnd) {
                var otherEntity = controller.GetOtherEntity(entity);
                if (otherEntity == null || otherEntity.IsDestroyed) return False;
                if (player.IsBuildingBlocked(otherEntity.WorldSpaceBounds())) {
                    return GetMessage(player.UserIDString, LangEntry.PickupErrorBuildingBlockedOtherEnd);
                }
            }
            return null;
        }
#endregion
#region Dependencies
        private bool IsRaidBlocked(BasePlayer player) {
            var result = NoEscape?.Call("IsRaidBlocked", player);
            return result is bool && (bool)result;
        }
        private bool IsCombatBlocked(BasePlayer player) {
            var result = NoEscape?.Call("IsCombatBlocked", player);
            return result is bool && (bool)result;
        }
#region Payment Providers
        private interface IPaymentProvider {
            int GetBalance(BasePlayer player);
            bool TakeBalance(BasePlayer player, int amount);
        }
        private class EconomicsPaymentProvider : IPaymentProvider {
            private DeployableZipline _plugin;
            private Plugin _ownerPlugin => _plugin.Economics;
            public EconomicsPaymentProvider(DeployableZipline plugin) {
                _plugin = plugin;
            }
            public bool IsAvailable => _ownerPlugin != null;
            public int GetBalance(BasePlayer player) {
                return Convert.ToInt32(_ownerPlugin.Call("Balance", player.userID));
            }
            public bool TakeBalance(BasePlayer player, int amount) {
                var result = _ownerPlugin.Call("Withdraw", player.userID, Convert.ToDouble(amount));
                return result is bool && (bool)result;
            }
        }
        private class ServerRewardsPaymentProvider : IPaymentProvider {
            private DeployableZipline _plugin;
            private Plugin _ownerPlugin => _plugin.ServerRewards;
            public ServerRewardsPaymentProvider(DeployableZipline plugin) {
                _plugin = plugin;
            }
            public bool IsAvailable => _ownerPlugin != null;
            public int GetBalance(BasePlayer player) {
                return Convert.ToInt32(_ownerPlugin.Call("CheckPoints", player.userID));
            }
            public bool TakeBalance(BasePlayer player, int amount) {
                var result = _ownerPlugin.Call("TakePoints", player.userID, amount);
                return result is bool && (bool)result;
            }
        }
        private class ItemsPaymentProvider : IPaymentProvider {
            private ItemDefinition _itemDefinition;
            private ulong _skinId;
            private int _itemId;
            public ItemDefinition ItemDefinition {
                get {
                    if (_itemDefinition == null) {
                        _itemDefinition = ItemManager.FindItemDefinition(_itemId);
                    }
                    return _itemDefinition;
                }
            }
            public ItemsPaymentProvider(int itemId, ulong skinId) {
                _itemId = itemId;
                _skinId = skinId;
            }
            public int GetBalance(BasePlayer player) {
                return SumPlayerItems(player, _itemId, _skinId);
            }
            public bool TakeBalance(BasePlayer player, int amount) {
                if (amount <= 0) return true;
                string displayName;
                TakePlayerItems(player, _itemId, _skinId, amount, out displayName);
                ShowGiveNotice(player, _itemId, -amount, displayName);
                return true;
            }
        }
#endregion
#region Remover Tool Integration
        private class RemovableEntityInfo {
            private const string DisplayNameField = "DisplayName";
            private const string RefundField = "Refund";
            private const string AmountField = "Amount";
            private Dictionary<string, object> _removeInfo;
            private Dictionary<string, object> _refundInfo;
            public RemovableEntityInfo() {
                _refundInfo = new Dictionary<string, object> {
                    [AmountField]
                    = 0,
                }
                ;
                _removeInfo = new Dictionary<string, object> {
                    ["Refund"]
                    = new Dictionary<string, object> {
                        [RemoverToolRefundItemName]
                        = _refundInfo,
                    }
                    ,
                }
                ;
            }
            public void SetDisplayName(string displayName) {
                _removeInfo[DisplayNameField] = displayName;
            }
            public void SetRefund(string displayName, int amount) {
                _refundInfo[DisplayNameField] = displayName;
                _refundInfo[AmountField] = amount;
            }
            public void SetNoRefund() {
                _refundInfo[AmountField] = 0;
            }
            public Dictionary<string, object> GetDictionary() {
                return _removeInfo;
            }
        }
#endregion
#endregion
#region Commands
        [Command("zipline")]
        private void CommandZipline(IPlayer player, string cmd, string[] args) {
            if (player.IsServer) return;
            var basePlayer = player.Object as BasePlayer;
            var firstArg = args.FirstOrDefault()?.ToLower();
            switch (firstArg) {
                case "buy" : {
                    var toolInfo = _config.ToolItem;
                    if (toolInfo.ItemDefinition == null) return;
                    if (!VerifyHasPermission(player, PermissionBuyTool)) return;
                    var costInfo = toolInfo.PurchaseInfo.Cost;
                    var paymentProvider = costInfo.GetPaymentProvider(_economicsPaymentProvider, _serverRewardsPaymentProvider);
                    var currentBalance = paymentProvider.GetBalance(basePlayer);
                    var currencyName = GetCurrencyName(player.Id, paymentProvider);
                    if (currentBalance < costInfo.Amount) {
                        ReplyToPlayer(player, LangEntry.PurchaseErrorInsufficientFunds, currentBalance, costInfo.Amount, currencyName);
                        return;
                    }
                    if (!paymentProvider.TakeBalance(basePlayer, costInfo.Amount)) {
                        ReplyToPlayer(player, LangEntry.PurchaseErrorPaymentFailed);
                        return;
                    }
                    var attachmentItemDefinitions = toolInfo.PurchaseInfo.AttachmentItemDefinitions;
                    var toolItem = toolInfo.CreateItem(1, "Zipline Tool");
                    if (toolItem.contents != null && attachmentItemDefinitions != null) {
                        foreach (var itemDefinition in attachmentItemDefinitions) {
                            toolItem.contents.AddItem(itemDefinition, 1);
                        }
                    }
                    if (attachmentItemDefinitions.Contains(_laserSightItemDefinition)) {
                        var heldEntity = toolItem.GetHeldEntity() as HeldEntity;
                        if (heldEntity != null) {
                            heldEntity.SetLightsOn(true);
                        }
                    }
                    var toolName = GetMessage(player.Id, LangEntry.ToolName);
                    GiveItem(basePlayer, toolItem, toolName, GiveItemReason.Crafted);
                    var message = GetMessage(player.Id, LangEntry.PurchaseToolSuccess, toolName);
                    if (costInfo.Amount > 0) {
                        message += $" {GetMessage(player.Id, LangEntry.PurchaseSuccessInfo, costInfo.Amount, currencyName)}";
                    }
                    player.Reply(message);
                    return;
                }
                case "buycable" : {
                    var cableInfo = _config.CableItem;
                    if (cableInfo.ItemDefinition == null) return;
                    if (!VerifyHasPermission(player, PermissionBuyCable)) return;
                    int buyAmount;
                    if (args.Length < 2 || !int.TryParse(args[1], out buyAmount)) {
                        ReplyToPlayer(player, LangEntry.PurchaseCableErrorSyntax, cmd);
                        return;
                    }
                    var costInfo = cableInfo.Cost;
                    var paymentProvider = costInfo.GetPaymentProvider(_economicsPaymentProvider, _serverRewardsPaymentProvider);
                    var currentBalance = paymentProvider.GetBalance(basePlayer);
                    var currencyName = GetCurrencyName(player.Id, paymentProvider);
                    var spendAmount = buyAmount * costInfo.Amount;
                    if (currentBalance < spendAmount) {
                        ReplyToPlayer(player, LangEntry.PurchaseErrorInsufficientFunds, currentBalance, spendAmount, currencyName);
                        return;
                    }
                    if (!paymentProvider.TakeBalance(basePlayer, spendAmount)) {
                        ReplyToPlayer(player, LangEntry.PurchaseErrorPaymentFailed);
                        return;
                    }
                    var cableItem = cableInfo.CreateItem(buyAmount, "Zipline Cable");
                    var cableName = GetMessage(player.Id, LangEntry.CableName);
                    GiveItem(basePlayer, cableItem, cableName, GiveItemReason.Crafted);
                    var message = GetMessage(player.Id, LangEntry.PurchaseCableSuccessInfo, buyAmount, cableName);
                    if (spendAmount > 0) {
                        message += $" {GetMessage(player.Id, LangEntry.PurchaseSuccessInfo, spendAmount, currencyName)}";
                    }
                    player.Reply(message);
                    return;
                }
                case "toggle" : {
                    var profile = _config.GetToolProfile(permission, player.Id);
                    if (profile == null) {
                        ReplyToPlayer(player, LangEntry.SelectErrorNoPermission);
                        return;
                    }
                    if (!profile.AllowBidirectional) {
                        ReplyToPlayer(player, LangEntry.BidirectionalErrorDisallowed);
                        return;
                    }
                    var isBidirectional = !_preferencesManager.IsBidirectionalEnabled(basePlayer);
                    _preferencesManager.SetBidirectional(basePlayer, isBidirectional);
                    var langKey = isBidirectional ? LangEntry.BidirectionalEnabled : LangEntry.BidirectionalDisabled;
                    ReplyToPlayer(player, langKey);
                    return;
                }
                case "protect" : {
                    if (!VerifyHasPermission(player, PermissionProtect)) return;
                    var protectionEnabled = !_preferencesManager.IsProtectionEnabled(basePlayer);
                    _preferencesManager.SetProtectionEnabled(basePlayer, protectionEnabled);
                    var langKey = protectionEnabled ? LangEntry.ProtectionEnabled : LangEntry.ProtectionDisabled;
                    ReplyToPlayer(player, langKey);
                    return;
                }
                default : {
                    // TODO: Print help commands
                    return;
                }
            }
        }
#endregion
#region Helper Methods
        private bool VerifyHasPermission(IPlayer player, string perm) {
            if (player.HasPermission(perm)) return true;
            ReplyToPlayer(player, LangEntry.ErrorNoPermission);
            return false;
        }
        private bool VerifyCanPickupZiplinePoint(BasePlayer player, BaseEntity entity, ZiplineController controller) {
            if (controller.IsBusy()) {
                ChatMessage(player, LangEntry.PickupErrorGeneric);
                return false;
            }
            if (controller.Data.Protected && !permission.UserHasPermission(player.UserIDString, PermissionProtect)) {
                ChatMessage(player, LangEntry.ErrorNoPermission);
                SendEffect(player, _config.Effects.PickupFailed);
                return false;
            }
            if (player.IsBuildingBlocked() || player.IsBuildingBlocked(entity.WorldSpaceBounds())) {
                ChatMessage(player, LangEntry.ErrorBuildingBlocked);
                SendEffect(player, _config.Effects.PickupFailed);
                return false;
            }
            if (!_config.PickupRestrictions.AllowPickupWhileBuildingBlockedAtOtherEnd) {
                var otherEntity = controller.GetOtherEntity(entity);
                if (otherEntity == null || otherEntity.IsDestroyed) return false;
                if (player.IsBuildingBlocked(otherEntity.WorldSpaceBounds())) {
                    ChatMessage(player, LangEntry.PickupErrorBuildingBlockedOtherEnd);
                    SendEffect(player, _config.Effects.PickupFailed);
                    return false;
                }
            }
            return true;
        }
        private void GiveRefund(BasePlayer player, ZiplineController controller) {
            var cableCost = controller.Profile.CableCost;
            if (cableCost == null || cableCost.CostPerMeter <= 0 || cableCost.RefundPerMeter <= 0) return;
            var refundAmount = controller.GetRefundAmount();
            if (refundAmount <= 0) return;
            var refundItem = _config.CableItem.CreateItem(refundAmount);
            if (refundItem == null) return;
            var itemName = GetMessage(player.UserIDString, LangEntry.CableName);
            GiveItem(player, refundItem, itemName, GiveItemReason.PickedUp);
        }
        private static void AddDismountPositions(ZiplineMountable ziplineMountable, Vector3[] dismountPositions) {
            var originalLength = ziplineMountable.dismountPositions.Length;
            Array.Resize(ref ziplineMountable.dismountPositions, originalLength + dismountPositions.Length);
            for (var i = 0; i < dismountPositions.Length; i++) {
                var transform = ziplineMountable.gameObject.CreateChild().transform;
                transform.localPosition = dismountPositions[i];
                ziplineMountable.dismountPositions[originalLength + i] = transform;
            }
        }
        private static float AngleBetween(Vector3 pointA, Vector3 pointB) {
            var directionalMultiplier = pointA.y < pointB.y ? 1 : -1;
            var yDistance = Mathf.Abs(pointA.y - pointB.y);
            var xZDistance = (pointA - pointB).MagnitudeXZ();
            return directionalMultiplier * Mathf.Atan2(yDistance, xZDistance) * Mathf.Rad2Deg;
        }
        private static bool IsBuildingBlocked(BasePlayer player, Vector3 position) {
            return player.IsBuildingBlocked(position, Quaternion.identity, default(Bounds));
        }
        private static bool UserHasPermission(Permission permission, UserData userData, string perm) {
            return userData.Perms.Contains(perm) || permission.GroupsHavePermission(userData.Groups, perm);
        }
        private static string FormatTime(float seconds) {
            return TimeSpan.FromSeconds(Math.Ceiling(seconds)).ToString("c");
        }
        private static BaseEntity FindEntity(ulong entityId) {
            return BaseNetworkable.serverEntities.Find(new NetworkableId(entityId)) as BaseEntity;
        }
        private static void ShowGiveNotice(BasePlayer player, int itemId, int amount, string name = null, GiveItemReason reason = GiveItemReason.Generic) {
            player.Command("note.inv", itemId, amount, name, (int)reason);
        }
        private static void GiveItem(BasePlayer player, Item item, string name, GiveItemReason reason = GiveItemReason.Generic) {
            if (!player.inventory.GiveItem(item)) {
                item.Drop(player.inventory.containerBelt.dropPosition, player.inventory.containerMain.dropVelocity);
            }
            ShowGiveNotice(player, item.info.itemid, item.amount, name, reason);
        }
        private static int SumContainerItems(ItemContainer container, int itemId, ulong skinId) {
            var sum = 0;
            foreach (var item in container.itemList) {
                if (item.info.itemid != itemId) continue;
                if (skinId != 0 && item.skin != skinId) continue;
                sum += item.amount;
            }
            return sum;
        }
        private static int SumPlayerItems(BasePlayer player, int itemId, ulong skinId) {
            return SumContainerItems(player.inventory.containerMain, itemId, skinId) + SumContainerItems(player.inventory.containerBelt, itemId, skinId);
        }
        private static int TakeContainerItems(ItemContainer container, int itemId, ulong skinId, int amountToTake, out string displayName) {
            displayName = null;
            if (amountToTake == 0) return 0;
            var amountTaken = 0;
            for (var i = container.itemList.Count - 1; i >= 0; i--) {
                var item = container.itemList[i];
                if (item.info.itemid != itemId) continue;
                if (skinId != 0 && item.skin != skinId) continue;
                displayName = item.name;
                var takeAmount = Math.Min(item.amount, amountToTake - amountTaken);
                item.amount -= takeAmount;
                amountTaken += takeAmount;
                if (item.amount <= 0) {
                    item.RemoveFromContainer();
                    item.Remove();
                }
                else {
                    item.MarkDirty();
                }
                if (amountTaken >= amountToTake) break;
            }
            return amountTaken;
        }
        private static int TakePlayerItems(BasePlayer player, int itemId, ulong skinId, int amountToTake, out string displayName) {
            var amountTaken = TakeContainerItems(player.inventory.containerMain, itemId, skinId, amountToTake, out displayName);
            if (amountTaken >= amountToTake) return amountTaken;
            amountTaken += TakeContainerItems(player.inventory.containerBelt, itemId, skinId, amountToTake - amountTaken, out displayName);
            return amountTaken;
        }
        private static void RunEffect(string effectPrefab, Vector3 position) {
            if (string.IsNullOrWhiteSpace(effectPrefab)) return;
            Effect.server.Run(effectPrefab, position);
        }
        private static void SendEffect(BasePlayer player, string effectPrefab, Vector3 position, Vector3 normal) {
            if (string.IsNullOrWhiteSpace(effectPrefab)) return;
            var effect = new Effect(effectPrefab, position, normal);
            EffectNetwork.Send(effect, player.net.connection);
        }
        private static void SendEffect(BasePlayer player, string effectPrefab) {
            if (string.IsNullOrWhiteSpace(effectPrefab)) return;
            var effect = new Effect(effectPrefab, player, 0, Vector3.zero, Vector3.forward);
            EffectNetwork.Send(effect, player.net.connection);
        }
        private static bool IsFacingUpward(Quaternion rotation) {
            return Vector3.Dot(rotation * Vector3.up, Vector3.up) > 0.5f;
        }
        private static Vector3 GetZiplineWorldOffset(Quaternion pointRotation) {
            var isTall = IsFacingUpward(pointRotation);
            var localOffset = isTall ? SpearCableLocalOffset : TeslaCoilCableLocalOffset;
            return pointRotation * localOffset;
        }
        private static void DestroyGroundWatch(BaseEntity entity) {
            UnityEngine.Object.DestroyImmediate(entity.GetComponent<GroundWatch>());
            UnityEngine.Object.DestroyImmediate(entity.GetComponent<DestroyOnGroundMissing>());
        }
        private static ZiplineLaunchPoint CreateLaunchPoint(Vector3 startPosition, Quaternion rotation, Vector3 endPosition, ulong ownerId) {
            var launchPoint = GameManager.server.CreateEntity(LaunchPointPrefab, startPosition, rotation) as ZiplineLaunchPoint;
            if (launchPoint == null) return null;
            launchPoint.ziplineTargets.Add(endPosition);
            launchPoint.OwnerID = ownerId;
            launchPoint.EnableSaving(false);
            launchPoint.Spawn();
            if (ZLP_CalculateLinePointsDelegate != null && ZLP_LinePointsField != null) {
                List<Vector3> linePoints = null;
                ZLP_CalculateLinePointsDelegate.Invoke(launchPoint, launchPoint.ziplineTargets, ref linePoints);
                ZLP_LinePointsField.SetValue(launchPoint, linePoints);
                var lastPosition = linePoints[linePoints.Count - 1];
                var direction = (lastPosition - linePoints[linePoints.Count - 2]).normalized;
                linePoints.Add(lastPosition + direction * 1.5f);
            }
            return launchPoint;
        }
        private BaseEntity CreateZiplinePoint(ZiplinePointData pointData, ulong ownerId, bool isTall, bool isUpper = false) {
            if (isTall) return CreateSpearPoint(pointData, ownerId, isUpper);
            return CreateTeslaCoilPoint(pointData, ownerId);
        }
        private static void HideInputsAndOutputs(IOEntity ioEntity) {
            foreach (var input in ioEntity.inputs) {
                input.type = IOEntity.IOType.Generic;
            }
            foreach (var output in ioEntity.outputs) {
                output.type = IOEntity.IOType.Generic;
            }
        }
        private static bool TryRaycast(BasePlayer player, out RaycastHit hit, float maxDistance, int layerMask = Rust.Layers.Solid) {
            return Physics.Raycast(player.eyes.HeadRay(), out hit, maxDistance, layerMask, QueryTriggerInteraction.Ignore);
        }
        private static bool TryCapsuleCast(Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask = Rust.Layers.Solid) {
            return Physics.CapsuleCast(point1, point2, radius, direction, out hitInfo, maxDistance, layerMask, QueryTriggerInteraction.Ignore);
        }
        private DroppedItem CreateSpearPoint(ZiplinePointData pointData, ulong ownerId, bool isUpper) {
            var rotation = pointData.Rotation * Quaternion.LookRotation(isUpper ? Vector3.up : Vector3.down);
            var position = pointData.Position + pointData.Rotation * new Vector3(0, isUpper ? UpperSpearOffset : LowerSpearOffset, 0);
            var item = ItemManager.Create(_spearItemDefinition);
            var spearEntity = item.CreateWorldObject(position, rotation) as DroppedItem;
            if (spearEntity == null) {
                item.Remove();
                return null;
            }
            spearEntity.OwnerID = ownerId;
            spearEntity.EnableSaving(false);
            spearEntity.CancelInvoke(spearEntity.IdleDestroy);
            spearEntity.syncPosition = false;
            if (spearEntity.PositionTickFixedTime) {
                spearEntity.CancelInvokeFixedTime(spearEntity.NetworkPositionTick);
            }
            else {
                spearEntity.CancelInvoke(spearEntity.NetworkPositionTick);
            }
            UnityEngine.Object.DestroyImmediate(spearEntity.GetComponent<Rigidbody>());
            UnityEngine.Object.DestroyImmediate(spearEntity.GetComponent<PhysicsEffects>());
            return spearEntity;
        }
        private TeslaCoil CreateTeslaCoilPoint(ZiplinePointData pointData, ulong ownerId) {
            var teslaCoil = GameManager.server.CreateEntity(TeslaCoilPrefab, pointData.Position, pointData.Rotation) as TeslaCoil;
            if (teslaCoil == null) return null;
            teslaCoil.baseProtection = _immortalProtection;
            DestroyGroundWatch(teslaCoil);
            HideInputsAndOutputs(teslaCoil);
            teslaCoil.OwnerID = ownerId;
            teslaCoil.EnableSaving(false);
            teslaCoil.Spawn();
            return teslaCoil;
        }
#endregion
#region Preferences Manager
        private class PlayerPreferences {
            public bool Bidirectional;
            public bool Protection;
        }
        private class PreferencesManager {
            private readonly Dictionary<ulong, PlayerPreferences> _playerPreferences = new Dictionary<ulong, PlayerPreferences>();
            public PlayerPreferences GetPlayerPreferences(BasePlayer player) {
                PlayerPreferences preferences;
                return _playerPreferences.TryGetValue(player.userID, out preferences) ? preferences : null;
            }
            public PlayerPreferences EnsurePreferences(BasePlayer player) {
                var preferences = GetPlayerPreferences(player);
                if (preferences == null) {
                    preferences = new PlayerPreferences();
                    _playerPreferences[player.userID] = preferences;
                }
                return preferences;
            }
            public bool IsBidirectionalEnabled(BasePlayer player) {
                return GetPlayerPreferences(player)?.Bidirectional ?? false;
            }
            public void SetBidirectional(BasePlayer player, bool value) {
                EnsurePreferences(player).Bidirectional = value;
            }
            public bool IsProtectionEnabled(BasePlayer player) {
                return GetPlayerPreferences(player)?.Protection ?? false;
            }
            public void SetProtectionEnabled(BasePlayer player, bool value) {
                EnsurePreferences(player).Protection = value;
            }
        }
#endregion
#region Tool Session Manager
        private class ToolSessionManager {
            private const float InputCooldownTime = 0.25f;
            private const int LOSCheckMask = 1 << (int)Rust.Layer.Default | 1 << (int)Rust.Layer.Deployed | 1 << (int)Rust.Layer.World | 1 << (int)Rust.Layer.Construction | 1 << (int)Rust.Layer.Terrain | 1 << (int)Rust.Layer.Vehicle_Large | 1 << (int)Rust.Layer.Tree;
            private class ToolSession {
                public BasePlayer Player {
                    get;
                }
                public ToolProfile Profile {
                    get;
                }
                public float LastInputTime;
                public ZiplinePointData StartPointData;
                public BaseEntity StartHostEntity;
                public ToolSession(BasePlayer player, ToolProfile profile) {
                    Player = player;
                    Profile = profile;
                    LastInputTime = UnityEngine.Time.time;
                }
            }
            private DeployableZipline _plugin;
            private ZiplineManager _ziplineManager;
            private CooldownManager _toolCooldownManager;
            private Configuration _config;
            private SavedData _data;
            private Timer _timer;
            private Action _handleTimerCached;
            private List<ToolSession> _sessions = new List<ToolSession>();
            private PreferencesManager _preferencesManager => _plugin._preferencesManager;
            public ToolSessionManager(DeployableZipline plugin, ZiplineManager ziplineManager, CooldownManager toolCooldownManager, Configuration config, SavedData data) {
                _plugin = plugin;
                _ziplineManager = ziplineManager;
                _toolCooldownManager = toolCooldownManager;
                _config = config;
                _data = data;
                _handleTimerCached = HandleTimer;
            }
            public void StartPlayerSession(BasePlayer player, ToolProfile profile) {
                var session = new ToolSession(player, profile);
                _sessions.Add(session);
                if (_timer == null || _timer.Destroyed) {
                    _timer = _plugin.timer.Every(0, _handleTimerCached);
                }
            }
            private bool CanUseWeapon(BasePlayer player) {
                if (player == null || player.IsDestroyed || !player.IsConnected || player.IsDead()) return false;
                var activeItem = player.GetActiveItem();
                if (activeItem == null) return false;
                return _config.ToolItem.ItemMatches(activeItem);
            }
            private bool VerifyLocationAcceptable(ToolSession session, PointRuleset ruleset, RaycastHit hit, bool isStart) {
                var player = session.Player;
                var collider = hit.collider;
                if (!ruleset.AllowWhileBuildingBlocked && IsBuildingBlocked(player, hit.point)) {
                    var langEntry = isStart ? LangEntry.DeployStartErrorBuildingBlocked : LangEntry.DeployEndBuildingBlocked;
                    _plugin.ChatMessage(player, langEntry);
                    return false;
                }
                if (ruleset.DisallowedTopologyMask != 0) {
                    var topology = TerrainMeta.TopologyMap.GetTopology(hit.point);
                    if (!ruleset.ShouldAllowTopology(topology)) {
                        var langEntry = isStart ? LangEntry.DeployStartErrorLocationRestricted : LangEntry.DeployEndErrorLocationRestricted;
                        _plugin.ChatMessage(player, langEntry);
                        return false;
                    }
                }
                if (ruleset.AllowedLayerMask != 0 && !ruleset.ShouldAllowLayer(collider.gameObject.layer)) {
                    var langEntry = isStart ? LangEntry.DeployStartErrorSurfaceRestricted : LangEntry.DeployEndErrorSurfaceRestricted;
                    _plugin.ChatMessage(player, langEntry);
                    return false;
                }
                if (ruleset.MinHeightAboveTerrain > 0) {
                    var diff = hit.point.y - TerrainMeta.HeightMap.GetHeight(hit.point);
                    if (diff < ruleset.MinHeightAboveTerrain) {
                        _plugin.ChatMessage(player, LangEntry.DeployErrorTooCloseToTerrain, diff, ruleset.MinHeightAboveTerrain);
                        return false;
                    }
                }
                if (ruleset.MaxDeployDistance > 0) {
                    var distance = Vector3.Distance(player.eyes.position, hit.point);
                    if (distance > ruleset.MaxDeployDistance) {
                        var langEntry = isStart ? LangEntry.DeployStartErrorMaxDistance : LangEntry.DeployEndErrorMaxDistance;
                        _plugin.ChatMessage(player, langEntry, distance, ruleset.MaxDeployDistance);
                        return false;
                    }
                }
                var entity = collider.ToBaseEntity();
                if (entity != null && collider.GetComponentInParent<Rigidbody>() != null) {
                    var langKey = isStart ? LangEntry.DeployStartErrorObjectRestricted : LangEntry.DeployEndErrorObjectRestricted;
                    _plugin.ChatMessage(player, langKey);
                    return false;
                }
                return true;
            }
            private bool HasMinimumRequiredCable(ToolSession session, out int minRequiredAmount) {
                minRequiredAmount = 0;
                var cableCost = session.Profile.CableCost;
                if (cableCost == null) return true;
                minRequiredAmount = session.Profile.GetMinCableRequired();
                if (minRequiredAmount < 0) return true;
                var currentAmount = SumPlayerItems(session.Player, _config.CableItem.ItemId, _config.CableItem.ItemSkinId);
                return currentAmount >= minRequiredAmount;
            }
            private bool VerifySufficientSpace(ToolSession session, RaycastHit hit) {
                var player = session.Player;
                var startPointData = session.StartPointData;
                var startPosition = startPointData.Position;
                var startRotation = startPointData.Rotation;
                var hitRotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
                var offsetStartPosition = startPosition + GetZiplineWorldOffset(startRotation);
                var offsetEndPosition = hit.point + GetZiplineWorldOffset(hitRotation);
                var capsuleHeight = 1.5f;
                var capsuleRadius = 0.25f;
                var startPointTop = offsetStartPosition - new Vector3(0, capsuleRadius, 0);
                va
// ... [Code preview truncated due to length. Full source in attached file] ...

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