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

FREE AutoCrafter : 1.0.4 1.0.4

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using Oxide.Plugins.AutoCrafterNamespace;
using Oxide.Plugins.AutoCrafterNamespace.Extensions;
using Rust;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Plugins.AutoCrafterNamespace.UI;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System.Globalization;
using ProtoBuf;
using Oxide.Plugins.AutoCrafterNamespace.JsonConverters;
namespace Oxide.Plugins {
    [Info("AutoCrafter", "Skipcast", "1.0.4", ResourceId = 2582)]
    [Description("A machine that automatically crafts items so the player can do more interesting stuff instead.")]
    public class AutoCrafter : RustPlugin {
        private readonly List<ItemAmount> UpgradeCost = new List<ItemAmount>();
        /// <summary>
        /// Used for keeping track of when research tables were placed so we know if enough time has passed that upgrading is impossible./// </summary>
        private readonly List<BaseEntity> upgradeableEntities = new List<BaseEntity>();
        /// <summary>
        /// List of players that have received the first join message./// </summary>
        private List<ulong> introducedPlayers = new List<ulong>();
        private bool serverInitialized = false;
#region Rust hooks
        private object OnItemCraft(ItemCraftTask task) {
            var player = task.owner;
            var crafter = CrafterManager.FindByPlayer(player);
            if (crafter != null && crafter.PlayerCanAccess(player)) {
                crafter.AddCraftTask(task);
                return true;
            }
            return null;
        }
        private void OnLootEntity(BasePlayer player, BaseEntity entity) {
            var recycler = entity as Recycler;
            if (recycler == null) return;
            var crafter = CrafterManager.GetCrafter(recycler);
            if (crafter == null) return;
            // Open the output container instead of the recycler ui.NextFrame(() =>
            {
                if (!crafter.PlayerCanAccess(player)) {
                    crafter.PlayLockedSound();
                    player.CloseInventory();
                    return;
                }
                player.inventory.loot.Clear();
                player.inventory.loot.StartLootingEntity(crafter.Output);
                player.inventory.loot.AddContainer(crafter.OutputInventory);
                player.inventory.loot.SendImmediate();
                player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", crafter.Output.lootPanelName);
                if (crafter.IsLocked()) crafter.PlayAccessSound();
            }
            );
        }
        void OnEntityGroundMissing(BaseEntity entity) {
            var recycler = entity as Recycler;
            if (recycler == null) return;
            var crafter = CrafterManager.GetCrafter(recycler);
            if (crafter == null) return;
            // Empty recycler, otherwise the hidden items inside it will drop into the world.recycler.inventory.Clear();
            recycler.inventory.itemList.Clear();
        }
        void OnEntitySpawned(BaseNetworkable networkable) {
            if (!serverInitialized)  // Check if server is initialized.This hook tends to call on startup before OnServerInitialized has been called.return;
            var entity = networkable as BaseEntity;
            if (entity == null) return;
            if (entity.OwnerID == 0) return;
            var researchTable = entity as ResearchTable;
            if (researchTable == null) return;
            upgradeableEntities.Add(researchTable);
            timer.Once(Constants.TimeToUpgrade, () => upgradeableEntities.Remove(researchTable));
        }
        void OnEntityKill(BaseNetworkable entity) {
            if (!serverInitialized)  // Check if server is initialized.This hook tends to call on startup before OnServerInitialized has been called.return;
            var researchTable = entity as ResearchTable;
            if (researchTable != null) {
                upgradeableEntities.Remove(researchTable);
            }
            var recycler = entity as Recycler;
            if (recycler == null) return;
            var crafter = CrafterManager.GetCrafter(recycler);
            if (crafter == null) return;
            CrafterManager.DestroyCrafter(crafter, false, false);
        }
        void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            float newHealth = entity.Health() - info.damageTypes.Total();
            // Empty recycler inventory if it's about to be killed to avoid dropping hidden items.if (newHealth <= 0)
            {
                var recycler = entity as Recycler;
                if (!(entity is Recycler)) return;
                var crafter = CrafterManager.GetCrafter(recycler);
                if (crafter == null) return;
                recycler.inventory.Clear();
                recycler.inventory.itemList.Clear();
            }
        }
        void OnPlayerInput(BasePlayer player, InputState input) {
            if (input.WasJustPressed(BUTTON.FIRE_PRIMARY)) {
                var activeItem = player.GetActiveItem();
                if (activeItem?.info.itemid != -975723312)  // Codelock
                return;
                var ray = player.eyes.HeadRay();
                RaycastHit hit;
                if (!Physics.Raycast(ray, out hit, 2.2f, 1 << (int) Layer.Deployed)) return;
                var recycler = hit.transform.GetComponentInParent<Recycler>();
                if (recycler == null) return;
                if (player.IsBuildingBlocked(recycler.ServerPosition, recycler.ServerRotation, recycler.bounds)) return;
                var crafter = CrafterManager.GetCrafter(recycler);
                if (crafter == null) return;
                if (crafter.AddCodeLock()) {
                    activeItem.UseItem();
                    FxManager.PlayFx(crafter.CodeLock.ServerPosition, Constants.CodelockPlaceSoundPrefab);
                }
            }
        }
        // Show message if enabled
        void OnPlayerSpawn(BasePlayer player) {
            if (!serverInitialized)  // Check if server is initialized.This hook tends to call on startup before OnServerInitialized has been called.return;
            timer.Once(1, () => {
                ShowJoinMessage(player);
            }
            );
        }
        // Make sure nothing is clipping into recycler.Pretty hacky method, but the recycler doesn't block things like other deployables.object CanBuild(Planner plan, Construction prefab, Vector3 position)
        {
            BasePlayer player = plan.GetOwnerPlayer();
            List<Recycler> recyclers = new List<Recycler>();
            Vis.Entities(position, prefab.bounds.size.magnitude / 3f, recyclers, 1 << (int) Layer.Deployed);
            if (recyclers.Count <= 0) {
                return null;
            }
            return true;
        }
        private object OnServerCommand(ConsoleSystem.Arg arg) {
            if (arg.Connection == null) return null;
            var player = (BasePlayer) arg.Connection.player;
            if (arg.cmd?.FullName == "craft.canceltask") {
                int taskid = arg.GetInt(0, -1);
                if (taskid == -1) return null;
                var crafters = CrafterManager.FindAllByPlayer(player);
                foreach (var crafter in crafters) {
                    if (crafter.CancelByTaskId(player, taskid)) return true;
                }
                return null;
            }
            return null;
        }
        private object OnHammerHit(BasePlayer player, HitInfo info) {
            var entity = info.HitEntity as BaseCombatEntity;
            var recycler = entity as Recycler;
            var researchTable = entity as ResearchTable;
            if (entity == null || (recycler == null && researchTable == null)) return null;
            Func<string> hpMessage = () => {
                return Lang.Translate(player, "hp-message", entity.Health(), entity.MaxHealth());
            }
            ;
            // Don't allow upgrading/downgrading/repairing if there's less than 8 seconds since the entity was attacked.if (entity.SecondsSinceAttacked < 8)
            {
                if (recycler != null && CrafterManager.ContainsRecycler(recycler)) {
                    // Show hp info if repairing is blocked.player.ShowScreenMessage(hpMessage(), 2);
                }
                return null;
            }
            if (!lastHammerHit.ContainsKey(player)) lastHammerHit[player] = 0;
            ((DecayEntity) entity).DecayTouch();
            // Reset decay
            // Make sure entity is full health, otherwise repair.if (entity.Health() < entity.MaxHealth())
            {
                if (recycler == null) return null;
                if (!CrafterManager.ContainsRecycler(recycler)) return null;
                if (Time.time - lastHammerHit[player] > Constants.HammerConfirmTime) {
                    player.ShowScreenMessage(hpMessage() + "\n\n" + Lang.Translate(player, "hit-again-to-repair"), Constants.HammerConfirmTime);
                    lastHammerHit[player] = Time.time;
                    return true;
                }
                lastHammerHit[player] = Time.time;
                player.HideScreenMessage();
                entity.DoRepair(player);
                player.ShowScreenMessage(hpMessage(), 2);
                // Reset last hammer hit so that the player won't accidentally downgrade/upgrade with the next hammer hit.if (entity.Health() >= entity.MaxHealth())
                {
                    lastHammerHit[player] = 0;
                }
                return true;
            }
            // Only allow upgrading/downgrading if we have building permission.if (player.IsBuildingBlocked(entity.ServerPosition, entity.ServerRotation, entity.bounds))
            {
                if (recycler != null && CrafterManager.ContainsRecycler(recycler))  // Only show hp info if this is a crafter
                {
                    // Show hp info if building blocked.player.ShowScreenMessage(hpMessage(), 2);
                }
                return null;
            }
            // Check permission and if the entity owner is the current player.if (!permission.UserHasPermission(player.UserIDString, Constants.UsePermission) || entity.OwnerID != player.userID)
            {
                if (recycler != null && CrafterManager.ContainsRecycler(recycler)) player.ShowScreenMessage(hpMessage(), 2);
                return null;
            }
            if (researchTable != null)  // Upgrade to crafter (if less than 10 minutes since placement)
            {
                if (!upgradeableEntities.Contains(researchTable)) return null;
                return HandleUpgradeRequest(player, researchTable);
            }
            var crafter = CrafterManager.GetCrafter(recycler);
            if (crafter == null) return null;
            if (DateTime.UtcNow - crafter.CreationTime > TimeSpan.FromSeconds(Constants.TimeToUpgrade)) {
                player.ShowScreenMessage(hpMessage(), 2);
                return null;
            }
            // Check if player has authed on potential codelock.if (!crafter.PlayerCanAccess(player))
            {
                crafter.PlayLockedSound();
                return true;
            }
            return HandleDowngradeRequest(player, crafter);
        }
        protected override void LoadDefaultConfig() {
            Utility.Config = new PluginConfig();
            Utility.Config.UpgradeCost.AddRange(new List<PluginConfig.ItemAmount> {
                new PluginConfig.ItemAmount("metal.refined", 25), new PluginConfig.ItemAmount("metal.fragments", 500), new PluginConfig.ItemAmount("techparts", 3), new PluginConfig.ItemAmount("gears", 3)
            }
            );
        }
        private void Loaded() {
            if (Utility.Config == null) {
                Utility.Config = Config.ReadObject<PluginConfig>();
                Config.WriteObject(Utility.Config);
                // Save any new or removed properties.}
                else {
                    Config.WriteObject(Utility.Config);
                }
            }
            private void OnServerInitialized() {
                Utility.Timer = timer;
                Config.Settings.AddConverters();
                permission.RegisterPermission(Constants.UsePermission, this);
                lang.RegisterMessages(Lang.DefaultMessages, this, "en");
                UiManager.Initialize();
                Lang.Initialize(this, lang);
                FxManager.Initialize();
                foreach (var itemAmount in Utility.Config.UpgradeCost) {
                    var itemDef = ItemManager.FindItemDefinition(itemAmount.Shortname);
                    if (itemDef == null) {
                        PrintError(Lang.Translate(null, "item-notfound-skipping-ingredient", itemAmount.Shortname));
                        continue;
                    }
                    UpgradeCost.Add(new ItemAmount(itemDef, itemAmount.Amount));
                }
                CrafterManager.Initialize();
                CrafterManager.Load();
                if (Utility.Config.ShowPlayerInstructionsOnFirstJoin) {
                    // Load previously introduced players
                    introducedPlayers = Core.Interface.Oxide.DataFileSystem.ReadObject<List<ulong>>("AutoCrafter/IntroducedPlayers");
                    foreach (var player in BasePlayer.activePlayerList) {
                        ShowJoinMessage(player);
                    }
                }
                serverInitialized = true;
            }
            private void OnServerSave() {
                CrafterManager.Save();
                if (Utility.Config.ShowPlayerInstructionsOnFirstJoin) {
                    Core.Interface.Oxide.DataFileSystem.WriteObject("AutoCrafter/IntroducedPlayers", introducedPlayers);
                }
            }
            private void Unload() {
                if (!serverInitialized)  // Check if server is initialized.This hook tends to call on startup before OnServerInitialized has been called.return;
                FxManager.Destroy();
                CrafterManager.Destroy();
                UiManager.Destroy();
            }
            private object OnRecycleItem(Recycler recycler, Item item) {
                if (CrafterManager.ContainsRecycler(recycler)) {
                    // Prevent recycling
                    return true;
                }
                return null;
            }
            object OnRecyclerToggle(Recycler recycler, BasePlayer player) {
                var crafter = CrafterManager.GetCrafter(recycler);
                if (crafter == null) return null;
                if (!crafter.PlayerCanAccess(player)) {
                    crafter.PlayLockedSound();
                    return true;
                }
                return null;
            }
            void OnUserPermissionGranted(string id, string perm) {
                if (perm == Constants.UsePermission) {
                    ShowJoinMessage(BasePlayer.Find(id));
                }
            }
            void OnGroupPermissionGranted(string name, string perm) {
                if (perm == Constants.UsePermission) {
                    foreach (var player in BasePlayer.activePlayerList) {
                        ShowJoinMessage(player);
                    }
                }
            }
#endregion
#region Chat commands
            [ChatCommand("autocrafter")]
            private void ChatCmd_Autocrafter(BasePlayer player, string command, string[] args) {
                if (!permission.UserHasPermission(player.UserIDString, Constants.UsePermission)) {
                    player.TranslatedChatMessage("nopermission");
                    return;
                }
                string submenu = args.FirstOrDefault();
                StringBuilder message = new StringBuilder();
                string title = null;
                Action appendMenus = () => {
                    message.AppendLine("- craft : " + Lang.Translate(player, "chat-description-craft"));
                    message.Append("- more : " + Lang.Translate(player, "chat-description-more"));
                }
                ;
                switch (submenu) {
                    default : {
                        message.Append(Lang.Translate(player, "chat-unknown-selection") + "\n");
                        appendMenus();
                        break;
                    }
                    case null : {
                        message.AppendLine(Lang.Translate(player, "chat-default-text"));
                        appendMenus();
                        break;
                    }
                    case "craft" : {
                        title = Lang.Translate(player, "chat-title-craft");
                        message.AppendLine(Lang.Translate(player, "chat-craft-text-top"));
                        foreach (var itemAmount in UpgradeCost) {
                            message.AppendLine("- " + itemAmount.amount + "x " + itemAmount.itemDef.displayName.english);
                        }
                        message.AppendLine();
                        message.AppendLine(Lang.Translate(player, "chat-craft-text-bottom"));
                        break;
                    }
                    case "usage" : {
                        title = Lang.Translate(player, "chat-title-usage");
                        message.AppendLine(Lang.Translate(player, "chat-usage-text"));
                        if (Utility.Config.ScanForWorldItems) {
                            message.AppendLine(Lang.Translate(player, "chat-usage-text-droptop"));
                        }
                        break;
                    }
                    case "more" : {
                        title = Lang.Translate(player, "chat-title-more");
                        message.AppendLine(Lang.Translate(player, "chat-more-text"));
                        break;
                    }
                }
                message.Insert(0, "<size=20>" + Lang.Translate(player, "chat-title") + (title != null ? (" - " + title) : "") + "</size>\n");
                player.ChatMessage(message.ToString());
            }
#endregion
            // For keeping track of how long ago they requested with the previous hammer hit.Used for confirming by hitting twice with hammer to upgrade, downgrade, or repair.private readonly Dictionary<BasePlayer, float> lastHammerHit = new Dictionary<BasePlayer, float>();
            // Return value:
            // - null = continue with default behaviour of hammer hit
            // - anything else: prevent default behaviour.private object HandleUpgradeRequest(BasePlayer player, ResearchTable researchTable)
            {
                if (UpgradeCost.Count > 0) {
                    if (!player.CanCraft(UpgradeCost)) {
                        StringBuilder builder = new StringBuilder();
                        foreach (var ingredient in UpgradeCost) {
                            builder.AppendLine("- x" + ingredient.amount.ToString("0") + " " + ingredient.itemDef.displayName.english);
                        }
                        string ingredientsStr = builder.ToString();
                        player.ShowScreenMessage(Lang.Translate(player, "ingredients-missing-youneed") + "\n" + ingredientsStr, 10, TextAnchor.MiddleLeft);
                        return true;
                    }
                }
                float lastHit = lastHammerHit[player];
                if (Time.time - lastHit > Constants.HammerConfirmTime)  // Confirm the upgrade
                {
                    lastHammerHit[player] = Time.time;
                    player.ShowScreenMessage(Lang.Translate(player, "hammer-confirm-upgrade"), Constants.HammerConfirmTime);
                    return true;
                }
                lastHammerHit[player] = 0;
                // Reset time
                foreach (var ingredient in UpgradeCost) {
                    List<Item> takenItems = new List<Item>();
                    player.inventory.Take(takenItems, ingredient.itemid, (int)ingredient.amount);
                }
                CrafterManager.CreateCrafter(researchTable);
                FxManager.PlayFx(researchTable.ServerPosition, Constants.UpgradeTopTierFxPrefab);
                player.HideScreenMessage();
                return true;
            }
            // Return value:
            // - null = continue with default behaviour of hammer hit
            // - anything else: prevent default behaviour.private object HandleDowngradeRequest(BasePlayer player, Crafter crafter)
            {
                float lastRequest = lastHammerHit[player];
                if (Time.time - lastRequest > Constants.HammerConfirmTime)  // Confirm the downgrade
                {
                    string message = Lang.Translate(player, "hp-message", crafter.Recycler.Health(), crafter.Recycler.MaxHealth());
                    message += "\n\n" + Lang.Translate(player, "hammer-confirm-downgrade");
                    lastHammerHit[player] = Time.time;
                    player.ShowScreenMessage(message, Constants.HammerConfirmTime);
                    return true;
                }
                lastHammerHit[player] = 0;
                // Reset time
                CrafterManager.DestroyCrafter(crafter, true, false);
                FxManager.PlayFx(crafter.Position, Constants.UpgradeMetalFxPrefab);
                player.HideScreenMessage();
                foreach (var itemAmount in UpgradeCost) {
                    player.GiveItem(ItemManager.CreateByItemID(itemAmount.itemid, (int) itemAmount.amount));
                }
                // Refund codelock if one is attached
                if (crafter.CodeLock != null) {
                    var item = ItemManager.Create(ItemManager.FindItemDefinition("lock.code"));
                    player.GiveItem(item);
                }
                return true;
            }
            private void ShowJoinMessage(BasePlayer player) {
                if (!Utility.Config.ShowPlayerInstructionsOnFirstJoin || !permission.UserHasPermission(player.UserIDString, Constants.UsePermission) || introducedPlayers.Contains(player.userID)) return;
                string message = Lang.Translate(player, "join-message");
                if (Utility.Config.ShowInstructionsAsGameTip) player.ShowGameTip(message, 10f);
                else player.ChatMessage(message);
                introducedPlayers.Add(player.userID);
            }
        }
    }
    namespace Oxide.Plugins.AutoCrafterNamespace {
        public static class Constants {
            public const string ItemDropPrefab = "assets/prefabs/misc/item drop/item_drop.prefab";
            public const string StaticRecyclerPrefab = "assets/bundled/prefabs/static/recycler_static.prefab";
            public const string DeployedResearchTablePrefab = "assets/prefabs/deployable/research table/researchtable_deployed.prefab";
            public const string StackSoundFxPrefab = "assets/bundled/prefabs/fx/notice/stack.world.fx.prefab";
            public const string UpgradeTopTierFxPrefab = "assets/bundled/prefabs/fx/build/promote_toptier.prefab";
            public const string UpgradeMetalFxPrefab = "assets/bundled/prefabs/fx/build/promote_metal.prefab";
            public const string CodelockPrefab = "assets/prefabs/locks/keypad/lock.code.prefab";
            public const string CodelockPlaceSoundPrefab = "assets/prefabs/locks/keypad/effects/lock-code-deploy.prefab";
            public const int RecyclerNumInputSlots = 6;
            public const float CrafterNearRadius = 0.6f;
            public const float HammerConfirmTime = 2f;
            public const float TimeToUpgrade = 600f;
            public const string UsePermission = "autocrafter.use";
        }
    }
    namespace Oxide.Plugins.AutoCrafterNamespace {
        public class Crafter {
            public delegate void PlayerEnterDelegate(Crafter crafter, BasePlayer player);
            public delegate void PlayerLeaveDelegate(Crafter crafter, BasePlayer player);
            public class CraftTask {
                [JsonIgnore]
                public ItemBlueprint Blueprint;
                public int Amount;
                public int SkinID;
                [JsonProperty("ItemID")]
                private int _itemid => Blueprint.targetItem.itemid;
                [JsonIgnore]
                public List<Item> TakenItems {
                    get;
                    set;
                }
                = new List<Item>();
                [JsonProperty("TakenItems")]
                private object _takenItems => TakenItems.Select(item => new {
                    item.info.itemid, item.skin, item.amount
                }
                ).ToList();
                /// <summary>
                /// Number of seconds this has been crafting for./// </summary>
                public float Elapsed;
                public CraftTask(ItemBlueprint blueprint, int amount, int skinId) {
                    Blueprint = blueprint;
                    Amount = amount;
                    SkinID = skinId;
                }
            }
            [JsonIgnore]
            public Recycler Recycler {
                get;
                private set;
            }
            [JsonIgnore]
            public Vector3 Position => Recycler.ServerPosition;
            /// <summary>
            /// Gets a list of players that are near the crafter, and should receive craft queue updates and be able to add/delete from queue
            /// </summary>
            [JsonIgnore]
            public List<BasePlayer> NearbyPlayers {
                get;
                private set;
            }
            = new List<BasePlayer>();
            public List<CraftTask> CraftingTasks {
                get;
                private set;
            }
            = new List<CraftTask>();
            [JsonIgnore]
            public ItemContainer OutputInventory => outputInventory;
            [JsonIgnore]
            public DroppedItemContainer Output => outputContainer;
            /// <summary>
            /// Gets the codelock on this crafter.May be null./// </summary>
            [JsonIgnore]
            public CodeLock CodeLock {
                get;
                private set;
            }
#region Json exclusive properties for saving/loading
            [JsonProperty("Code")]
            private string _code => CodeLock?.code;
            [JsonProperty("GuestCode")]
            private string _guestCode => CodeLock?.guestCode;
            [JsonProperty("AuthedPlayers")]
            private List<ulong> _authedPlayers => CodeLock?.whitelistPlayers;
            [JsonProperty("GuestPlayers")]
            private List<ulong> _guestPlayers => CodeLock?.guestPlayers;
            [JsonProperty("HasCodeLock")]
            private bool _hasCodelock => CodeLock != null;
            [JsonProperty("IsLocked")]
            private bool _locked => CodeLock?.IsLocked() ?? false;
            [JsonProperty("OutputItems")]
            private object _outputItems => OutputInventory.itemList.Select(item => {
                if (item.info.itemid == 98228420)  // Hidden item
                return null;
                return new {
                    item.position, item.info.itemid, item.amount, item.skin
                }
                ;
            }
            ).Where(obj => obj != null).ToList();
            [JsonProperty("On")]
            private bool _turnedOn => Recycler.IsOn();
            [JsonProperty("Health")]
            private float _health => Recycler.Health();
            [JsonProperty("DecayTimer")]
            private float _decayTimer => (float) (typeof (DecayEntity).GetField("decayTimer", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(Recycler) ?? 0f);
#endregion
            public event PlayerEnterDelegate PlayerEnter;
            public event PlayerLeaveDelegate PlayerLeave;
            /// <summary>
            /// Gets or sets the time this was created in UTC./// </summary>
            public DateTime CreationTime {
                get;
                set;
            }
            // Lookup table for players on each crafting task.private readonly Dictionary<BasePlayer, Dictionary<CraftTask, int>> taskLookup = new Dictionary<BasePlayer, Dictionary<CraftTask, int>>();
            private DroppedItemContainer outputContainer;
            private ItemContainer outputInventory;
            private readonly Timer resetDespawnTimer;
            private float nextPickup = Time.time;
            private const float pickupDelay = 0.5f;
            private float nextUiUpdate = Time.time;
            private const float uiUpdateDelay = 0.5f;
            /// <param name="recycler">The recycler entity we're "overwriting".</param>
            public Crafter(Recycler recycler) {
                CreationTime = DateTime.UtcNow;
                Recycler = recycler;
                CreateOutputContainer();
                // Reset despawn timer on loot bag once per minute.resetDespawnTimer = Utility.Timer.Every(60, () =>
                {
                    if (!outputContainer.IsDestroyed) outputContainer.ResetRemovalTime();
                }
                );
                recycler.gameObject.AddComponent<GroundWatch>();
                recycler.gameObject.AddComponent<DestroyOnGroundMissing>();
                recycler.repair.enabled = true;
                recycler.repair.itemTarget = ItemManager.FindItemDefinition("wall.frame.shopfront.metal");
                // Set health to 1000
                Recycler._maxHealth = 1000;
                Recycler.health = recycler.MaxHealth();
                // Set up damage protection
                Recycler.baseProtection.density = 4;
                for (int i = 0; i < Recycler.baseProtection.amounts.Length; ++i) {
                    Recycler.baseProtection.amounts[i] = Utility.Config.CrafterProtectionProperties[i];
                }
                // Set up decay
                var researchPrefab = GameManager.server.FindPrefab(Constants.DeployedResearchTablePrefab);
                // Copying decay settings from research table
                if (researchPrefab == null) {
                    Utility.LogWarning("Could not find research table prefab, skipping decay setup");
                }
                else {
                    uint prefabID = researchPrefab.GetComponent<BaseEntity>().prefabID;
                    var decay = PrefabAttribute.server.Find<Decay>(prefabID);
                    var decayPoints = PrefabAttribute.server.FindAll<DecayPoint>(prefabID);
                    typeof (DecayEntity).GetField("decay", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(Recycler, decay);
                    typeof (DecayEntity).GetField("decayPoints", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(Recycler, decayPoints);
                    BuildingManager.DecayEntities.Add(Recycler);
                }
            }
            private void CreateOutputContainer() {
                Vector3 position = Position + (Recycler.transform.forward * 0f) + (Recycler.transform.up * 0.72f) + (Recycler.transform.right * -0.25f);
                Quaternion rotation = Recycler.ServerRotation * Quaternion.Euler(90, 0, 0);
                outputContainer = CreateItemContainer(position, rotation, Lang.Translate(null, "crafted-items"), out outputInventory);
                var rigidBody = outputContainer.GetComponent<Rigidbody>();
                rigidBody.isKinematic = true;
                // Prevent physics from moving the container.// Add a hidden inventory slot in output container to prevent it from despawning when closing empty loot.outputInventory.capacity = 37;
                var item = ItemManager.Create(ItemManager.FindItemDefinition("gears"), 1);
                item.MoveToContainer(outputInventory, outputInventory.capacity - 1);
            }
            public void Tick(float elapsed) {
                if (outputContainer.IsDestroyed) {
                    CrafterManager.DestroyCrafter(this, false, destroyOutputContainer : false);
                    // Don't destroy output container because it's already destroyed.}
                    ProcessWorldItems();
                    ProcessNearbyPlayers();
                    ProcessQueue(elapsed);
                    ProcessUiUpdates();
                }
                /// <param name="unloading">Specify true if the plugin is unloading.</param>
                public void Destroy(bool destroyOutputContainer, bool unloading = false) {
                    resetDespawnTimer.DestroyToPool();
                    foreach (var player in NearbyPlayers) {
                        OnPlayerLeave(player);
                    }
                    if (!unloading) {
                        // Drop queue items
                        if (CraftingTasks.Count > 0) {
                            var container = new ItemContainer();
                            container.ServerInitialize(null, 36);
                            foreach (var task in CraftingTasks) {
                                foreach (var ingredient in task.Blueprint.ingredients) {
                                    var item = ItemManager.CreateByItemID(ingredient.itemid, (int) ingredient.amount * task.Amount);
                                    if (!item.MoveToContainer(container)) item.Drop(Position + Recycler.transform.up * 1.25f, Recycler.GetDropVelocity(), Recycler.ServerRotation);
                                }
                            }
                            var droppedContainer = container.Drop(Constants.ItemDropPrefab, Position + Recycler.transform.up * 1.25f, Recycler.ServerRotation);
                            droppedContainer.playerName = Lang.Translate(null, "queue-items");
                        }
                    }
                    Recycler.Kill();
                    CodeLock?.Kill();
                    if (!outputContainer.IsDestroyed) {
                        // Remove rock from output container that keeps it from despawning when emptied
                        outputInventory.GetSlot(outputInventory.capacity - 1).Remove();
                        // Force kill output bag if there's nothing in it.if (!destroyOutputContainer && OutputInventory.AnyItems())
                        {
                            // Enable physics on output container
                            outputContainer.GetComponent<Rigidbody>().isKinematic = false;
                        }
                        else {
                            outputContainer.Kill();
                        }
                    }
                }
                private void ProcessQueue(float elapsed) {
                    if (!Recycler.IsOn() || CraftingTasks.Count <= 0) return;
                    var currentTask = CraftingTasks.FirstOrDefault();
                    if (currentTask != null) {
                        currentTask.Elapsed += elapsed;
                        if (currentTask.Elapsed >= currentTask.Blueprint.time) {
                            ulong workshopSkinId = Rust.Global.SteamServer.Inventory.FindDefinition(currentTask.SkinID)?.GetProperty<ulong>("workshopdownload") ?? 0;
                            if (workshopSkinId == 0) workshopSkinId = (ulong)currentTask.SkinID;
                            var item = ItemManager.CreateByItemID(currentTask.Blueprint.targetItem.itemid, currentTask.Blueprint.amountToCreate, workshopSkinId);
                            if (!GiveItem(item)) {
                                item.Drop(Recycler.GetDropPosition(), Recycler.GetDropVelocity());
                                Recycler.StopRecycling();
                            }
                            currentTask.Amount -= 1;
                            currentTask.Elapsed -= currentTask.Blueprint.time;
                            // Take used items
                            foreach (var ingredient in currentTask.Blueprint.ingredients) {
                                foreach (var taskItem in currentTask.TakenItems) {
                                    if (taskItem.info.itemid != ingredient.itemid) continue;
                                    taskItem.amount -= (int) ingredient.amount;
                                    if (taskItem.amount <= 0) {
                                        taskItem.Remove();
                                        currentTask.TakenItems.Remove(taskItem);
                                    }
                                    break;
                                }
                            }
                            if (currentTask.Amount <= 0) {
                                // Remove from ui
                                foreach (var player in NearbyPlayers) {
                                    SendRemoveCraftingTask(player, currentTask);
                                }
                                CraftingTasks.RemoveAt(0);
                                // Stop recycler if there's nothing more to craft.if (CraftingTasks.Count <= 0)
                                {
                                    Recycler.StopRecycling();
                                }
                            }
                            else {
                                foreach (var player in NearbyPlayers) {
                                    SendCraftingTaskProgress(player, currentTask);
                                }
                            }
                        }
                    }
                }
                private void ProcessWorldItems() {
                    if (Utility.Config.ScanForWorldItems && Recycler.IsOn()) {
                        List<BaseEntity> entities = new List<BaseEntity>();
                        Vector3 position = Position + (Recycler.transform.up * 1.5f) + (Recycler.transform.forward * 0.1f) + (Recycler.transform.right * -0.25f);
                        float radius = 0.3f;
                        Vis.Entities(position, radius, entities);
                        entities = entities.Where(ent => ent.GetComponent<WorldItem>() != null).ToList();
                        if (nextPickup <= Time.time) {
                            foreach (var entity in entities) {
                                if (nextPickup > Time.time) break;
                                var worldItem = (WorldItem) entity;
                                bool partiallyInserted = false;
                                for (int i = 0; i < outputInventory.capacity - 1; ++i) {
                                    var slot = outputInventory.GetSlot(i);
                                    if (slot == null) {
                                        worldItem.item.MoveToContainer(outputInventory, i);
                                        partiallyInserted = true;
                                        break;
                                    }
                                    if (slot.info == worldItem.item.info && slot.skin == worldItem.item.skin && slot.amount < slot.info.stackable) {
                                        int available = slot.info.stackable - slot.amount;
                                        int toMove = Math.Min(available, worldItem.item.amount);
                                        worldItem.item.amount -= toMove;
                                        slot.amount += toMove;
                                        slot.MarkDirty();
                                        partiallyInserted = true;
                                        if (worldItem.item.amount <= 0) {
                                            worldItem.item.Remove();
                                            worldItem.Kill();
                                            break;
                                        }
                                    }
                                }
                                if (partiallyInserted) {
                                    FxManager.PlayFx(worldItem.ServerPosition, Constants.StackSoundFxPrefab);
                                }
                            }
                        }
                    }
                }
                private void ProcessNearbyPlayers() {
                    List<BasePlayer> nearPlayers = new List<BasePlayer>();
                    Vector3 checkPosition = Position + Recycler.transform.up * 0.75f + Recycler.transform.forward * 1f + Recycler.transform.right * -0.2f;
                    float checkRadius = Constants.CrafterNearRadius;
                    Vis.Entities(checkPosition, checkRadius, nearPlayers);
                    var previousNearbyPlayers = NearbyPlayers.ToList();
                    // Nearby players last tick
                    // Keep all players that are the following:
                    // - Alive and not sleeping
                    // - Has codelock access
                    // - Can see the recycler from their position, aka not behind a wall or anything
                    nearPlayers = nearPlayers.Where(plr => plr.IsAlive() && !plr.IsSleeping() && PlayerCanAccess(plr) && Recycler.IsVisible(plr.ServerPosition)).ToList();
                    var playersLeaving = previousNearbyPlayers.Where(plr => !nearPlayers.Contains(plr)).ToList();
                    var playersEntering = nearPlayers.Where(plr => !previousNearbyPlayers.Contains(plr)).ToList();
                    foreach (var player in playersLeaving) {
                        NearbyPlayers.Remove(player);
                        OnPlayerLeave(player);
                    }
                    foreach (var player in playersEntering) {
                        NearbyPlayers.Add(player);
                        OnPlayerEnter(player);
                    }
                    /*foreach (var player in BasePlayer.activePlayerList)
			{
				player.SendConsoleCommand("ddraw.sphere", 0.5f, Color.red, checkPosition, checkRadius);
			}*/
                }
                private void ProcessUiUpdates() {
                    if (!(Time.time > nextUiUpdate)) return;
                    nextUiUpdate = Time.time + uiUpdateDelay;
                    foreach (var player in NearbyPlayers) {
                        SendCraftingListUpdate(player);
                    }
                }
                /// <summary>
                /// Called when a player comes into range of this crafter./// </summary>
                private void OnPlayerEnter(BasePlayer player) {
                    if (CraftingTasks.Count > 0) {
                        SendCraftingList(player);
                    }
                    PlayerEnter?.Invoke(this, player);
                }
                /// <summary>
                /// Called when a player goes out of range of this crafter./// </summary>
                private void OnPlayerLeave(BasePlayer player) {
                    SendClearCraftingList(player);
                    PlayerLeave?.Invoke(this, player);
                }
                private void SendCraftingList(BasePlayer player) {
                    foreach (var task in CraftingTasks) {
                        SendAddCraftingTask(player, task);
                    }
                }
                private void SendCraftingListUpdate(BasePlayer player) {
                    foreach (var task in CraftingTasks) {
                        SendUpdateCraftingTask(player, task);
                    }
                }
                private void SendAddCraftingTask(BasePlayer player, CraftTask task) {
                    var crafting = player.inventory.crafting;
                    crafting.taskUID++;
                    // The reason for always sending 2 as amount is because if a craft task is started with 1 item, the amount counter won't show in clientside, even if amount is incremented later.// The real amount will be sent straight after, but then it will show with the counter, even if there's only 1.player.Command("note.craft_add", crafting.taskUID, task.Blueprint.targetItem.itemid, 2, task.SkinID);
                    // Correct the craft amount.player.Command("note.craft_done", crafting.taskUID, 0, task.Amount);
                    var dict = GetTaskLookupDict(player);
                    dict.Add(task, crafting.taskUID);
                }
                private void SendUpdateCraftingTask(BasePlayer player, CraftTask task) {
                    var lookup = GetTaskLookupDict(player);
                    int taskUID = lookup[task];
                    float time = task.Blueprint.time - task.Elapsed;
                    if (!Recycler.IsOn()) time = (float) Math.Ceiling(time) - 0.01f;
                    player.Command("note.craft_start", taskUID, time, task.Amount);
                }
                private void SendCraftingTaskProgress(BasePlayer player, CraftTask task) {
                    var lookup = GetTaskLookupDict(player);
                    var taskUID = lookup[task];
                    player.Command("note.craft_done", taskUID, 0, task.Amount);
                }
                private void SendClearCraftingList(BasePlayer player) {
                    var lookup = GetTaskLookupDict(player);
                    foreach (var kv in lookup.ToDictionary(kv => kv.Key, kv => kv.Value)) {
                        SendRemoveCraftingTask(player, kv.Key);
                    }
                }
                private void SendRemoveCraftingTask(BasePlayer player, CraftTask task) {
                    var lookup = GetTaskLookupDict(player);
                    int taskUID = lookup[task];
                    player.Command("note.craft_done", taskUID, 0);
                    lookup.Remove(task);
                }
                private Dictionary<CraftTask, int> GetTaskLookupDict(BasePlayer player) {
                    if (taskLookup.ContainsKey(player)) return taskLookup[player];
                    var dictionary = new Dictionary<CraftTask, int>();
                    taskLookup.Add(player, dictionary);
                    return dictionary;
                }
#region Public api methods
                public CraftTask AddCraftTask(ItemBlueprint blueprint, int amount, int skinId = 0, bool startRecycler = true, List<Item> takenItems = null) {
                    bool wasEmpty = CraftingTasks.Count == 0;
                    // Merge with current craft queue if the item is in queue with matching skin.var craftTask = CraftingTasks.FirstOrDefault(task => task.Blueprint.targetItem.itemid == blueprint.targetItem.itemid && task.SkinID == skinId);
                    if (craftTask != null) {
                        craftTask.Amount += amount;
                        // Send new amount to all players
                        foreach (var player in NearbyPlayers) {
                            SendCraftingTaskProgress(player, craftTask);
                        }
                        return craftTask
// ... [Code preview truncated due to length. Full source in attached file] ...

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