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

FREE NWGProduction : 3.0.0 3.0.0

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

namespace Oxide.Plugins
{
    [Info("NWGProduction", "NWG Team", "3.0.0")]
    [Description("Optimized Smelting Controller and Furnace Splitter.")]
    public class NWGProduction : RustPlugin
    {
#region Configuration
        private class PluginConfig
        {
            public float GlobalSpeedMultiplier = 2.0f;
            public float FuelConsumptionMultiplier = 1.0f;
            public float CharcoalChance = 0.75f;
            public bool EnableAutoSplit = true;
            public Dictionary<string, float> SpeedModifiers = new Dictionary<string, float>
            {
                ["furnace.shortname"] = 1.0f,
                ["furnace.large"] = 2.0f,
                ["refinery_small_deployed"] = 1.0f,
                ["electric.furnace.deployed"] = 1.0f
            };
        }
        private PluginConfig _config;
#endregion

#region Lifecycle
        private void Init()
        {
            LoadConfigVariables();
        }

        private void LoadConfigVariables()
        {
            try
            {
                _config = Config.ReadObject<PluginConfig>();
                if (_config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                LoadDefaultConfig();
            }
        }

        protected override void LoadDefaultConfig()
        {
            Puts("Creating new configuration file for NWG Production");
            _config = new PluginConfig();
            SaveConfig();
        }


        protected override void SaveConfig() => Config.WriteObject(_config);
#endregion

#region Localization
        public static class Lang
        {
            public const string ConfigReloaded = "ConfigReloaded";
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                [Lang.ConfigReloaded] = "<color=#b7d092>[NWG]</color> Config reloaded."
            }, this);
        }

        private string GetMessage(string key, string userId, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);
#endregion

#region Smelting Controller
        // Hook called by the engine when an oven cooks
        private object OnOvenCook(BaseOven oven, Item fuel)
        {
            if (oven == null) return null;

            // 1. Get Speed Multiplier
            float speedMult = _config.GlobalSpeedMultiplier;
            if (_config.SpeedModifiers.TryGetValue(oven.ShortPrefabName, out float modifier))
                speedMult *= modifier;

            // If standard speed (1.0), do nothing, let Rust handle it
            if (speedMult <= 1.0f) return null;

            // 2. Accelerate Cooking
            // We simulate extra ticks. We do (Speed - 1) extra ticks.
            // e.g., Speed 2.0 means 1 normal tick + 1 extra tick.
            
            int extraTicks = Mathf.FloorToInt(speedMult) - 1;
            // Handle fractional speed (e.g. 1.5x)
            if (UnityEngine.Random.Range(0f, 1f) < (speedMult % 1)) extraTicks++;

            for (int i = 0; i < extraTicks; i++)
            {
                // Consume Fuel
                // We manually consume fuel here because we are bypassing the internal loop for these extra ticks
                // However, bypassing OnOvenCook recursively is tricky. 
                // Instead, we just call the cooking logic directly on the items.
                
                CookItems(oven);
            }

            // Return null to allow the default 1 tick to proceed as well
            return null;
        }

        private void CookItems(BaseOven oven)
        {
            // Simple iteration over inventory to cook items
            // This mirrors BaseOven.Cook() logic but optimized
            foreach (var item in oven.inventory.itemList.ToList()) 
            {
                if (item == null) continue;
                
                var cookable = item.info.GetComponent<ItemModCookable>();
                if (cookable == null) continue;

                // Check temperature requirements
                if (cookable.lowTemp > oven.cookingTemperature || cookable.highTemp < oven.cookingTemperature) continue;

                // Cook it
                // Logic: 1 ore -> cooked item
                // Use default rust logic for conversion rates (usually 1:1)
                
                // Be careful with concurrency modifying the list
                if (cookable.becomeOnCooked != null)
                {
                    int amountToCook = 1; 
                    if (item.amount < amountToCook) continue;

                    // Reduce raw
                    item.UseItem(amountToCook);

                    // Create cooked
                    var result = ItemManager.Create(cookable.becomeOnCooked, cookable.amountOfBecome * amountToCook);
                    if (result != null)
                    {
                        if (!result.MoveToContainer(oven.inventory))
                        {
                            result.Drop(oven.transform.position + Vector3.up, Vector3.up);
                        }
                    }
                }
            }
        }
        
