using System.Collections.Generic; using Newtonsoft.Json; using System.Linq; using UnityEngine; namespace Oxide.Plugins { [Info("Fused Recycler", "Bazz3l", "1.0.4")] [Description("Recyclers will now require a fuse to recycle items.")] internal class FusedRecycler : RustPlugin { #region Fields private const string FUSEBOX_PREFAB = "assets/prefabs/io/electric/switches/fusebox/fusebox.prefab"; private const string DENIED_PREFAB = "assets/prefabs/locks/keypad/effects/lock.code.denied.prefab"; private readonly Quaternion _localRotation = new(0f, -0.7071068f, 0, 0.7071068f); private readonly Vector3 _localPosition = new(-0.93f, -0.6f, 0.25f); private readonly Effect _effect = new(); private readonly object _objTrue = true; private readonly object _objFalse = false; private PluginConfig _config; private bool _isShutdown; #endregion #region Config protected override void LoadDefaultConfig() => _config = PluginConfig.DefaultConfig(); protected override void LoadConfig() { base.LoadConfig(); try { _config = Config.ReadObject(); if (_config == null) throw new JsonException(); if (_config.ToDictionary().Keys .SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys)) return; PrintWarning("Config has been updated."); SaveConfig(); } catch { PrintWarning("Default config loaded."); LoadDefaultConfig(); } } protected override void SaveConfig() => Config.WriteObject(_config, true); private class PluginConfig { [JsonProperty("Enable player placed only recyclers")] public bool EnablePlayerPlacedOnly; [JsonProperty("Fuse durability per recycle")] public float FuseUseAmount; public string ToJson() => JsonConvert.SerializeObject(this); public Dictionary ToDictionary() => JsonConvert.DeserializeObject>(ToJson()); public static PluginConfig DefaultConfig() { return new PluginConfig { EnablePlayerPlacedOnly = false, FuseUseAmount = 10f }; } } #endregion #region Lang protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary {{ "NoFuse", "Please insert a fuse to power the Recycler." }}, this); } #endregion #region Oxide Hooks private void OnServerInitialized() { foreach (BaseNetworkable nEntity in BaseNetworkable.serverEntities) { if (nEntity is Recycler recycler && !recycler.IsDestroyed) TryCreateElectricalRecycler(recycler); } Subscribe(nameof(OnEntitySpawned)); } private void OnServerShutdown() { _isShutdown = true; } private void Init() { Unsubscribe(nameof(OnEntitySpawned)); } private void Unload() { if (_isShutdown) return; foreach (BaseNetworkable nEntity in BaseNetworkable.serverEntities) { if (nEntity is Recycler recycler && !recycler.IsDestroyed) TryRemoveElectricalRecycler(recycler); } } private void OnEntitySpawned(Recycler recycler) { TryCreateElectricalRecycler(recycler); } private void OnItemRecycle(Item item, Recycler recycler) { ItemBasedFlowRestrictor fuseBox = GetFuseBox(recycler); if (fuseBox == null) return; if (fuseBox.HasPassthroughItem()) fuseBox.inventory.GetSlot(0)?.LoseCondition(_config.FuseUseAmount); else recycler.StopRecycling(); } private object OnRecyclerToggle(Recycler recycler, BasePlayer player) { if (recycler.IsOn()) return null; ItemBasedFlowRestrictor fuseBox = GetFuseBox(recycler); if (fuseBox == null || fuseBox.HasPassthroughItem()) return null; SendPlayerSound(player); ShowPlayerToast(player, "NoFuse"); return _objFalse; } private object CanMoveItem(Item item, PlayerInventory playerLoot, ItemContainerId targetContainer, int targetSlot, int amount) { if (item?.GetRootContainer()?.entityOwner is not ItemBasedFlowRestrictor fuseBox || fuseBox.prefabID != 3622071578) return null; if (fuseBox.GetParentEntity() is Recycler recycler && recycler.IsOn()) return _objTrue; return null; } private void OnItemRemovedFromContainer(ItemContainer container, Item item) { if (container?.entityOwner is not ItemBasedFlowRestrictor fuseBox || fuseBox.prefabID != 3622071578) return; if (fuseBox.GetParentEntity() is Recycler recycler && recycler.IsOn()) recycler.StopRecycling(); } #endregion #region Fused Recycler private void TryCreateElectricalRecycler(Recycler recycler) { if (_config.EnablePlayerPlacedOnly && recycler.OwnerID == 0UL) return; if (HasFuseBox(recycler)) return; AttachFuseBox(recycler); } private void TryRemoveElectricalRecycler(Recycler recycler) { ItemBasedFlowRestrictor fuseBox = GetFuseBox(recycler); if (fuseBox == null) return; DropUtil.DropItems(fuseBox.inventory, recycler.GetDropPosition()); fuseBox.SetParent(null); fuseBox.KillMessage(); } private ItemBasedFlowRestrictor GetFuseBox(BaseEntity entity) { foreach (BaseEntity childEntity in entity.children) { if (childEntity != null && childEntity.prefabID == 3622071578 && childEntity.GetParentEntity()?.prefabID == 1729604075) return childEntity as ItemBasedFlowRestrictor; } return null; } private bool HasFuseBox(BaseEntity entity) => GetFuseBox(entity) != null; private void AttachFuseBox(Recycler recycler) { ItemBasedFlowRestrictor fuseBox = GameManager.server.CreateEntity(FUSEBOX_PREFAB, recycler.ServerPosition, recycler.ServerRotation) as ItemBasedFlowRestrictor; if (fuseBox == null) return; fuseBox.Spawn(); fuseBox.SetParent(recycler, 0u, true, true); fuseBox.transform.localPosition = _localPosition; fuseBox.transform.localRotation = _localRotation; fuseBox.SetFlag(BaseEntity.Flags.Reserved8, true); } #endregion #region Helpers private void ShowPlayerToast(BasePlayer player, string key, params object[] args) => player.ShowToast(0, string.Format(lang.GetMessage(key, this, player.UserIDString), args)); private void SendPlayerSound(BasePlayer player) { _effect.Clear(); _effect.Init(Effect.Type.Generic, player.ServerPosition, Vector3.zero); _effect.pooledString = DENIED_PREFAB; EffectNetwork.Send(_effect, player.Connection); } #endregion } }