        // Hook for fuel consumption
        private void OnFuelConsume(BaseOven oven, Item fuel, ItemModBurnable burnable)
        {
            // We can modify fuel consumption here
            // Usage: 1 means normal usage.
            // If we want 0.5x usage (efficient), we can add fuel back sometimes?
            // Or prevent consumption.
            
            if (_config.FuelConsumptionMultiplier < 1.0f)
            {
                 // Chance to refund the fuel used by the engine
                 if (UnityEngine.Random.Range(0f, 1f) > _config.FuelConsumptionMultiplier)
                 {
                     fuel.amount += 1; // Refund
                 }
            }
        }
#endregion

#region Splitter Logic
        // Hook: Called when an item is moved within/into an inventory
        private object CanMoveItem(Item item, PlayerInventory playerInventory, ItemContainerId targetContainerId, int targetSlot, int amount)
        {
            if (!_config.EnableAutoSplit) return null;
            if (item == null || playerInventory == null) return null;

            // Find target container
            var targetContainer = playerInventory.FindContainer(targetContainerId);
            if (targetContainer == null)
            {
                // Might be an entity container
                 var player = playerInventory.baseEntity;
                 // This hook logic is tricky in generic cases, simpler:
                 // Use OnItemAddedToContainer? No, that's too late for splitting effectively without reshuffling.
                 return null; 
            }
            
            // Check if target is an oven
            var oven = targetContainer.entityOwner as BaseOven;
            if (oven == null) return null;

            // Is it cookable?
            var cookable = item.info.GetComponent<ItemModCookable>();
            if (cookable == null) return null;

            // Split Logic
            // We want to distribute the stack across ALL available input slots
            // Return null to let default behavior happen if we don't want to interfere,
            // OR return true/false to override.
            
            // Simplified: If dragging a large stack, split it across empty slots.
            // We'll use a NextTick to reorganize to avoid fighting the drag event.
            
            NextTick(() => {
                if (oven == null || oven.IsDestroyed) return;
                SplitOres(oven);
            });

            return null;
        }
        
        private void OnItemAddedToContainer(ItemContainer container, Item item)
        {
            if (!_config.EnableAutoSplit) return;
            if (container.entityOwner is BaseOven oven)
            {
                 if (item.info.GetComponent<ItemModCookable>() != null)
                 {
                     // Re-balance logic
                     NextTick(() => SplitOres(oven));
                 }
            }
        }

        [ConsoleCommand("nwgproduction.reload")]
        private void ConsoleCmdReload(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !arg.Player().IsAdmin) return;
            LoadConfigVariables();
            arg.ReplyWith(GetMessage(Lang.ConfigReloaded, arg.Player()?.UserIDString));
        }

        private void SplitOres(BaseOven oven)
        {
            var container = oven.inventory;
            int maxSlots = oven.inputSlots;
            if (maxSlots <= 0) return;

            // Get all cookable items in input slots
            var ores = container.itemList
                .Where(x => x.position < maxSlots && x.info.GetComponent<ItemModCookable>() != null)
                .ToList();
            if (ores.Count == 0) return;

            // Group by item type
            var groups = ores.GroupBy(x => x.info.itemid).ToList();

            foreach (var group in groups)
            {
                int totalAmount = group.Sum(x => x.amount);
                if (totalAmount <= 0) continue;

                // Find slots available for this ore type (empty or same item)
                var availableSlots = Enumerable.Range(0, maxSlots)
                    .Where(i =>
                    {
                        var slot = container.GetSlot(i);
                        return slot == null || slot.info.itemid == group.Key;
                    })
                    .ToList();

                int splitCount = availableSlots.Count;
                if (splitCount <= 1) continue; // nothing to split

                int amountPerSlot = totalAmount / splitCount;
                int remainder = totalAmount % splitCount;
                if (amountPerSlot <= 0) continue;

                // Remove all existing items of this type from input slots
                var itemId = group.First().info.itemid;
                foreach (var item in group.ToList())
                    item.RemoveFromContainer();
                foreach (var item in group.ToList())
                    item.Remove();

                // Create balanced stacks in available slots
                for (int i = 0; i < splitCount; i++)
                {
                    int amount = amountPerSlot + (i < remainder ? 1 : 0);
                    if (amount <= 0) continue;

                    var newItem = ItemManager.CreateByItemID(itemId, amount);
                    if (newItem == null) continue;
                    newItem.MoveToContainer(container, availableSlots[i]);
                }
            }
        }
#endregion
    }
}

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