From 6fe25e10b2236b7c5b0e7ddc021e5c33aa4511d4 Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Sat, 6 Jun 2026 15:52:39 +0800 Subject: [PATCH 01/10] Port upstream upgrades and backpack interface systems - Add magnet, void, refill, compacting, everlasting, jukebox, tool swapper, tank, pump, battery, and anvil upgrades with advanced variants - Register upgrade capabilities, wrappers, items, recipes, models, textures, and localization - Extend backpack storage with fluid, energy, filtering, stash, and upgrade lookup support - Rework the backpack GUI with scrollable storage, inline settings mode, upgrade tabs, and side controls - Add backpack settings, item display settings, displayed item rendering, and item insert (+/-) - Synchronize upgrade insert/remove state across tabs, toggles, tank controls, battery controls, and storage layout --- .gitignore | 4 + build.gradle.kts | 2 +- .../capability/Capabilities.java | 87 ++ .../client/RenderStateHelper.java | 66 ++ .../mixin/EntityItemAccessor.java | 15 + .../mixin/GuiContainerAccessor.java | 19 + .../mixin/GuiContainerMixin.java | 8 + .../backpack/BackpackStashHelper.kt | 45 ++ .../backpack/DisplaySide.kt | 18 + .../block/BackpackBlock.kt | 37 +- .../capability/BackpackEnergyStorage.kt | 48 ++ .../capability/BackpackFluidHandler.kt | 55 ++ .../capability/BackpackWrapper.kt | 524 +++++++++++- .../upgrade/AdvancedFilterUpgradeWrapper.kt | 4 +- .../upgrade/AdvancedUpgradeWrapper.kt | 6 +- .../capability/upgrade/AnvilUpgradeWrapper.kt | 110 +++ .../capability/upgrade/BasicUpgradeWrapper.kt | 6 +- .../upgrade/BatteryUpgradeWrapper.kt | 134 ++++ .../upgrade/CompactingUpgradeWrapper.kt | 98 +++ .../upgrade/EverlastingUpgradeWrapper.kt | 24 + .../capability/upgrade/IAnvilUpgrade.kt | 40 + .../capability/upgrade/IBatteryUpgrade.kt | 41 + .../capability/upgrade/ICompactingUpgrade.kt | 17 + .../capability/upgrade/IEverlastingUpgrade.kt | 18 + .../capability/upgrade/IJukeboxUpgrade.kt | 36 + .../capability/upgrade/IMagnetUpgrade.kt | 18 + .../capability/upgrade/IPumpUpgrade.kt | 43 + .../capability/upgrade/IRefillUpgrade.kt | 17 + .../capability/upgrade/ITankUpgrade.kt | 41 + .../capability/upgrade/IToolSwapperUpgrade.kt | 29 + .../capability/upgrade/IVoidUpgrade.kt | 16 + .../upgrade/JukeboxUpgradeWrapper.kt | 257 ++++++ .../upgrade/MagnetUpgradeWrapper.kt | 43 + .../capability/upgrade/PumpUpgradeWrapper.kt | 275 +++++++ .../upgrade/RefillUpgradeWrapper.kt | 267 +++++++ .../capability/upgrade/TankUpgradeWrapper.kt | 218 +++++ .../upgrade/ToolSwapperUpgradeWrapper.kt | 271 +++++++ .../capability/upgrade/UpgradeFilterUtils.kt | 13 + .../capability/upgrade/UpgradeWrapper.kt | 2 + .../capability/upgrade/VoidUpgradeWrapper.kt | 110 +++ .../client/BackpackBlockEntityRenderer.kt | 46 ++ .../client/BackpackDisplayItemRenderer.kt | 77 ++ .../client/BackpackDynamicModel.kt | 20 +- .../client/BackpackItemStackRenderer.kt | 10 +- .../client/gui/BackpackPanel.kt | 753 ++++++++++++++++-- .../client/gui/BackpackSettingPanel.kt | 111 --- .../client/gui/RSBTextures.kt | 99 +++ .../client/gui/UpgradeSlotUpdateGroup.kt | 93 ++- .../gui/widgets/BackToBackpackTabWidget.kt | 59 ++ .../widgets/BackpackInventoryScrollWidget.kt | 71 ++ .../gui/widgets/BackpackMainSettingsWidget.kt | 160 ++++ .../widgets/BatteryInventoryControlWidget.kt | 91 +++ .../gui/widgets/CyclicVariantButtonWidget.kt | 5 +- .../gui/widgets/DynamicIconButtonWidget.kt | 18 + .../client/gui/widgets/ExpandedTabWidget.kt | 20 +- .../gui/widgets/ItemDisplaySettingsWidget.kt | 123 +++ .../client/gui/widgets/MemorySettingWidget.kt | 32 +- .../client/gui/widgets/SettingTabWidget.kt | 16 +- .../gui/widgets/SortingSettingWidget.kt | 26 +- .../client/gui/widgets/TabWidget.kt | 13 +- .../gui/widgets/TankInventoryControlWidget.kt | 101 +++ .../gui/widgets/UpgradeSlotGroupWidget.kt | 84 +- .../client/gui/widgets/slot/BackpackSlot.kt | 222 ++++-- .../gui/widgets/slot/NoBackgroundItemSlot.kt | 10 + .../widgets/upgrade/AdvancedFilterWidget.kt | 8 +- .../gui/widgets/upgrade/AnvilUpgradeWidget.kt | 91 +++ .../gui/widgets/upgrade/BasicFilterWidget.kt | 8 +- .../widgets/upgrade/BatteryUpgradeWidget.kt | 70 ++ .../upgrade/CompactingUpgradeWidget.kt | 65 ++ .../widgets/upgrade/JukeboxUpgradeWidget.kt | 84 ++ .../gui/widgets/upgrade/PumpUpgradeWidget.kt | 104 +++ .../widgets/upgrade/RefillUpgradeWidget.kt | 67 ++ .../gui/widgets/upgrade/TankUpgradeWidget.kt | 64 ++ .../upgrade/ToolSwapperUpgradeWidget.kt | 51 ++ .../gui/widgets/upgrade/VoidUpgradeWidget.kt | 71 ++ .../common/gui/BackpackContainer.kt | 164 ++-- .../common/gui/BackpackGuiHolder.kt | 28 +- .../common/gui/slot/ModularUpgradeSlot.kt | 6 +- .../handler/CapabilityHandler.kt | 171 +++- .../handler/ClientGuiStashHandler.kt | 163 ++++ .../handler/EntityEventHandler.kt | 155 +++- .../handler/KeyInputHandler.kt | 75 +- .../handler/NetworkHandler.kt | 16 +- .../inventory/BackpackItemStackHandler.kt | 6 + .../inventory/DelegatedItemHandler.kt | 24 +- .../inventory/UpgradeItemStackHandler.kt | 21 +- .../item/AnvilUpgradeItem.kt | 15 + .../item/BackpackItem.kt | 28 +- .../item/BatteryUpgradeItem.kt | 15 + .../item/CompactingUpgradeItem.kt | 6 + .../item/EverlastingUpgradeItem.kt | 6 + .../item/HiddenUpgradeItem.kt | 17 + .../retrosophisticatedbackpacks/item/Items.kt | 56 +- .../item/JukeboxUpgradeItem.kt | 16 + .../item/MagnetUpgradeItem.kt | 6 + .../item/PumpUpgradeItem.kt | 15 + .../item/RefillUpgradeItem.kt | 6 + .../item/TankUpgradeItem.kt | 16 + .../item/ToolSwapperUpgradeItem.kt | 16 + .../item/VoidUpgradeItem.kt | 6 + .../network/C2SRefillBlockPickPacket.kt | 63 ++ .../network/C2SStashToBackpackPacket.kt | 112 +++ .../proxy/RSBProxy.kt | 9 + .../sync/BackpackSH.kt | 55 +- .../sync/DelegatedStackHandlerSH.kt | 28 +- .../sync/UpgradeSlotSH.kt | 212 ++++- .../tileentity/BackpackTileEntity.kt | 75 +- .../util/DyeColorUtils.kt | 17 + .../lang/en_us.lang | 163 +++- .../lang/es_es.lang | 103 ++- .../lang/ja_jp.lang | 125 ++- .../lang/ko_kr.lang | 125 ++- .../lang/pl_pl.lang | 109 ++- .../lang/ru_ru.lang | 103 ++- .../lang/zh_cn.lang | 159 +++- .../lang/zh_tw.lang | 125 ++- .../models/block/backpack_left_tank.json | 144 ++++ .../models/block/backpack_right_tank.json | 135 ++++ .../item/advanced_compacting_upgrade.json | 6 + .../models/item/advanced_jukebox_upgrade.json | 6 + .../models/item/advanced_magnet_upgrade.json | 6 + .../models/item/advanced_pump_upgrade.json | 6 + .../models/item/advanced_refill_upgrade.json | 6 + .../item/advanced_tool_swapper_upgrade.json | 6 + .../models/item/advanced_void_upgrade.json | 6 + .../models/item/anvil_upgrade.json | 6 + .../models/item/battery_upgrade.json | 6 + .../models/item/compacting_upgrade.json | 6 + .../models/item/everlasting_upgrade.json | 6 + .../models/item/jukebox_upgrade.json | 6 + .../models/item/magnet_upgrade.json | 6 + .../models/item/pump_upgrade.json | 6 + .../models/item/refill_upgrade.json | 6 + .../models/item/tank_upgrade.json | 6 + .../models/item/tool_swapper_upgrade.json | 6 + .../models/item/void_upgrade.json | 6 + .../recipes/advanced_compacting_upgrade.json | 25 + .../recipes/advanced_jukebox_upgrade.json | 22 + .../recipes/advanced_magnet_upgrade.json | 25 + .../recipes/advanced_refill_upgrade.json | 25 + .../advanced_tool_swapper_upgrade.json | 22 + .../recipes/advanced_void_upgrade.json | 25 + .../recipes/compacting_upgrade.json | 25 + .../recipes/everlasting_upgrade.json | 22 + .../recipes/jukebox_upgrade.json | 25 + .../recipes/magnet_upgrade.json | 29 + .../recipes/refill_upgrade.json | 28 + .../recipes/tank_upgrade.json | 24 + .../recipes/tool_swapper_upgrade.json | 25 + .../recipes/void_upgrade.json | 25 + .../textures/gui/slots_background.png | Bin 2743 -> 7615 bytes .../textures/gui/storage_background_12.png | Bin 0 -> 980 bytes .../gui/storage_background_12_wider.png | Bin 0 -> 981 bytes .../textures/gui/storage_background_9.png | Bin 0 -> 4816 bytes .../gui/storage_background_9_wider.png | Bin 0 -> 1002 bytes .../item/empty_battery_input_slot.png | Bin 0 -> 132 bytes .../item/empty_battery_output_slot.png | Bin 0 -> 123 bytes .../textures/item/empty_tank_input_slot.png | Bin 0 -> 146 bytes .../textures/item/empty_tank_output_slot.png | Bin 0 -> 135 bytes .../textures/item/empty_upgrade_slot.png | Bin 0 -> 1260 bytes .../mixin.retro_sophisticated_backpacks.json | 2 + 161 files changed, 8848 insertions(+), 549 deletions(-) create mode 100644 src/main/java/com/cleanroommc/retrosophisticatedbackpacks/client/RenderStateHelper.java create mode 100644 src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/EntityItemAccessor.java create mode 100644 src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerAccessor.java create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackStashHelper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/DisplaySide.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackEnergyStorage.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidHandler.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/EverlastingUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAnvilUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBatteryUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ICompactingUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IEverlastingUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IJukeboxUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IPumpUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IRefillUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ITankUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IVoidUpgrade.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeFilterUtils.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackBlockEntityRenderer.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDisplayItemRenderer.kt delete mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackSettingPanel.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TankInventoryControlWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/AnvilUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BatteryUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CompactingUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/EverlastingUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/HiddenUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MagnetUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/PumpUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/RefillUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/TankUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/ToolSwapperUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/VoidUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SRefillBlockPickPacket.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SStashToBackpackPacket.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/DyeColorUtils.kt create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_left_tank.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_right_tank.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_compacting_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_jukebox_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_magnet_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_pump_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_refill_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_tool_swapper_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_void_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/anvil_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/battery_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/compacting_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/everlasting_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/jukebox_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/magnet_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/pump_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/refill_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/tank_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/tool_swapper_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/void_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_compacting_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_jukebox_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_magnet_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_refill_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_tool_swapper_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_void_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/compacting_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/everlasting_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/jukebox_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/magnet_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/refill_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/tank_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/tool_swapper_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/void_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_12.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_12_wider.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_9.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_9_wider.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_battery_input_slot.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_battery_output_slot.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_tank_input_slot.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_tank_output_slot.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_upgrade_slot.png diff --git a/.gitignore b/.gitignore index 2c770e0..101fc45 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,7 @@ build # other eclipse run + +source/ +docs/ +AGENTS.md \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 9b24871..c231bfd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,7 @@ plugins { id("maven-publish") id("org.jetbrains.gradle.plugin.idea-ext") version "1.1.7" id("eclipse") - id("com.gtnewhorizons.retrofuturagradle") version "1.3.27" + id("com.gtnewhorizons.retrofuturagradle") version "1.4.9" id("com.matthewprenger.cursegradle") version "1.4.0" } diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java index c8e8822..78c1643 100644 --- a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java @@ -44,6 +44,60 @@ public final class Capabilities { @CapabilityInject(AdvancedFilterUpgradeWrapper.class) public static final @NotNull Capability ADVANCED_FILTER_UPGRADE_WRAPPER_CAPABILITY = null; + @CapabilityInject(MagnetUpgradeWrapper.class) + public static final @NotNull Capability MAGNET_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AdvancedMagnetUpgradeWrapper.class) + public static final @NotNull Capability ADVANCED_MAGNET_UPGRADE_CAPABILITY = null; + + @CapabilityInject(VoidUpgradeWrapper.class) + public static final @NotNull Capability VOID_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AdvancedVoidUpgradeWrapper.class) + public static final @NotNull Capability ADVANCED_VOID_UPGRADE_CAPABILITY = null; + + @CapabilityInject(RefillUpgradeWrapper.class) + public static final @NotNull Capability REFILL_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AdvancedRefillUpgradeWrapper.class) + public static final @NotNull Capability ADVANCED_REFILL_UPGRADE_CAPABILITY = null; + + @CapabilityInject(CompactingUpgradeWrapper.class) + public static final @NotNull Capability COMPACTING_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AdvancedCompactingUpgradeWrapper.class) + public static final @NotNull Capability ADVANCED_COMPACTING_UPGRADE_CAPABILITY = null; + + @CapabilityInject(EverlastingUpgradeWrapper.class) + public static final @NotNull Capability EVERLASTING_UPGRADE_CAPABILITY = null; + + @CapabilityInject(ToolSwapperUpgradeWrapper.class) + public static final @NotNull Capability TOOL_SWAPPER_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AdvancedToolSwapperUpgradeWrapper.class) + public static final @NotNull Capability ADVANCED_TOOL_SWAPPER_UPGRADE_CAPABILITY = null; + + @CapabilityInject(TankUpgradeWrapper.class) + public static final @NotNull Capability TANK_UPGRADE_CAPABILITY = null; + + @CapabilityInject(JukeboxUpgradeWrapper.class) + public static final @NotNull Capability JUKEBOX_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AdvancedJukeboxUpgradeWrapper.class) + public static final @NotNull Capability ADVANCED_JUKEBOX_UPGRADE_CAPABILITY = null; + + @CapabilityInject(PumpUpgradeWrapper.class) + public static final @NotNull Capability PUMP_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AdvancedPumpUpgradeWrapper.class) + public static final @NotNull Capability ADVANCED_PUMP_UPGRADE_CAPABILITY = null; + + @CapabilityInject(BatteryUpgradeWrapper.class) + public static final @NotNull Capability BATTERY_UPGRADE_CAPABILITY = null; + + @CapabilityInject(AnvilUpgradeWrapper.class) + public static final @NotNull Capability ANVIL_UPGRADE_CAPABILITY = null; + // Abstract capabilities @CapabilityInject(UpgradeWrapper.class) public static final @NotNull Capability> UPGRADE_CAPABILITY = null; @@ -71,4 +125,37 @@ public final class Capabilities { @CapabilityInject(IFilterUpgrade.class) public static final @NotNull Capability IFILTER_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IMagnetUpgrade.class) + public static final @NotNull Capability IMAGNET_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IVoidUpgrade.class) + public static final @NotNull Capability IVOID_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IRefillUpgrade.class) + public static final @NotNull Capability IREFILL_UPGRADE_CAPABILITY = null; + + @CapabilityInject(ICompactingUpgrade.class) + public static final @NotNull Capability ICOMPACTING_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IEverlastingUpgrade.class) + public static final @NotNull Capability IEVERLASTING_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IToolSwapperUpgrade.class) + public static final @NotNull Capability ITOOL_SWAPPER_UPGRADE_CAPABILITY = null; + + @CapabilityInject(ITankUpgrade.class) + public static final @NotNull Capability ITANK_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IJukeboxUpgrade.class) + public static final @NotNull Capability IJUKEBOX_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IPumpUpgrade.class) + public static final @NotNull Capability IPUMP_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IBatteryUpgrade.class) + public static final @NotNull Capability IBATTERY_UPGRADE_CAPABILITY = null; + + @CapabilityInject(IAnvilUpgrade.class) + public static final @NotNull Capability IANVIL_UPGRADE_CAPABILITY = null; } diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/client/RenderStateHelper.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/client/RenderStateHelper.java new file mode 100644 index 0000000..6b6a4aa --- /dev/null +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/client/RenderStateHelper.java @@ -0,0 +1,66 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client; + +import net.minecraft.client.renderer.GlStateManager; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL14; + +import java.nio.ByteBuffer; + +@SideOnly(Side.CLIENT) +public final class RenderStateHelper { + private static final ByteBuffer COLOR_MASK = BufferUtils.createByteBuffer(16); + + private RenderStateHelper() { + } + + public static void syncGlStateManagerCache() { + forceSetToggle(GL11.glIsEnabled(GL11.GL_DEPTH_TEST), GlStateManager::enableDepth, GlStateManager::disableDepth); + forceSetToggle(GL11.glIsEnabled(GL11.GL_BLEND), GlStateManager::enableBlend, GlStateManager::disableBlend); + forceSetToggle(GL11.glIsEnabled(GL11.GL_CULL_FACE), GlStateManager::enableCull, GlStateManager::disableCull); + forceSetToggle(GL11.glIsEnabled(GL11.GL_LIGHTING), GlStateManager::enableLighting, GlStateManager::disableLighting); + forceSetToggle(GL11.glIsEnabled(GL11.GL_ALPHA_TEST), GlStateManager::enableAlpha, GlStateManager::disableAlpha); + forceSetToggle(GL11.glIsEnabled(GL11.GL_FOG), GlStateManager::enableFog, GlStateManager::disableFog); + GlStateManager.setActiveTexture(GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE)); + forceSetToggle(GL11.glIsEnabled(GL11.GL_TEXTURE_2D), GlStateManager::enableTexture2D, GlStateManager::disableTexture2D); + forceSetToggle(GL11.glIsEnabled(GL12.GL_RESCALE_NORMAL), GlStateManager::enableRescaleNormal, GlStateManager::disableRescaleNormal); + + boolean depthMask = GL11.glGetBoolean(GL11.GL_DEPTH_WRITEMASK); + GlStateManager.depthMask(!depthMask); + GlStateManager.depthMask(depthMask); + GlStateManager.depthFunc(GL11.glGetInteger(GL11.GL_DEPTH_FUNC)); + GlStateManager.alphaFunc(GL11.glGetInteger(GL11.GL_ALPHA_TEST_FUNC), GL11.glGetFloat(GL11.GL_ALPHA_TEST_REF)); + GlStateManager.tryBlendFuncSeparate( + GL11.glGetInteger(GL14.GL_BLEND_SRC_RGB), + GL11.glGetInteger(GL14.GL_BLEND_DST_RGB), + GL11.glGetInteger(GL14.GL_BLEND_SRC_ALPHA), + GL11.glGetInteger(GL14.GL_BLEND_DST_ALPHA) + ); + syncColorMask(); + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.color(0.0F, 0.0F, 0.0F, 0.0F); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.bindTexture(GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D)); + } + + private static void syncColorMask() { + COLOR_MASK.clear(); + GL11.glGetBoolean(GL11.GL_COLOR_WRITEMASK, COLOR_MASK); + GlStateManager.colorMask(COLOR_MASK.get(0) != 0, COLOR_MASK.get(1) != 0, COLOR_MASK.get(2) != 0, COLOR_MASK.get(3) != 0); + } + + private static void forceSetToggle(boolean desired, Runnable enable, Runnable disable) { + if (desired) { + disable.run(); + enable.run(); + } else { + enable.run(); + disable.run(); + } + } +} diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/EntityItemAccessor.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/EntityItemAccessor.java new file mode 100644 index 0000000..bc59f01 --- /dev/null +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/EntityItemAccessor.java @@ -0,0 +1,15 @@ +package com.cleanroommc.retrosophisticatedbackpacks.mixin; + +import net.minecraft.entity.item.EntityItem; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(EntityItem.class) +public interface EntityItemAccessor { + @Accessor("pickupDelay") + int rsb$getPickupDelay(); + + @Accessor("age") + void rsb$setAge(int age); + +} diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerAccessor.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerAccessor.java new file mode 100644 index 0000000..50e72f0 --- /dev/null +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerAccessor.java @@ -0,0 +1,19 @@ +package com.cleanroommc.retrosophisticatedbackpacks.mixin; + +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.inventory.Slot; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(GuiContainer.class) +public interface GuiContainerAccessor { + @Accessor("guiLeft") + int getGuiLeft(); + + @Accessor("guiTop") + int getGuiTop(); + + @Invoker("getSlotAtPosition") + Slot rsb$getSlotAtPosition(int mouseX, int mouseY); +} diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerMixin.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerMixin.java index 42917e2..efd466a 100644 --- a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerMixin.java +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/GuiContainerMixin.java @@ -1,5 +1,6 @@ package com.cleanroommc.retrosophisticatedbackpacks.mixin; +import com.cleanroommc.retrosophisticatedbackpacks.handler.ClientGuiStashHandler; import com.cleanroommc.retrosophisticatedbackpacks.handler.KeyInputHandler; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiContainer; @@ -14,4 +15,11 @@ public class GuiContainerMixin extends GuiScreen { private void keyTyped(char typedChar, int keyCode, CallbackInfo info) { KeyInputHandler.onKeyInputInGuiScreen(keyCode); } + + @Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true) + private void rsb$mouseClicked(int mouseX, int mouseY, int mouseButton, CallbackInfo info) { + if (ClientGuiStashHandler.handleMouseClicked((GuiContainer) (Object) this, mouseX, mouseY, mouseButton)) { + info.cancel(); + } + } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackStashHelper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackStashHelper.kt new file mode 100644 index 0000000..b2ae49c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackStashHelper.kt @@ -0,0 +1,45 @@ +package com.cleanroommc.retrosophisticatedbackpacks.backpack + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import net.minecraft.item.ItemStack +import net.minecraftforge.items.ItemHandlerHelper + +object BackpackStashHelper { + enum class Result { + MATCH_AND_SPACE, + SPACE, + NO_SPACE + } + + fun getStashResult(backpackStack: ItemStack, stack: ItemStack): Result { + val wrapper = backpackStack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return Result.NO_SPACE + return getStashResult(wrapper, stack) + } + + fun getStashResult(wrapper: BackpackWrapper, stack: ItemStack): Result { + if (stack.isEmpty || wrapper.insertStack(stack.copy(), true, true).count == stack.count) { + return Result.NO_SPACE + } + return if (hasMatchingStack(wrapper, stack) || hasMatchingMemory(wrapper, stack)) Result.MATCH_AND_SPACE else Result.SPACE + } + + fun stash(wrapper: BackpackWrapper, stack: ItemStack, simulate: Boolean): ItemStack = + wrapper.insertStack(stack.copy(), simulate, true) + + private fun hasMatchingStack(wrapper: BackpackWrapper, stack: ItemStack): Boolean = + (0 until wrapper.slots).any { + val slotStack = wrapper.getStackInSlot(it) + !slotStack.isEmpty && ItemHandlerHelper.canItemStacksStack(slotStack, stack) + } + + private fun hasMatchingMemory(wrapper: BackpackWrapper, stack: ItemStack): Boolean = + (0 until wrapper.backpackInventorySize()).any { + val memoryStack = wrapper.getMemorizedStack(it) + !memoryStack.isEmpty && if (wrapper.isMemoryStackRespectNBT(it)) { + ItemStack.areItemStacksEqual(stack, memoryStack) + } else { + stack.isItemEqualIgnoreDurability(memoryStack) + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/DisplaySide.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/DisplaySide.kt new file mode 100644 index 0000000..748f9e9 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/DisplaySide.kt @@ -0,0 +1,18 @@ +package com.cleanroommc.retrosophisticatedbackpacks.backpack + +enum class DisplaySide(val serializedName: String) { + FRONT("front"), + LEFT("left"), + RIGHT("right"); + + fun next(): DisplaySide = + entries[(ordinal + 1) % entries.size] + + fun previous(): DisplaySide = + entries[(ordinal + entries.size - 1) % entries.size] + + companion object { + fun fromName(name: String): DisplaySide = + entries.firstOrNull { it.serializedName == name } ?: FRONT + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt index 5316656..5c8cdc0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt @@ -2,7 +2,10 @@ package com.cleanroommc.retrosophisticatedbackpacks.block import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackTier +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.EverlastingUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.handler.RegistryHandler import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import com.cleanroommc.retrosophisticatedbackpacks.util.IModelRegister @@ -178,6 +181,14 @@ class BackpackBlock( val tileEntity = worldIn.getTileEntity(pos) as? BackpackTileEntity ?: return tileEntity.wrapper.deserializeNBT(backpackInventory.serializeNBT()) + val (leftTank, rightTank) = tileEntity.wrapper.tankRenderSides() + worldIn.setBlockState( + pos, + state.withProperty(LEFT_TANK, leftTank) + .withProperty(RIGHT_TANK, rightTank) + .withProperty(BATTERY, tileEntity.wrapper.hasBatteryUpgrade()), + 3 + ) } override fun onBlockActivated( @@ -193,6 +204,11 @@ class BackpackBlock( ): Boolean { if (!worldIn.isRemote) { if (playerIn.isSneaking) { + val tileEntity = worldIn.getTileEntity(pos) as? BackpackTileEntity + if (tileEntity?.wrapper?.hasEverlastingUpgrade() == true) { + return true + } + tileEntity?.wrapper?.stopJukeboxUpgrades() worldIn.playSound(playerIn, pos, SoundEvents.BLOCK_CLOTH_BREAK, SoundCategory.BLOCKS, 1f, 0.5f) dropBlockAsItem(worldIn, pos, state, 0) worldIn.setBlockState(pos, net.minecraft.init.Blocks.AIR.defaultState) @@ -235,6 +251,9 @@ class BackpackBlock( fortune: Int ) { val tileEntity = world.getTileEntity(pos) as? BackpackTileEntity ?: return + if (tileEntity.wrapper.hasEverlastingUpgrade()) { + return + } val stack = ItemStack(Item.getItemFromBlock(this)) val tileEntityBackpackInventory = tileEntity.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return val stackBackpackInventory = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return @@ -250,6 +269,11 @@ class BackpackBlock( player: EntityPlayer, willHarvest: Boolean ): Boolean { + val tileEntity = world.getTileEntity(pos) as? BackpackTileEntity + if (tileEntity?.wrapper?.hasEverlastingUpgrade() == true) { + return false + } + tileEntity?.wrapper?.stopJukeboxUpgrades() if (willHarvest) return true return super.removedByPlayer(state, world, pos, player, false) } @@ -265,4 +289,15 @@ class BackpackBlock( super.harvestBlock(worldIn, player, pos, state, te, stack) worldIn.setBlockToAir(pos) } -} \ No newline at end of file + + private fun BackpackWrapper.hasEverlastingUpgrade(): Boolean = + gatherCapabilityUpgrades(Capabilities.EVERLASTING_UPGRADE_CAPABILITY) + .filterIsInstance() + .isNotEmpty() + + private fun BackpackWrapper.stopJukeboxUpgrades() { + gatherCapabilityUpgrades(Capabilities.IJUKEBOX_UPGRADE_CAPABILITY) + .filterIsInstance() + .forEach { it.requestStop() } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackEnergyStorage.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackEnergyStorage.kt new file mode 100644 index 0000000..d4ba2de --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackEnergyStorage.kt @@ -0,0 +1,48 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability + +import net.minecraftforge.energy.IEnergyStorage + +class BackpackEnergyStorage(private val wrapper: BackpackWrapper) : IEnergyStorage { + private fun batteries() = + wrapper.gatherCapabilityUpgrades(Capabilities.IBATTERY_UPGRADE_CAPABILITY) + + override fun receiveEnergy(maxReceive: Int, simulate: Boolean): Int { + var remaining = maxReceive + var received = 0 + for (battery in batteries()) { + val moved = battery.receiveEnergy(wrapper, remaining, simulate) + received += moved + remaining -= moved + if (remaining <= 0) { + break + } + } + return received + } + + override fun extractEnergy(maxExtract: Int, simulate: Boolean): Int { + var remaining = maxExtract + var extracted = 0 + for (battery in batteries()) { + val moved = battery.extractEnergy(wrapper, remaining, simulate) + extracted += moved + remaining -= moved + if (remaining <= 0) { + break + } + } + return extracted + } + + override fun getEnergyStored(): Int = + batteries().fold(0) { acc, battery -> acc + battery.energyStored } + + override fun getMaxEnergyStored(): Int = + batteries().fold(0) { acc, battery -> acc + battery.getMaxEnergyStored(wrapper) } + + override fun canExtract(): Boolean = + batteries().any { it.canExtractEnergy } + + override fun canReceive(): Boolean = + batteries().any { it.canReceiveEnergy } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidHandler.kt new file mode 100644 index 0000000..cdcfda1 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidHandler.kt @@ -0,0 +1,55 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.TankUpgradeWrapper +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.capability.IFluidHandler +import net.minecraftforge.fluids.capability.IFluidTankProperties + +class BackpackFluidHandler(private val wrapper: BackpackWrapper) : IFluidHandler { + private fun tanks(): List = + wrapper.gatherCapabilityUpgrades(Capabilities.TANK_UPGRADE_CAPABILITY) + .filterIsInstance() + + override fun getTankProperties(): Array = + tanks().flatMap { it.getTankProperties(wrapper).toList() }.toTypedArray() + + override fun fill(resource: FluidStack?, doFill: Boolean): Int { + if (resource == null || resource.amount <= 0) { + return 0 + } + var filled = 0 + for (tank in tanks()) { + val toFill = FluidStack(resource.fluid, resource.amount - filled, resource.tag?.copy()) + filled += tank.fill(wrapper, toFill, doFill) + if (filled >= resource.amount) { + return resource.amount + } + } + return filled + } + + override fun drain(resource: FluidStack?, doDrain: Boolean): FluidStack? { + if (resource == null || resource.amount <= 0) { + return null + } + var drained = 0 + for (tank in tanks()) { + val stack = tank.drain(wrapper, FluidStack(resource.fluid, resource.amount - drained, resource.tag?.copy()), doDrain) ?: continue + drained += stack.amount + if (drained >= resource.amount) { + return FluidStack(resource.fluid, resource.amount, resource.tag?.copy()) + } + } + return if (drained > 0) FluidStack(resource.fluid, drained, resource.tag?.copy()) else null + } + + override fun drain(maxDrain: Int, doDrain: Boolean): FluidStack? { + for (tank in tanks()) { + val drained = tank.drain(wrapper, maxDrain, doDrain) + if (drained != null && drained.amount > 0) { + return drained + } + } + return null + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt index 2a44765..201bf99 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt @@ -1,24 +1,46 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability +import com.cleanroommc.retrosophisticatedbackpacks.backpack.DisplaySide import com.cleanroommc.retrosophisticatedbackpacks.backpack.SortType +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.ICompactingUpgrade +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IMagnetUpgrade +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedCompactingUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedVoidUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CompactingUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.inventory.BackpackItemStackHandler +import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.inventory.UpgradeItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import com.cleanroommc.retrosophisticatedbackpacks.item.ExponentialStackUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.InceptionUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.StackUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.mixin.EntityItemAccessor import com.cleanroommc.retrosophisticatedbackpacks.util.BackpackItemStackHelper import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.item.EntityItem +import net.minecraft.init.SoundEvents +import net.minecraft.inventory.Container +import net.minecraft.inventory.InventoryCrafting +import net.minecraft.item.EnumDyeColor import net.minecraft.item.ItemStack +import net.minecraft.item.crafting.CraftingManager import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing +import net.minecraft.util.SoundCategory +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos import net.minecraft.util.text.ITextComponent import net.minecraft.util.text.TextComponentTranslation +import net.minecraft.world.World import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.INBTSerializable +import net.minecraftforge.fluids.capability.CapabilityFluidHandler +import net.minecraftforge.energy.CapabilityEnergy import net.minecraftforge.items.CapabilityItemHandler import net.minecraftforge.items.IItemHandler +import net.minecraftforge.items.ItemHandlerHelper import java.util.* class BackpackWrapper( @@ -39,6 +61,17 @@ class BackpackWrapper( private const val MEMORY_STACK_RESPECT_NBT_TAG = "MemoryRespectNBT" private const val SORT_TYPE_TAG = "SortType" private const val LOCKED_SLOTS_TAG = "LockedSlots" + private const val MAIN_SETTINGS_TAG = "MainSettings" + private const val MAIN_SETTINGS_CONTEXT_TAG = "Context" + private const val MAIN_SETTINGS_SHIFT_CLICK_INTO_OPEN_TAB_TAG = "ShiftClickIntoOpenTab" + private const val MAIN_SETTINGS_KEEP_TAB_OPEN_TAG = "KeepTabOpen" + private const val MAIN_SETTINGS_KEEP_SEARCH_PHRASE_TAG = "KeepSearchPhrase" + private const val MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG = "AnotherPlayerCanOpen" + private const val ITEM_DISPLAY_SETTINGS_TAG = "ItemDisplay" + private const val ITEM_DISPLAY_SLOTS_TAG = "Slots" + private const val ITEM_DISPLAY_ROTATIONS_TAG = "Rotations" + private const val ITEM_DISPLAY_COLOR_TAG = "Color" + private const val ITEM_DISPLAY_SIDE_TAG = "DisplaySide" private const val UUID_TAG = "UUID" @@ -53,6 +86,26 @@ class BackpackWrapper( var mainColor = DEFAULT_MAIN_COLOR var accentColor = DEFAULT_ACCENT_COLOR + var isGuiInteractionInProgress = false + var settingsContext: SettingsContext = SettingsContext.PLAYER + var shiftClickIntoOpenTab = false + var keepTabOpen = true + var keepSearchPhrase = false + var anotherPlayerCanOpen = false + var itemDisplayColor: EnumDyeColor = EnumDyeColor.RED + var itemDisplaySide: DisplaySide = DisplaySide.FRONT + private val itemDisplaySlots = linkedSetOf() + private val itemDisplayRotations = mutableMapOf() + private val slotsToCompact = mutableSetOf() + private val slotsToVoid = mutableSetOf() + + enum class SettingsContext { + PLAYER, + STORAGE; + + fun next(): SettingsContext = + if (this == PLAYER) STORAGE else PLAYER + } fun isStackedByMultiplication(): Boolean = upgradeItemStackHandler.inventory.map(ItemStack::getItem).filterIsInstance().any() @@ -104,7 +157,7 @@ class BackpackWrapper( return false } - return true + return canFitBatteryEnergyWithMultiplier(newStackMultiplier) } fun canAddExponentialStackUpgrade(): Boolean { @@ -129,7 +182,7 @@ class BackpackWrapper( return false } - return true + return canFitBatteryEnergyWithMultiplier(byAddMultiplier) } fun canNestBackpack(): Boolean = @@ -171,6 +224,306 @@ class BackpackWrapper( else filterUpgrades.any { it.canInsert(stack) } } + fun onBeforeInsert(stack: ItemStack): ItemStack = + if (shouldVoid(stack, false, false)) ItemStack.EMPTY else stack + + fun onSlotChanged(slotIndex: Int, fromGui: Boolean = false) { + val stack = getStackInSlot(slotIndex) + if (!fromGui || shouldVoidInGui(stack)) { + slotsToVoid.add(slotIndex) + } + if (!fromGui || shouldCompactInGui()) { + slotsToCompact.add(slotIndex) + } + } + + fun onGuiSlotChanged(slotIndex: Int) { + onSlotChanged(slotIndex, true) + } + + fun shouldHandleSlotChangeFromGui(): Boolean = + isGuiInteractionInProgress + + fun insertStack(stack: ItemStack, simulate: Boolean, processInsertUpgrades: Boolean = false): ItemStack { + val stack = if (processInsertUpgrades) onBeforeInsert(stack) else stack + if (stack.isEmpty) { + return ItemStack.EMPTY + } + + var remaining = backpackItemStackHandler.insertItemToMemorySlots(stack, simulate) + for (slot in 0 until slots) { + if (remaining.isEmpty) { + return ItemStack.EMPTY + } + remaining = insertItem(slot, remaining, simulate) + } + return if (processInsertUpgrades) onInsertRemainder(remaining) else remaining + } + + fun onInsertRemainder(remaining: ItemStack): ItemStack = + if (shouldVoid(remaining, true, hasMatchingStack(remaining))) ItemStack.EMPTY else remaining + + fun extractMatching(filter: ItemStack, amount: Int, simulate: Boolean): ItemStack { + var remaining = amount + var extracted = ItemStack.EMPTY + + for (slot in 0 until slots) { + val stack = getStackInSlot(slot) + if (stack.isEmpty || !ItemHandlerHelper.canItemStacksStack(stack, filter)) { + continue + } + + val slotExtracted = extractItem(slot, minOf(stack.count, remaining), simulate) + if (extracted.isEmpty) { + extracted = slotExtracted.copy() + } else { + extracted.grow(slotExtracted.count) + } + remaining -= slotExtracted.count + + if (remaining <= 0) { + break + } + } + + return extracted + } + + fun tickUpgrades(player: EntityPlayer?, world: World, x: Double, y: Double, z: Double, pos: BlockPos = BlockPos(x, y, z)) { + if (world.totalWorldTime % 5L == 0L) { + if (player != null) { + gatherCapabilityUpgrades(Capabilities.IREFILL_UPGRADE_CAPABILITY).forEach { it.refill(player, this) } + } else if (gatherCapabilityUpgrades(Capabilities.IREFILL_UPGRADE_CAPABILITY).isNotEmpty()) { + val players = world.getEntitiesWithinAABB(EntityPlayer::class.java, AxisAlignedBB(x - 3, y - 3, z - 3, x + 3, y + 3, z + 3)) + players.forEach { nearbyPlayer -> + gatherCapabilityUpgrades(Capabilities.IREFILL_UPGRADE_CAPABILITY).forEach { it.refill(nearbyPlayer, this) } + } + } + } + + if (world.totalWorldTime % 10L == 0L) { + magnetItems(player, world, x, y, z) + } + + gatherCapabilityUpgrades(Capabilities.ITANK_UPGRADE_CAPABILITY).forEach { it.tick(this, world) } + gatherCapabilityUpgrades(Capabilities.IBATTERY_UPGRADE_CAPABILITY).forEach { it.tick(this, world) } + gatherCapabilityUpgrades(Capabilities.IPUMP_UPGRADE_CAPABILITY).forEach { it.tick(player, this, world, pos) } + gatherCapabilityUpgrades(Capabilities.IJUKEBOX_UPGRADE_CAPABILITY) + .forEach { it.tick(world, pos) } + + val compactingUpgrades = gatherCapabilityUpgrades(Capabilities.ICOMPACTING_UPGRADE_CAPABILITY) + if (compactingUpgrades.isNotEmpty()) { + compactingUpgrades.forEach { it.compact(this, world) } + slotsToCompact.clear() + } + + if (slotsToVoid.isNotEmpty()) { + for (slot in slotsToVoid.toSet()) { + val stack = getStackInSlot(slot) + if (!stack.isEmpty && shouldVoidInGui(stack)) { + extractItem(slot, stack.count, false) + } + } + slotsToVoid.clear() + } + } + + fun compactChangedSlots( + world: World, + upgrade: ICompactingUpgrade, + shouldCompactThreeByThree: Boolean, + compactNonUncraftable: Boolean, + stackFilter: (ItemStack) -> Boolean + ) { + val slots = if (slotsToCompact.isEmpty()) (0 until this.slots).toSet() else slotsToCompact.toSet() + for (slot in slots) { + compactSlot(world, slot, shouldCompactThreeByThree, compactNonUncraftable, stackFilter) + } + } + + private fun magnetItems(player: EntityPlayer?, world: World, x: Double, y: Double, z: Double) { + val magnetUpgrades = gatherCapabilityUpgrades(Capabilities.IMAGNET_UPGRADE_CAPABILITY) + if (magnetUpgrades.isEmpty()) { + return + } + + val range = magnetUpgrades.map(IMagnetUpgrade::range).max() + val items = world.getEntitiesWithinAABB(EntityItem::class.java, AxisAlignedBB(x - range, y - range, z - range, x + range, y + range, z + range)) + + for (entityItem in items) { + if (entityItem.isDead || (entityItem as EntityItemAccessor).`rsb$getPickupDelay`() == 32767 || magnetUpgrades.none { it.canPickup(entityItem.item) }) { + continue + } + + val original = entityItem.item.copy() + val remaining = insertStack(original, false, true) + if (remaining.count != original.count) { + entityItem.item = remaining + player?.world?.playSound( + null, + player.posX, + player.posY, + player.posZ, + SoundEvents.ENTITY_ITEM_PICKUP, + SoundCategory.PLAYERS, + 0.2f, + (world.rand.nextFloat() - world.rand.nextFloat()) * 1.4f + 2.0f + ) + if (remaining.isEmpty) { + entityItem.setDead() + } else { + entityItem.setNoPickupDelay() + } + player?.onItemPickup(entityItem, original.count - remaining.count) + } + } + } + + private fun compactSlot( + world: World, + slot: Int, + shouldCompactThreeByThree: Boolean, + compactNonUncraftable: Boolean, + stackFilter: (ItemStack) -> Boolean + ) { + val stack = getStackInSlot(slot) + if (stack.isEmpty || !stackFilter(stack)) { + return + } + + if (shouldCompactThreeByThree && tryCompact(world, stack, 3, 3, compactNonUncraftable)) { + return + } + tryCompact(world, stack, 2, 2, compactNonUncraftable) + } + + private fun tryCompact(world: World, stack: ItemStack, width: Int, height: Int, compactNonUncraftable: Boolean): Boolean { + val count = width * height + val compactingResult = getCompactingResult(world, stack, width, height) + val result = compactingResult.result + if (result.isEmpty || (!compactNonUncraftable && !canUncompact(world, result, stack, count))) { + return false + } + + var compacted = false + val stacksToInsert = listOf(result) + compactingResult.remainingItems + while (extractMatching(stack, count, true).count == count && canInsertAll(stacksToInsert)) { + extractMatching(stack, count, false) + stacksToInsert.forEach { insertStack(it.copy(), false) } + compacted = true + } + return compacted + } + + private fun getCompactingResult(world: World, stack: ItemStack, width: Int, height: Int): CompactingResult { + val inventory = InventoryCrafting(DummyContainer, width, height) + for (slot in 0 until width * height) { + inventory.setInventorySlotContents(slot, ItemHandlerHelper.copyStackWithSize(stack, 1)) + } + val recipe = CraftingManager.findMatchingRecipe(inventory, world) ?: return CompactingResult.EMPTY + return CompactingResult( + recipe.getCraftingResult(inventory), + recipe.getRemainingItems(inventory).filterNot(ItemStack::isEmpty).map(ItemStack::copy) + ) + } + + private fun canInsertAll(stacks: List): Boolean { + val simulation = ExposedItemStackHandler(slots) + for (slot in 0 until slots) { + simulation.setStackInSlot(slot, getStackInSlot(slot).copy()) + } + + for (stack in stacks) { + if (!insertIntoSimulation(simulation, stack.copy()).isEmpty) { + return false + } + } + return true + } + + private fun insertIntoSimulation(simulation: ExposedItemStackHandler, stack: ItemStack): ItemStack { + var remaining = stack + for (slot in 0 until simulation.slots) { + val existing = simulation.getStackInSlot(slot) + if (existing.isEmpty) { + val moved = minOf(remaining.count, remaining.maxStackSize * getTotalStackMultiplier()) + simulation.setStackInSlot(slot, ItemHandlerHelper.copyStackWithSize(remaining, moved)) + remaining = ItemHandlerHelper.copyStackWithSize(remaining, remaining.count - moved) + if (remaining.isEmpty) { + return ItemStack.EMPTY + } + continue + } + if (!ItemHandlerHelper.canItemStacksStack(existing, remaining)) { + continue + } + val moved = minOf(remaining.count, existing.maxStackSize * getTotalStackMultiplier() - existing.count) + if (moved > 0) { + existing.grow(moved) + remaining = ItemHandlerHelper.copyStackWithSize(remaining, remaining.count - moved) + if (remaining.isEmpty) { + return ItemStack.EMPTY + } + } + } + return remaining + } + + private fun canUncompact(world: World, result: ItemStack, input: ItemStack, expectedCount: Int): Boolean { + val inventory = InventoryCrafting(DummyContainer, 3, 3) + inventory.setInventorySlotContents(0, ItemHandlerHelper.copyStackWithSize(result, 1)) + val recipe = CraftingManager.findMatchingRecipe(inventory, world) ?: return false + val uncompactResult = recipe.getCraftingResult(inventory) + return ItemHandlerHelper.canItemStacksStack(uncompactResult, input) && uncompactResult.count >= expectedCount + } + + private fun shouldVoid(stack: ItemStack, storageFull: Boolean, hasMatchingStack: Boolean): Boolean { + if (stack.isEmpty) { + return false + } + + return gatherCapabilityUpgrades(Capabilities.IVOID_UPGRADE_CAPABILITY).any { + when (it) { + is VoidUpgradeWrapper -> it.shouldVoidOverflow(stack, storageFull, hasMatchingStack) + is AdvancedVoidUpgradeWrapper -> it.shouldVoidOverflow(stack, storageFull, hasMatchingStack) + else -> it.shouldVoid(stack) + } + } + } + + private fun shouldVoidInGui(stack: ItemStack): Boolean = + gatherCapabilityUpgrades(Capabilities.IVOID_UPGRADE_CAPABILITY).any { + when (it) { + is VoidUpgradeWrapper -> it.shouldWorkInGui && it.shouldVoid(stack) + is AdvancedVoidUpgradeWrapper -> it.shouldWorkInGui && it.shouldVoid(stack) + else -> false + } + } + + private fun shouldCompactInGui(): Boolean = + gatherCapabilityUpgrades(Capabilities.ICOMPACTING_UPGRADE_CAPABILITY).any { + when (it) { + is CompactingUpgradeWrapper -> it.enabled && it.shouldWorkInGui + is AdvancedCompactingUpgradeWrapper -> it.enabled && it.shouldWorkInGui + else -> false + } + } + + private fun hasMatchingStack(stack: ItemStack): Boolean = + backpackItemStackHandler.inventory.any { !it.isEmpty && ItemHandlerHelper.canItemStacksStack(it, stack) } + + private fun isFull(): Boolean = + (0 until slots).all { + val stack = getStackInSlot(it) + !stack.isEmpty && stack.count >= getSlotLimit(it) + } + + private data class CompactingResult(val result: ItemStack, val remainingItems: List) { + companion object { + val EMPTY = CompactingResult(ItemStack.EMPTY, emptyList()) + } + } + fun canExtract(slotIndex: Int): Boolean { val stack = getStackInSlot(slotIndex) val filterUpgrades = gatherCapabilityUpgrades(Capabilities.IFILTER_UPGRADE_CAPABILITY) @@ -220,6 +573,73 @@ class BackpackWrapper( backpackItemStackHandler.sortLockedSlots[slotIndex] = locked } + fun toggleSettingsContext() { + settingsContext = settingsContext.next() + } + + fun toggleShiftClickIntoOpenTab() { + shiftClickIntoOpenTab = !shiftClickIntoOpenTab + } + + fun toggleKeepTabOpen() { + keepTabOpen = !keepTabOpen + } + + fun toggleKeepSearchPhrase() { + keepSearchPhrase = !keepSearchPhrase + } + + fun toggleAnotherPlayerCanOpen() { + anotherPlayerCanOpen = !anotherPlayerCanOpen + } + + fun isItemDisplaySlotSelected(slotIndex: Int): Boolean = + slotIndex in itemDisplaySlots + + fun selectItemDisplaySlot(slotIndex: Int) { + if (slotIndex !in 0 until backpackInventorySize() || slotIndex in itemDisplaySlots) { + return + } + if (itemDisplaySlots.size + 1 > 1) { + return + } + itemDisplaySlots.add(slotIndex) + } + + fun unselectItemDisplaySlot(slotIndex: Int) { + itemDisplaySlots.remove(slotIndex) + itemDisplayRotations.remove(slotIndex) + } + + fun getFirstItemDisplaySlot(): Int = + itemDisplaySlots.firstOrNull() ?: -1 + + fun getItemDisplaySlots(): Set = + itemDisplaySlots + + fun getItemDisplayRotation(slotIndex: Int): Int = + itemDisplayRotations[slotIndex] ?: 0 + + fun rotateItemDisplaySlot(slotIndex: Int, clockwise: Boolean) { + if (slotIndex !in itemDisplaySlots) { + return + } + itemDisplayRotations[slotIndex] = (getItemDisplayRotation(slotIndex) + if (clockwise) 45 else -45 + 360) % 360 + } + + fun getDisplayItem(): DisplayItem? { + val slotIndex = getFirstItemDisplaySlot() + if (slotIndex !in 0 until backpackInventorySize()) { + return null + } + val stack = getStackInSlot(slotIndex).takeIf { !it.isEmpty } + ?: getMemorizedStack(slotIndex).takeIf { !it.isEmpty } + ?: return null + return DisplayItem(ItemHandlerHelper.copyStackWithSize(stack, 1), getItemDisplayRotation(slotIndex), itemDisplaySide) + } + + data class DisplayItem(val stack: ItemStack, val rotation: Int, val side: DisplaySide) + // This is only meant to used for bogosorter as RSB already implemented a sorting mechanism fun getSortableSlotIndexes(): List = (0.. gatherCapabilityUpgrades(capability: Capability): List = + fun gatherCapabilityUpgrades(capability: Capability): List = upgradeItemStackHandler.inventory .mapNotNull { it.getCapability(capability, null) } + fun tankUpgradeSlots(): List = + upgradeItemStackHandler.inventory.mapIndexedNotNull { slot, upgrade -> + if (upgrade.getCapability(Capabilities.TANK_UPGRADE_CAPABILITY, null) != null) slot else null + } + + fun hasTankUpgrade(): Boolean = + tankUpgradeSlots().isNotEmpty() + + fun batteryUpgradeSlots(): List = + upgradeItemStackHandler.inventory.mapIndexedNotNull { slot, upgrade -> + if (upgrade.getCapability(Capabilities.BATTERY_UPGRADE_CAPABILITY, null) != null) slot else null + } + + fun hasBatteryUpgrade(): Boolean = + batteryUpgradeSlots().isNotEmpty() + + fun canAddBatteryUpgrade(): Boolean = + !hasBatteryUpgrade() + + fun canFitBatteryEnergyWithMultiplier(stackMultiplier: Int): Boolean = + gatherCapabilityUpgrades(Capabilities.IBATTERY_UPGRADE_CAPABILITY) + .all { it.energyStored <= it.getMaxEnergyStored(this, stackMultiplier) } + + fun tankRenderSides(): Pair { + val tankSlots = tankUpgradeSlots() + return (tankSlots.size > 1) to tankSlots.isNotEmpty() + } + + private object DummyContainer : Container() { + override fun canInteractWith(playerIn: EntityPlayer): Boolean = false + } + override fun getSlots(): Int = backpackItemStackHandler.slots @@ -250,7 +702,20 @@ class BackpackWrapper( override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.BACKPACK_CAPABILITY || - capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY + capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && hasTankUpgrade() || + capability == CapabilityEnergy.ENERGY && hasBatteryUpgrade() + + @Suppress("UNCHECKED_CAST") + override fun getCapability(capability: Capability, facing: EnumFacing?): T? = + when { + capability == Capabilities.BACKPACK_CAPABILITY -> this as T + capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY -> this as T + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && + hasTankUpgrade() -> BackpackFluidHandler(this) as T + capability == CapabilityEnergy.ENERGY && hasBatteryUpgrade() -> BackpackEnergyStorage(this) as T + else -> null + } override fun serializeNBT(): NBTTagCompound { val nbt = NBTTagCompound() @@ -281,6 +746,23 @@ class BackpackWrapper( backpackItemStackHandler.sortLockedSlots.map { if (it) 1 else 0 }.map(Int::toByte).toByteArray() ) + val mainSettingsNbt = NBTTagCompound() + mainSettingsNbt.setByte(MAIN_SETTINGS_CONTEXT_TAG, settingsContext.ordinal.toByte()) + mainSettingsNbt.setBoolean(MAIN_SETTINGS_SHIFT_CLICK_INTO_OPEN_TAB_TAG, shiftClickIntoOpenTab) + mainSettingsNbt.setBoolean(MAIN_SETTINGS_KEEP_TAB_OPEN_TAG, keepTabOpen) + mainSettingsNbt.setBoolean(MAIN_SETTINGS_KEEP_SEARCH_PHRASE_TAG, keepSearchPhrase) + mainSettingsNbt.setBoolean(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG, anotherPlayerCanOpen) + nbt.setTag(MAIN_SETTINGS_TAG, mainSettingsNbt) + + val itemDisplayNbt = NBTTagCompound() + itemDisplayNbt.setIntArray(ITEM_DISPLAY_SLOTS_TAG, itemDisplaySlots.toIntArray()) + val rotationsNbt = NBTTagCompound() + itemDisplayRotations.forEach { (slot, rotation) -> rotationsNbt.setInteger(slot.toString(), rotation) } + itemDisplayNbt.setTag(ITEM_DISPLAY_ROTATIONS_TAG, rotationsNbt) + itemDisplayNbt.setByte(ITEM_DISPLAY_COLOR_TAG, itemDisplayColor.ordinal.toByte()) + itemDisplayNbt.setString(ITEM_DISPLAY_SIDE_TAG, itemDisplaySide.serializedName) + nbt.setTag(ITEM_DISPLAY_SETTINGS_TAG, itemDisplayNbt) + nbt.setUniqueId(UUID_TAG, uuid) return nbt } @@ -325,6 +807,38 @@ class BackpackWrapper( setSlotLocked(index, b.toInt() != 0) } + if (nbt.hasKey(MAIN_SETTINGS_TAG)) { + val mainSettingsNbt = nbt.getCompoundTag(MAIN_SETTINGS_TAG) + settingsContext = SettingsContext.entries.getOrElse(mainSettingsNbt.getByte(MAIN_SETTINGS_CONTEXT_TAG).toInt()) { + SettingsContext.PLAYER + } + shiftClickIntoOpenTab = mainSettingsNbt.getBoolean(MAIN_SETTINGS_SHIFT_CLICK_INTO_OPEN_TAB_TAG) + keepTabOpen = if (mainSettingsNbt.hasKey(MAIN_SETTINGS_KEEP_TAB_OPEN_TAG)) + mainSettingsNbt.getBoolean(MAIN_SETTINGS_KEEP_TAB_OPEN_TAG) + else true + keepSearchPhrase = mainSettingsNbt.getBoolean(MAIN_SETTINGS_KEEP_SEARCH_PHRASE_TAG) + anotherPlayerCanOpen = mainSettingsNbt.getBoolean(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG) + } + + itemDisplaySlots.clear() + itemDisplayRotations.clear() + if (nbt.hasKey(ITEM_DISPLAY_SETTINGS_TAG)) { + val itemDisplayNbt = nbt.getCompoundTag(ITEM_DISPLAY_SETTINGS_TAG) + itemDisplayNbt.getIntArray(ITEM_DISPLAY_SLOTS_TAG) + .filter { it in 0 until backpackInventorySize() } + .forEach(itemDisplaySlots::add) + val rotationsNbt = itemDisplayNbt.getCompoundTag(ITEM_DISPLAY_ROTATIONS_TAG) + rotationsNbt.keySet.forEach { key -> + key.toIntOrNull() + ?.takeIf { it in itemDisplaySlots } + ?.let { itemDisplayRotations[it] = rotationsNbt.getInteger(key) } + } + itemDisplayColor = EnumDyeColor.entries.getOrElse(itemDisplayNbt.getByte(ITEM_DISPLAY_COLOR_TAG).toInt()) { + EnumDyeColor.RED + } + itemDisplaySide = DisplaySide.fromName(itemDisplayNbt.getString(ITEM_DISPLAY_SIDE_TAG)) + } + sortType = SortType.entries[nbt.getByte(SORT_TYPE_TAG).toInt()] } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt index 6b427ee..3f9fe59 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt @@ -9,7 +9,7 @@ import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability class AdvancedFilterUpgradeWrapper : AdvancedUpgradeWrapper(), IFilterUpgrade { - override val settingsLangKey: String = "gui.advanced_filter_upgrade".asTranslationKey() + override val settingsLangKey: String = "gui.advanced_filter_settings".asTranslationKey() override var filterWay: IFilterUpgrade.FilterWayType = IFilterUpgrade.FilterWayType.IN_OUT override fun canInsert(stack: ItemStack): Boolean { @@ -41,4 +41,4 @@ class AdvancedFilterUpgradeWrapper : AdvancedUpgradeWrapper() super.deserializeNBT(nbt) filterWay = IFilterUpgrade.FilterWayType.entries[nbt.getByte(IFilterUpgrade.FILTER_WAY_TAG).toInt()] } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt index b9323a9..64ff348 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt @@ -10,10 +10,10 @@ import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.Constants -abstract class AdvancedUpgradeWrapper : UpgradeWrapper(), IToggleable, IAdvancedFilterable where T : UpgradeItem { +abstract class AdvancedUpgradeWrapper(filterSlots: Int = 16) : UpgradeWrapper(), IToggleable, IAdvancedFilterable where T : UpgradeItem { override var enabled = true override var filterType = IBasicFilterable.FilterType.WHITELIST - override val filterItems: ExposedItemStackHandler = ExposedItemStackHandler(16) + override val filterItems: ExposedItemStackHandler = ExposedItemStackHandler(filterSlots) override var matchType = IAdvancedFilterable.MatchType.ITEM override var oreDictEntries = mutableListOf() override var ignoreDurability = true @@ -59,4 +59,4 @@ abstract class AdvancedUpgradeWrapper : UpgradeWrapper(), IToggleable, IAd for (stringNBT in oreDictList) oreDictEntries.add((stringNBT as NBTTagString).string) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt new file mode 100644 index 0000000..e88ebd2 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt @@ -0,0 +1,110 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler +import com.cleanroommc.retrosophisticatedbackpacks.item.AnvilUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.inventory.ContainerRepair +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.items.IItemHandler + +class AnvilUpgradeWrapper : UpgradeWrapper(), IAnvilUpgrade { + companion object { + private const val INVENTORY_TAG = "Inventory" + private const val SHIFT_CLICK_TAG = "ShiftClickIntoStorage" + private const val ITEM_NAME_TAG = "ItemName" + private const val MAXIMUM_COST_TAG = "MaximumCost" + private const val MATERIAL_COST_TAG = "MaterialCost" + private const val RESULT_TAG = "Result" + } + + override val settingsLangKey = "gui.anvil_settings".asTranslationKey() + override var shouldShiftClickIntoStorage = true + override var itemName = "" + override var maximumCost = 0 + private set + override var materialCost = 0 + private set + private var result = ItemStack.EMPTY + private val inventory = object : ExposedItemStackHandler(2) { + override fun onContentsChanged(slot: Int) { + result = ItemStack.EMPTY + maximumCost = 0 + materialCost = 0 + } + } + + override fun getInventory(): IItemHandler = + inventory + + override fun updateRepairOutput(player: EntityPlayer, world: World): ItemStack { + val container = createContainer(player, world) + maximumCost = container.maximumCost + materialCost = container.materialCost + result = container.getSlot(2).stack.copy() + return result.copy() + } + + override fun canTakeResult(player: EntityPlayer): Boolean = + !result.isEmpty && maximumCost > 0 && (player.capabilities.isCreativeMode || player.experienceLevel >= maximumCost) + + override fun takeResult(player: EntityPlayer, world: World): ItemStack { + updateRepairOutput(player, world) + if (!canTakeResult(player)) { + return ItemStack.EMPTY + } + val container = createContainer(player, world) + val resultSlot = container.getSlot(2) + val taken = resultSlot.stack.copy() + resultSlot.onTake(player, taken.copy()) + inventory.setStackInSlot(0, container.getSlot(0).stack.copy()) + inventory.setStackInSlot(1, container.getSlot(1).stack.copy()) + result = ItemStack.EMPTY + maximumCost = 0 + materialCost = 0 + return taken + } + + private fun createContainer(player: EntityPlayer, world: World): ContainerRepair { + val container = ContainerRepair(player.inventory, world, BlockPos(player), player) + container.getSlot(0).putStack(inventory.getStackInSlot(0).copy()) + container.getSlot(1).putStack(inventory.getStackInSlot(1).copy()) + container.updateItemName(itemName) + container.updateRepairOutput() + return container + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setTag(INVENTORY_TAG, inventory.serializeNBT()) + nbt.setBoolean(SHIFT_CLICK_TAG, shouldShiftClickIntoStorage) + nbt.setString(ITEM_NAME_TAG, itemName) + nbt.setInteger(MAXIMUM_COST_TAG, maximumCost) + nbt.setInteger(MATERIAL_COST_TAG, materialCost) + if (!result.isEmpty) { + nbt.setTag(RESULT_TAG, result.writeToNBT(NBTTagCompound())) + } + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) + shouldShiftClickIntoStorage = if (nbt.hasKey(SHIFT_CLICK_TAG)) nbt.getBoolean(SHIFT_CLICK_TAG) else true + itemName = nbt.getString(ITEM_NAME_TAG) + maximumCost = nbt.getInteger(MAXIMUM_COST_TAG) + materialCost = nbt.getInteger(MATERIAL_COST_TAG) + result = if (nbt.hasKey(RESULT_TAG)) ItemStack(nbt.getCompoundTag(RESULT_TAG)) else ItemStack.EMPTY + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ANVIL_UPGRADE_CAPABILITY || + capability == Capabilities.IANVIL_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt index cb0a143..1bbd550 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt @@ -7,10 +7,10 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -abstract class BasicUpgradeWrapper : UpgradeWrapper(), IToggleable, IBasicFilterable where T : UpgradeItem { +abstract class BasicUpgradeWrapper(filterSlots: Int = 9) : UpgradeWrapper(), IToggleable, IBasicFilterable where T : UpgradeItem { override var enabled = true override var filterType = IBasicFilterable.FilterType.WHITELIST - override val filterItems = ExposedItemStackHandler(9) + override val filterItems = ExposedItemStackHandler(filterSlots) override fun checkFilter(stack: ItemStack): Boolean = enabled && super.checkFilter(stack) @@ -34,4 +34,4 @@ abstract class BasicUpgradeWrapper : UpgradeWrapper(), IToggleable, IBasic filterItems.deserializeNBT(nbt.getCompoundTag(IBasicFilterable.FILTER_ITEMS_TAG)) filterType = IBasicFilterable.FilterType.entries[nbt.getByte(IBasicFilterable.FILTER_TYPE_TAG).toInt()] } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt new file mode 100644 index 0000000..924f2cd --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt @@ -0,0 +1,134 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler +import com.cleanroommc.retrosophisticatedbackpacks.item.BatteryUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.energy.CapabilityEnergy +import net.minecraftforge.items.IItemHandler + +class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgrade { + companion object { + private const val ENERGY_TAG = "Energy" + private const val INVENTORY_TAG = "Inventory" + private const val INPUT_SLOT = 0 + private const val OUTPUT_SLOT = 1 + private const val ENERGY_PER_ROW = 10000 + private const val MAX_INPUT_OUTPUT_PER_ROW = 20 + } + + override val settingsLangKey = "gui.battery_settings".asTranslationKey() + override var energyStored = 0 + private set + override val canExtractEnergy = true + override val canReceiveEnergy = true + + private val inventory = object : ExposedItemStackHandler(2) { + override fun getSlotLimit(slot: Int): Int = 1 + + override fun isItemValid(slot: Int, stack: ItemStack): Boolean = + stack.isEmpty || when (slot) { + INPUT_SLOT -> isValidEnergyItem(stack, output = false) + OUTPUT_SLOT -> isValidEnergyItem(stack, output = true) + else -> false + } + } + + override fun getMaxEnergyStored(wrapper: BackpackWrapper): Int = + getMaxEnergyStored(wrapper, maxOf(1, wrapper.getTotalStackMultiplier())) + + override fun getMaxEnergyStored(wrapper: BackpackWrapper, stackMultiplier: Int): Int = + getSlotRows(wrapper) * ENERGY_PER_ROW * maxOf(1, stackMultiplier) + + override fun receiveEnergy(wrapper: BackpackWrapper, maxReceive: Int, simulate: Boolean): Int { + val accepted = minOf(maxReceive, getMaxInOut(wrapper), getMaxEnergyStored(wrapper) - energyStored) + if (!simulate && accepted > 0) { + energyStored += accepted + } + return accepted.coerceAtLeast(0) + } + + override fun extractEnergy(wrapper: BackpackWrapper, maxExtract: Int, simulate: Boolean): Int { + val extracted = minOf(maxExtract, getMaxInOut(wrapper), energyStored) + if (!simulate && extracted > 0) { + energyStored -= extracted + } + return extracted.coerceAtLeast(0) + } + + override fun tick(wrapper: BackpackWrapper, world: World) { + if (world.isRemote) { + return + } + if (energyStored < getMaxEnergyStored(wrapper)) { + receiveFromContainer(wrapper) + } + if (energyStored > 0) { + extractToContainer(wrapper) + } + } + + override fun getInventory(): IItemHandler = + inventory + + private fun receiveFromContainer(wrapper: BackpackWrapper) { + val stack = inventory.getStackInSlot(INPUT_SLOT) + val energyStorage = stack.getCapability(CapabilityEnergy.ENERGY, null) ?: return + val toReceive = receiveEnergy(wrapper, getMaxInOut(wrapper), true) + val extracted = energyStorage.extractEnergy(toReceive, true) + if (extracted <= 0) { + return + } + energyStorage.extractEnergy(extracted, false) + receiveEnergy(wrapper, extracted, false) + inventory.setStackInSlot(INPUT_SLOT, stack) + } + + private fun extractToContainer(wrapper: BackpackWrapper) { + val stack = inventory.getStackInSlot(OUTPUT_SLOT) + val energyStorage = stack.getCapability(CapabilityEnergy.ENERGY, null) ?: return + val toExtract = extractEnergy(wrapper, getMaxInOut(wrapper), true) + val received = energyStorage.receiveEnergy(toExtract, true) + if (received <= 0) { + return + } + energyStorage.receiveEnergy(received, false) + extractEnergy(wrapper, received, false) + inventory.setStackInSlot(OUTPUT_SLOT, stack) + } + + private fun isValidEnergyItem(stack: ItemStack, output: Boolean): Boolean { + val energyStorage = stack.getCapability(CapabilityEnergy.ENERGY, null) ?: return false + return if (output) energyStorage.canReceive() else energyStorage.canExtract() && energyStorage.energyStored > 0 + } + + private fun getMaxInOut(wrapper: BackpackWrapper): Int = + maxOf(1, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * maxOf(1, wrapper.getTotalStackMultiplier())) + + private fun getSlotRows(wrapper: BackpackWrapper): Int = + maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setInteger(ENERGY_TAG, energyStored) + nbt.setTag(INVENTORY_TAG, inventory.serializeNBT()) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + energyStored = nbt.getInteger(ENERGY_TAG) + inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.BATTERY_UPGRADE_CAPABILITY || + capability == Capabilities.IBATTERY_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt new file mode 100644 index 0000000..b5eb365 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt @@ -0,0 +1,98 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.item.CompactingUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability + +open class CompactingUpgradeWrapper : BasicUpgradeWrapper(), ICompactingUpgrade { + companion object { + private const val COMPACT_NON_UNCRAFTABLE_TAG = "CompactNonUncraftable" + private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" + } + + override val settingsLangKey = "gui.compacting_settings".asTranslationKey() + var compactNonUncraftable = false + var shouldWorkInGui = false + + override fun compact(wrapper: BackpackWrapper, world: World) { + if (enabled) { + wrapper.compactChangedSlots(world, this, false, compactNonUncraftable) { matchesAllowEmpty(it) } + } + } + + fun toggleCompactNonUncraftable() { + compactNonUncraftable = !compactNonUncraftable + } + + fun toggleWorkInGui() { + shouldWorkInGui = !shouldWorkInGui + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setBoolean(COMPACT_NON_UNCRAFTABLE_TAG, compactNonUncraftable) + nbt.setBoolean(SHOULD_WORK_IN_GUI_TAG, shouldWorkInGui) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + compactNonUncraftable = nbt.getBoolean(COMPACT_NON_UNCRAFTABLE_TAG) + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.COMPACTING_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} + +class AdvancedCompactingUpgradeWrapper : AdvancedUpgradeWrapper(), ICompactingUpgrade { + companion object { + private const val COMPACT_NON_UNCRAFTABLE_TAG = "CompactNonUncraftable" + private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" + } + + override val settingsLangKey = "gui.advanced_compacting_settings".asTranslationKey() + var compactNonUncraftable = false + var shouldWorkInGui = false + + override fun compact(wrapper: BackpackWrapper, world: World) { + if (enabled) { + wrapper.compactChangedSlots(world, this, true, compactNonUncraftable) { matchesAllowEmpty(it) } + } + } + + fun toggleCompactNonUncraftable() { + compactNonUncraftable = !compactNonUncraftable + } + + fun toggleWorkInGui() { + shouldWorkInGui = !shouldWorkInGui + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setBoolean(COMPACT_NON_UNCRAFTABLE_TAG, compactNonUncraftable) + nbt.setBoolean(SHOULD_WORK_IN_GUI_TAG, shouldWorkInGui) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + compactNonUncraftable = nbt.getBoolean(COMPACT_NON_UNCRAFTABLE_TAG) + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ADVANCED_COMPACTING_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/EverlastingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/EverlastingUpgradeWrapper.kt new file mode 100644 index 0000000..5426c78 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/EverlastingUpgradeWrapper.kt @@ -0,0 +1,24 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.item.EverlastingUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability + +class EverlastingUpgradeWrapper : UpgradeWrapper(), IEverlastingUpgrade { + override val settingsLangKey = "gui.everlasting_settings".asTranslationKey() + + override fun serializeNBT(): NBTTagCompound = + super.serializeNBT() + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.EVERLASTING_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAnvilUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAnvilUpgrade.kt new file mode 100644 index 0000000..3f4c375 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAnvilUpgrade.kt @@ -0,0 +1,40 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable +import net.minecraftforge.items.IItemHandler + +interface IAnvilUpgrade : ISidelessCapabilityProvider, INBTSerializable { + var shouldShiftClickIntoStorage: Boolean + var itemName: String + val maximumCost: Int + val materialCost: Int + + fun getInventory(): IItemHandler + fun updateRepairOutput(player: EntityPlayer, world: World): ItemStack + fun canTakeResult(player: EntityPlayer): Boolean + fun takeResult(player: EntityPlayer, world: World): ItemStack + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.IANVIL_UPGRADE_CAPABILITY + + object Impl : IAnvilUpgrade { + override var shouldShiftClickIntoStorage = false + override var itemName = "" + override val maximumCost = 0 + override val materialCost = 0 + override fun getInventory(): IItemHandler = net.minecraftforge.items.ItemStackHandler(0) + override fun updateRepairOutput(player: EntityPlayer, world: World): ItemStack = ItemStack.EMPTY + override fun canTakeResult(player: EntityPlayer): Boolean = false + override fun takeResult(player: EntityPlayer, world: World): ItemStack = ItemStack.EMPTY + override fun serializeNBT(): NBTTagCompound = NBTTagCompound() + override fun deserializeNBT(nbt: NBTTagCompound) {} + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBatteryUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBatteryUpgrade.kt new file mode 100644 index 0000000..356343b --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBatteryUpgrade.kt @@ -0,0 +1,41 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable +import net.minecraftforge.items.IItemHandler + +interface IBatteryUpgrade : ISidelessCapabilityProvider, INBTSerializable { + val energyStored: Int + val canExtractEnergy: Boolean + val canReceiveEnergy: Boolean + + fun getMaxEnergyStored(wrapper: BackpackWrapper): Int + fun getMaxEnergyStored(wrapper: BackpackWrapper, stackMultiplier: Int): Int + fun receiveEnergy(wrapper: BackpackWrapper, maxReceive: Int, simulate: Boolean): Int + fun extractEnergy(wrapper: BackpackWrapper, maxExtract: Int, simulate: Boolean): Int + fun tick(wrapper: BackpackWrapper, world: World) + fun getInventory(): IItemHandler + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.IBATTERY_UPGRADE_CAPABILITY + + object Impl : IBatteryUpgrade { + override val energyStored = 0 + override val canExtractEnergy = false + override val canReceiveEnergy = false + override fun getMaxEnergyStored(wrapper: BackpackWrapper): Int = 0 + override fun getMaxEnergyStored(wrapper: BackpackWrapper, stackMultiplier: Int): Int = 0 + override fun receiveEnergy(wrapper: BackpackWrapper, maxReceive: Int, simulate: Boolean): Int = 0 + override fun extractEnergy(wrapper: BackpackWrapper, maxExtract: Int, simulate: Boolean): Int = 0 + override fun tick(wrapper: BackpackWrapper, world: World) {} + override fun getInventory(): IItemHandler = net.minecraftforge.items.ItemStackHandler(0) + override fun serializeNBT(): NBTTagCompound = NBTTagCompound() + override fun deserializeNBT(nbt: NBTTagCompound) {} + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ICompactingUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ICompactingUpgrade.kt new file mode 100644 index 0000000..01665d6 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ICompactingUpgrade.kt @@ -0,0 +1,17 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable + +sealed interface ICompactingUpgrade : ISidelessCapabilityProvider, INBTSerializable { + fun compact(wrapper: BackpackWrapper, world: World) + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ICOMPACTING_UPGRADE_CAPABILITY +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IEverlastingUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IEverlastingUpgrade.kt new file mode 100644 index 0000000..d86f80c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IEverlastingUpgrade.kt @@ -0,0 +1,18 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable + +interface IEverlastingUpgrade : ISidelessCapabilityProvider, INBTSerializable { + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.IEVERLASTING_UPGRADE_CAPABILITY + + object Impl : IEverlastingUpgrade { + override fun serializeNBT(): NBTTagCompound = NBTTagCompound() + override fun deserializeNBT(nbt: NBTTagCompound) {} + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IJukeboxUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IJukeboxUpgrade.kt new file mode 100644 index 0000000..b4763c9 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IJukeboxUpgrade.kt @@ -0,0 +1,36 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.entity.Entity +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable +import net.minecraftforge.items.IItemHandler + +interface IJukeboxUpgrade : ISidelessCapabilityProvider, INBTSerializable { + val discInventory: IItemHandler + + fun play(world: World, pos: BlockPos) + fun play(entity: Entity) + fun stop(world: World, pos: BlockPos) + fun next() + fun previous() + fun tick(world: World, pos: BlockPos?) + + object Impl : IJukeboxUpgrade { + override val discInventory: IItemHandler = net.minecraftforge.items.wrapper.EmptyHandler.INSTANCE + override fun play(world: World, pos: BlockPos) {} + override fun play(entity: Entity) {} + override fun stop(world: World, pos: BlockPos) {} + override fun next() {} + override fun previous() {} + override fun tick(world: World, pos: BlockPos?) {} + override fun serializeNBT() = NBTTagCompound() + override fun deserializeNBT(nbt: NBTTagCompound) {} + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?) = false + override fun getCapability(capability: Capability, facing: EnumFacing?): T? = null + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt new file mode 100644 index 0000000..e309294 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt @@ -0,0 +1,18 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.item.ItemStack +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable +import net.minecraft.nbt.NBTTagCompound + +sealed interface IMagnetUpgrade : ISidelessCapabilityProvider, INBTSerializable { + val range: Double + + fun canPickup(stack: ItemStack): Boolean + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.IMAGNET_UPGRADE_CAPABILITY +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IPumpUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IPumpUpgrade.kt new file mode 100644 index 0000000..bb85250 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IPumpUpgrade.kt @@ -0,0 +1,43 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable +import net.minecraftforge.fluids.FluidStack + +interface IPumpUpgrade : ISidelessCapabilityProvider, INBTSerializable { + var enabled: Boolean + var isInput: Boolean + var interactWithHand: Boolean + var interactWithWorld: Boolean + var interactWithFluidHandlers: Boolean + val fluidFilters: List + + fun tick(player: EntityPlayer?, wrapper: BackpackWrapper, world: World, pos: BlockPos) + fun setFluidFilter(slot: Int, fluid: FluidStack?) + fun fluidMatches(fluid: FluidStack): Boolean + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.IPUMP_UPGRADE_CAPABILITY + + object Impl : IPumpUpgrade { + override var enabled = false + override var isInput = true + override var interactWithHand = false + override var interactWithWorld = false + override var interactWithFluidHandlers = false + override val fluidFilters: List = emptyList() + override fun tick(player: EntityPlayer?, wrapper: BackpackWrapper, world: World, pos: BlockPos) {} + override fun setFluidFilter(slot: Int, fluid: FluidStack?) {} + override fun fluidMatches(fluid: FluidStack): Boolean = false + override fun serializeNBT(): NBTTagCompound = NBTTagCompound() + override fun deserializeNBT(nbt: NBTTagCompound) {} + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IRefillUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IRefillUpgrade.kt new file mode 100644 index 0000000..c1ec718 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IRefillUpgrade.kt @@ -0,0 +1,17 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable + +sealed interface IRefillUpgrade : ISidelessCapabilityProvider, INBTSerializable { + fun refill(player: EntityPlayer, wrapper: BackpackWrapper) + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.IREFILL_UPGRADE_CAPABILITY +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ITankUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ITankUpgrade.kt new file mode 100644 index 0000000..3dd77d7 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ITankUpgrade.kt @@ -0,0 +1,41 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.items.IItemHandler + +interface ITankUpgrade : ISidelessCapabilityProvider, INBTSerializable { + val tankCapacity: Int + fun getTankCapacity(wrapper: BackpackWrapper): Int = tankCapacity + fun getFluid(): FluidStack? + fun fill(wrapper: BackpackWrapper, resource: FluidStack, doFill: Boolean, ignoreInOutLimit: Boolean = false): Int + fun drain(wrapper: BackpackWrapper, maxDrain: Int, doDrain: Boolean, ignoreInOutLimit: Boolean = false): FluidStack? + fun drain(wrapper: BackpackWrapper, resource: FluidStack, doDrain: Boolean, ignoreInOutLimit: Boolean = false): FluidStack? + fun tick(wrapper: BackpackWrapper, world: World) + fun getInventory(): IItemHandler + fun interactWithCursorStack(player: EntityPlayer, wrapper: BackpackWrapper) + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ITANK_UPGRADE_CAPABILITY + + object Impl : ITankUpgrade { + override val tankCapacity = 0 + override fun getFluid(): FluidStack? = null + override fun fill(wrapper: BackpackWrapper, resource: FluidStack, doFill: Boolean, ignoreInOutLimit: Boolean): Int = 0 + override fun drain(wrapper: BackpackWrapper, maxDrain: Int, doDrain: Boolean, ignoreInOutLimit: Boolean): FluidStack? = null + override fun drain(wrapper: BackpackWrapper, resource: FluidStack, doDrain: Boolean, ignoreInOutLimit: Boolean): FluidStack? = null + override fun tick(wrapper: BackpackWrapper, world: World) {} + override fun getInventory(): IItemHandler = net.minecraftforge.items.ItemStackHandler(0) + override fun interactWithCursorStack(player: EntityPlayer, wrapper: BackpackWrapper) {} + override fun serializeNBT(): NBTTagCompound = NBTTagCompound() + override fun deserializeNBT(nbt: NBTTagCompound) {} + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt new file mode 100644 index 0000000..0f008b1 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt @@ -0,0 +1,29 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.block.state.IBlockState +import net.minecraft.entity.Entity +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable + +interface IToolSwapperUpgrade : ISidelessCapabilityProvider, INBTSerializable { + fun onBlockClick(player: EntityPlayer, wrapper: BackpackWrapper, pos: BlockPos, state: IBlockState): Boolean = false + fun onAttackEntity(player: EntityPlayer, wrapper: BackpackWrapper): Boolean = false + fun onBlockInteract(player: EntityPlayer, wrapper: BackpackWrapper, world: World, pos: BlockPos, state: IBlockState): Boolean = false + fun onEntityInteract(player: EntityPlayer, wrapper: BackpackWrapper, entity: Entity): Boolean = false + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY + + object Impl : IToolSwapperUpgrade { + override fun serializeNBT(): NBTTagCompound = NBTTagCompound() + override fun deserializeNBT(nbt: NBTTagCompound) {} + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IVoidUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IVoidUpgrade.kt new file mode 100644 index 0000000..92688c3 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IVoidUpgrade.kt @@ -0,0 +1,16 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable + +sealed interface IVoidUpgrade : ISidelessCapabilityProvider, INBTSerializable { + fun shouldVoid(stack: ItemStack): Boolean + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.IVOID_UPGRADE_CAPABILITY +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt new file mode 100644 index 0000000..713e0e3 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt @@ -0,0 +1,257 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler +import com.cleanroommc.retrosophisticatedbackpacks.item.JukeboxUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.entity.Entity +import net.minecraft.init.Items +import net.minecraft.item.Item +import net.minecraft.item.ItemRecord +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.items.IItemHandler +import java.util.Collections +import java.util.LinkedList + +open class JukeboxUpgradeWrapper(private val slots: Int = 1) : UpgradeWrapper(), IJukeboxUpgrade { + companion object { + private const val INVENTORY_TAG = "Inventory" + private const val IS_PLAYING_TAG = "IsPlaying" + private const val ACTIVE_SLOT_TAG = "ActiveSlot" + private const val SHUFFLE_TAG = "Shuffle" + private const val REPEAT_MODE_TAG = "RepeatMode" + private const val FINISH_TIME_TAG = "FinishTime" + + private const val RECORD_PLAY_EVENT = 1010 + private const val DEFAULT_DISC_LENGTH = 3600L + + private val VANILLA_DISC_LENGTHS = mapOf( + Items.RECORD_13 to 1780L, + Items.RECORD_CAT to 3700L, + Items.RECORD_BLOCKS to 6900L, + Items.RECORD_CHIRP to 3700L, + Items.RECORD_FAR to 3480L, + Items.RECORD_MALL to 3940L, + Items.RECORD_MELLOHI to 1920L, + Items.RECORD_STAL to 3000L, + Items.RECORD_STRAD to 3760L, + Items.RECORD_WARD to 5020L, + Items.RECORD_11 to 1420L, + Items.RECORD_WAIT to 4760L + ) + } + + override val settingsLangKey = "gui.jukebox_settings".asTranslationKey() + private var isPlaying = false + private var activeSlot = -1 + var shuffleEnabled = false + var repeatMode = RepeatMode.NO + private var finishTime = 0L + private var worldPlaying: World? = null + private var posPlaying: BlockPos? = null + private val playlist = LinkedList() + private val history = LinkedList() + + override val discInventory: IItemHandler = object : ExposedItemStackHandler(slots) { + override fun isItemValid(slot: Int, stack: ItemStack): Boolean = + stack.isEmpty || stack.item is ItemRecord + + override fun onContentsChanged(slot: Int) { + super.onContentsChanged(slot) + initPlaylist(excludeActive = true) + } + } + + override fun play(world: World, pos: BlockPos) { + if (world.isRemote) { + return + } + worldPlaying = world + posPlaying = pos + if (!isPlaying) { + playNext() + } + } + + override fun play(entity: Entity) { + play(entity.world, BlockPos(entity)) + } + + override fun stop(world: World, pos: BlockPos) { + if (world.isRemote) { + return + } + world.playEvent(null, RECORD_PLAY_EVENT, pos, 0) + setPlaying(false) + playlist.clear() + history.clear() + } + + override fun next() { + playNext() + } + + override fun previous() { + if (history.isEmpty()) { + return + } + if (activeSlot >= 0) { + playlist.addFirst(activeSlot) + } + activeSlot = history.pollLast() + playDisc() + } + + override fun tick(world: World, pos: BlockPos?) { + if (world.isRemote || !isPlaying) { + return + } + if (pos != null && (activeSlot == -1 || worldPlaying == null || posPlaying == null)) { + worldPlaying = world + posPlaying = pos + } + if (isPlaying && activeSlot == -1) { + playNext() + return + } + if (finishTime > 0L && world.totalWorldTime >= finishTime) { + onDiscFinished() + } + } + + fun toggleShuffle() { + shuffleEnabled = !shuffleEnabled + initPlaylist(excludeActive = true) + } + + fun cycleRepeatMode() { + repeatMode = repeatMode.next() + } + + fun isPlaying(): Boolean = isPlaying + + fun requestPlay() { + setPlaying(true) + } + + fun requestStop() { + worldPlaying?.let { world -> + posPlaying?.let { pos -> stop(world, pos) } + } ?: setPlaying(false) + } + + override fun onBeforeRemoved() { + requestStop() + } + + private fun playNext(startOverIfAtEnd: Boolean = true) { + if (playlist.isEmpty() && startOverIfAtEnd) { + initPlaylist(excludeActive = false) + } + val nextSlot = playlist.poll() ?: return + if (activeSlot >= 0) { + history.add(activeSlot) + while (history.size > slots) { + history.poll() + } + } + activeSlot = nextSlot + playDisc() + } + + private fun onDiscFinished() { + when (repeatMode) { + RepeatMode.ONE -> playDisc() + RepeatMode.ALL -> playNext() + RepeatMode.NO -> playNext(startOverIfAtEnd = false) + } + } + + private fun playDisc() { + val world = worldPlaying ?: return + val pos = posPlaying ?: return + val disc = getDisc() + if (world.isRemote || disc.isEmpty || disc.item !is ItemRecord) { + setPlaying(false) + return + } + world.playEvent(null, RECORD_PLAY_EVENT, pos, 0) + world.playEvent(null, RECORD_PLAY_EVENT, pos, Item.getIdFromItem(disc.item)) + finishTime = world.totalWorldTime + getDiscLength(disc) + setPlaying(true) + } + + private fun getDisc(): ItemStack = + if (activeSlot in 0 until slots) discInventory.getStackInSlot(activeSlot) else ItemStack.EMPTY + + private fun setPlaying(playing: Boolean) { + isPlaying = playing + if (!playing) { + activeSlot = -1 + finishTime = 0L + } + } + + private fun initPlaylist(excludeActive: Boolean) { + playlist.clear() + for (slot in 0 until slots) { + if (!discInventory.getStackInSlot(slot).isEmpty && (!excludeActive || !isPlaying || slot != activeSlot)) { + playlist.add(slot) + } + } + if (shuffleEnabled) { + Collections.shuffle(playlist) + } + } + + private fun getDiscLength(stack: ItemStack): Long = + VANILLA_DISC_LENGTHS[stack.item] ?: DEFAULT_DISC_LENGTH + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setTag(INVENTORY_TAG, (discInventory as ExposedItemStackHandler).serializeNBT()) + nbt.setBoolean(IS_PLAYING_TAG, isPlaying) + nbt.setInteger(ACTIVE_SLOT_TAG, activeSlot) + nbt.setBoolean(SHUFFLE_TAG, shuffleEnabled) + nbt.setString(REPEAT_MODE_TAG, repeatMode.name) + nbt.setLong(FINISH_TIME_TAG, finishTime) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + (discInventory as ExposedItemStackHandler).deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) + isPlaying = nbt.getBoolean(IS_PLAYING_TAG) + activeSlot = nbt.getInteger(ACTIVE_SLOT_TAG) + shuffleEnabled = nbt.getBoolean(SHUFFLE_TAG) + repeatMode = runCatching { RepeatMode.valueOf(nbt.getString(REPEAT_MODE_TAG)) }.getOrDefault(RepeatMode.NO) + finishTime = nbt.getLong(FINISH_TIME_TAG) + initPlaylist(excludeActive = true) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.JUKEBOX_UPGRADE_CAPABILITY || + capability == Capabilities.IJUKEBOX_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} + +class AdvancedJukeboxUpgradeWrapper : JukeboxUpgradeWrapper(12) { + override val settingsLangKey = "gui.advanced_jukebox_settings".asTranslationKey() + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ADVANCED_JUKEBOX_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} + +enum class RepeatMode { + ALL, + ONE, + NO; + + fun next(): RepeatMode = entries[(ordinal + 1) % entries.size] +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt new file mode 100644 index 0000000..1cee70d --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt @@ -0,0 +1,43 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.item.MagnetUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability + +open class MagnetUpgradeWrapper(filterSlots: Int = 9, override val range: Double = 3.0) : + BasicUpgradeWrapper(filterSlots), IMagnetUpgrade { + override val settingsLangKey = "gui.magnet_settings".asTranslationKey() + + init { + filterType = IBasicFilterable.FilterType.BLACKLIST + } + + override fun canPickup(stack: ItemStack): Boolean = + enabled && matchesAllowEmpty(stack) + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.MAGNET_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} + +class AdvancedMagnetUpgradeWrapper : AdvancedUpgradeWrapper(), IMagnetUpgrade { + override val settingsLangKey = "gui.advanced_magnet_settings".asTranslationKey() + override val range = 5.0 + + init { + filterType = IBasicFilterable.FilterType.BLACKLIST + } + + override fun canPickup(stack: ItemStack): Boolean = + enabled && matchesAllowEmpty(stack) + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ADVANCED_MAGNET_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt new file mode 100644 index 0000000..afaa507 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt @@ -0,0 +1,275 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackFluidHandler +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.item.PumpUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumHand +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.fluids.Fluid +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.FluidUtil +import net.minecraftforge.fluids.capability.CapabilityFluidHandler +import net.minecraftforge.fluids.capability.IFluidHandler +import java.util.LinkedList + +open class PumpUpgradeWrapper( + private val filterSlots: Int = 0, + interactWithHandDefault: Boolean = false, + interactWithWorldDefault: Boolean = false, + interactWithFluidHandlersDefault: Boolean = true +) : UpgradeWrapper(), IPumpUpgrade, IToggleable { + companion object { + private const val ENABLED_TAG = "Enabled" + private const val INPUT_TAG = "Input" + private const val HAND_TAG = "InteractWithHand" + private const val WORLD_TAG = "InteractWithWorld" + private const val FLUID_HANDLERS_TAG = "InteractWithFluidHandlers" + private const val COOLDOWN_UNTIL_TAG = "CooldownUntil" + private const val LAST_HAND_ACTION_TAG = "LastHandAction" + private const val FILTER_TAG = "FluidFilter" + private const val DID_NOTHING_COOLDOWN = 40L + private const val HAND_COOLDOWN = 3L + private const val WORLD_COOLDOWN = 20L + private const val FLUID_HANDLER_COOLDOWN = 20L + private const val PLAYER_SEARCH_RANGE = 3.0 + private const val WORLD_RANGE = 4 + private const val MAX_INPUT_OUTPUT_PER_ROW = 20 + } + + override val settingsLangKey = "gui.pump_settings".asTranslationKey() + override var enabled = true + override var isInput = true + override var interactWithHand = interactWithHandDefault + override var interactWithWorld = interactWithWorldDefault + override var interactWithFluidHandlers = interactWithFluidHandlersDefault + override val fluidFilters: MutableList = MutableList(filterSlots) { null } + private var cooldownUntil = 0L + private var lastHandAction = -1L + + override fun tick(player: EntityPlayer?, wrapper: BackpackWrapper, world: World, pos: BlockPos) { + if (!enabled || world.isRemote || world.totalWorldTime < cooldownUntil || !wrapper.hasTankUpgrade()) { + return + } + val storage = BackpackFluidHandler(wrapper) + cooldownUntil = world.totalWorldTime + tick(storage, player, wrapper, world, pos) + } + + private fun tick(storage: IFluidHandler, player: EntityPlayer?, wrapper: BackpackWrapper, world: World, pos: BlockPos): Long { + if (interactWithHand && handlePlayers(player, world, pos, storage)) { + lastHandAction = world.totalWorldTime + return HAND_COOLDOWN + } + if (interactWithWorld) { + val cooldown = if (isInput) fillFromBlockInRange(world, pos, storage) else placeFluidInWorld(world, pos, storage) + if (cooldown != null) { + return cooldown + } + } + if (interactWithFluidHandlers && interactWithAttachedFluidHandlers(world, pos, storage, wrapper)) { + return FLUID_HANDLER_COOLDOWN + } + return if (lastHandAction + HAND_COOLDOWN * 10 > world.totalWorldTime) HAND_COOLDOWN else DID_NOTHING_COOLDOWN + } + + override fun setFluidFilter(slot: Int, fluid: FluidStack?) { + if (slot !in fluidFilters.indices) { + return + } + fluidFilters[slot] = fluid?.copy()?.also { it.amount = Fluid.BUCKET_VOLUME } + } + + override fun fluidMatches(fluid: FluidStack): Boolean = + fluidFilters.isEmpty() || fluidFilters.filterNotNull().let { filters -> + filters.isEmpty() || filters.any { it.isFluidEqual(fluid) } + } + + private fun handlePlayers(player: EntityPlayer?, world: World, pos: BlockPos, storage: IFluidHandler): Boolean { + if (player != null) { + return handlePlayer(player, storage) + } + val players = world.getEntitiesWithinAABB( + EntityPlayer::class.java, + AxisAlignedBB( + pos.x - PLAYER_SEARCH_RANGE, pos.y - PLAYER_SEARCH_RANGE, pos.z - PLAYER_SEARCH_RANGE, + pos.x + 1 + PLAYER_SEARCH_RANGE, pos.y + 1 + PLAYER_SEARCH_RANGE, pos.z + 1 + PLAYER_SEARCH_RANGE + ) + ) + return players.any { handlePlayer(it, storage) } + } + + private fun handlePlayer(player: EntityPlayer, storage: IFluidHandler): Boolean = + handleHand(player, EnumHand.MAIN_HAND, storage) || handleHand(player, EnumHand.OFF_HAND, storage) + + private fun handleHand(player: EntityPlayer, hand: EnumHand, storage: IFluidHandler): Boolean { + val stack = player.getHeldItem(hand) + if (stack.isEmpty || stack.count != 1) { + return false + } + val itemHandler = FluidUtil.getFluidHandler(stack.copy()) ?: return false + val moved = if (isInput) fillFromFluidHandler(itemHandler, storage, Fluid.BUCKET_VOLUME) + else fillFluidHandler(itemHandler, storage, Fluid.BUCKET_VOLUME) + if (moved) { + player.setHeldItem(hand, itemHandler.container) + } + return moved + } + + private fun interactWithAttachedFluidHandlers(world: World, pos: BlockPos, storage: IFluidHandler, wrapper: BackpackWrapper): Boolean { + for (side in EnumFacing.values()) { + val te = world.getTileEntity(pos.offset(side)) ?: continue + val fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side.opposite) ?: continue + if (if (isInput) fillFromFluidHandler(fluidHandler, storage, getMaxInOut(wrapper)) + else fillFluidHandler(fluidHandler, storage, getMaxInOut(wrapper)) + ) { + return true + } + } + return false + } + + private fun fillFromBlockInRange(world: World, basePos: BlockPos, storage: IFluidHandler): Long? { + val queue = LinkedList() + val searched = mutableSetOf() + queue.add(basePos) + searched.add(basePos) + while (queue.isNotEmpty()) { + val pos = queue.poll() + if (fillFromBlock(world, pos, storage)) { + return maxOf(1L, Math.sqrt(distanceSq(basePos, pos).toDouble()).toLong()) * WORLD_COOLDOWN + } + for (side in EnumFacing.values()) { + val next = pos.offset(side) + if (searched.add(next) && distanceSq(basePos, next) < WORLD_RANGE * WORLD_RANGE) { + queue.add(next) + } + } + } + return null + } + + private fun fillFromBlock(world: World, pos: BlockPos, storage: IFluidHandler): Boolean { + val fluidHandler = FluidUtil.getFluidHandler(world, pos, null) ?: return false + return fillFromFluidHandler(fluidHandler, storage, Fluid.BUCKET_VOLUME) + } + + private fun placeFluidInWorld(world: World, pos: BlockPos, storage: IFluidHandler): Long? { + for (side in EnumFacing.values()) { + if (side == EnumFacing.UP) { + continue + } + val offsetPos = pos.offset(side) + if (!isValidForFluidPlacement(world, offsetPos)) { + continue + } + for (tank in storage.tankProperties) { + val fluid = tank.contents ?: continue + if (fluid.amount <= 0 || !fluidMatches(fluid)) { + continue + } + val resource = FluidStack(fluid.fluid, minOf(Fluid.BUCKET_VOLUME, fluid.amount), fluid.tag?.copy()) + if (FluidUtil.tryPlaceFluid(null, world, offsetPos, storage, resource)) { + return WORLD_COOLDOWN + } + } + } + return null + } + + private fun isValidForFluidPlacement(world: World, pos: BlockPos): Boolean { + val state = world.getBlockState(pos) + return world.isAirBlock(pos) || !state.material.isSolid || state.block.isReplaceable(world, pos) + } + + private fun fillFromFluidHandler(source: IFluidHandler, storage: IFluidHandler, maxDrain: Int): Boolean { + val contained = source.drain(maxDrain, false) ?: return false + if (contained.amount <= 0 || !fluidMatches(contained)) { + return false + } + return FluidUtil.tryFluidTransfer(storage, source, contained, true) != null + } + + private fun fillFluidHandler(destination: IFluidHandler, storage: IFluidHandler, maxFill: Int): Boolean { + for (tank in storage.tankProperties) { + val fluid = tank.contents ?: continue + if (fluid.amount <= 0 || !fluidMatches(fluid)) { + continue + } + val resource = FluidStack(fluid.fluid, minOf(maxFill, fluid.amount), fluid.tag?.copy()) + if (FluidUtil.tryFluidTransfer(destination, storage, resource, true) != null) { + return true + } + } + return false + } + + private fun getMaxInOut(wrapper: BackpackWrapper): Int = + maxOf(Fluid.BUCKET_VOLUME, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * maxOf(1, wrapper.getTotalStackMultiplier())) + + private fun getSlotRows(wrapper: BackpackWrapper): Int = + maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) + + private fun distanceSq(first: BlockPos, second: BlockPos): Int { + val dx = first.x - second.x + val dy = first.y - second.y + val dz = first.z - second.z + return dx * dx + dy * dy + dz * dz + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setBoolean(ENABLED_TAG, enabled) + nbt.setBoolean(INPUT_TAG, isInput) + nbt.setBoolean(HAND_TAG, interactWithHand) + nbt.setBoolean(WORLD_TAG, interactWithWorld) + nbt.setBoolean(FLUID_HANDLERS_TAG, interactWithFluidHandlers) + nbt.setLong(COOLDOWN_UNTIL_TAG, cooldownUntil) + nbt.setLong(LAST_HAND_ACTION_TAG, lastHandAction) + fluidFilters.forEachIndexed { index, fluid -> + fluid?.let { nbt.setTag("$FILTER_TAG$index", it.writeToNBT(NBTTagCompound())) } + } + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + enabled = if (nbt.hasKey(ENABLED_TAG)) nbt.getBoolean(ENABLED_TAG) else enabled + isInput = if (nbt.hasKey(INPUT_TAG)) nbt.getBoolean(INPUT_TAG) else isInput + interactWithHand = if (nbt.hasKey(HAND_TAG)) nbt.getBoolean(HAND_TAG) else interactWithHand + interactWithWorld = if (nbt.hasKey(WORLD_TAG)) nbt.getBoolean(WORLD_TAG) else interactWithWorld + interactWithFluidHandlers = if (nbt.hasKey(FLUID_HANDLERS_TAG)) nbt.getBoolean(FLUID_HANDLERS_TAG) else interactWithFluidHandlers + cooldownUntil = nbt.getLong(COOLDOWN_UNTIL_TAG) + lastHandAction = nbt.getLong(LAST_HAND_ACTION_TAG) + for (slot in fluidFilters.indices) { + fluidFilters[slot] = if (nbt.hasKey("$FILTER_TAG$slot")) { + FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag("$FILTER_TAG$slot")) + } else null + } + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.PUMP_UPGRADE_CAPABILITY || + capability == Capabilities.IPUMP_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} + +class AdvancedPumpUpgradeWrapper : PumpUpgradeWrapper( + filterSlots = 4, + interactWithHandDefault = true, + interactWithWorldDefault = false, + interactWithFluidHandlersDefault = true +) { + override val settingsLangKey = "gui.advanced_pump_settings".asTranslationKey() + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ADVANCED_PUMP_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt new file mode 100644 index 0000000..20b25f3 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt @@ -0,0 +1,267 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.item.RefillUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.nbt.NBTTagList +import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumHand +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.Constants +import net.minecraftforge.items.ItemHandlerHelper + +open class RefillUpgradeWrapper(filterSlots: Int = 6) : + BasicUpgradeWrapper(filterSlots), IRefillUpgrade { + override val settingsLangKey = "gui.refill_settings".asTranslationKey() + + init { + filterType = IBasicFilterable.FilterType.BLACKLIST + } + + override fun refill(player: EntityPlayer, wrapper: BackpackWrapper) { + if (!enabled) { + return + } + + for ((filterSlot, filter) in filterItems.inventory.withIndex()) { + if (!filter.isEmpty) { + refillFilter(player, wrapper, filter, getTargetSlot(filterSlot)) + } + } + } + + open fun getTargetSlot(filterSlot: Int): TargetSlot = + TargetSlot.ANY + + protected fun refillFilter(player: EntityPlayer, wrapper: BackpackWrapper, filter: ItemStack, targetSlot: TargetSlot) { + var missingCount = targetSlot.getMissingCount(player, filter) + val carried = player.inventory.itemStack + if (ItemHandlerHelper.canItemStacksStack(carried, filter)) { + missingCount -= minOf(missingCount, carried.count) + } + if (missingCount <= 0) { + return + } + + val extracted = wrapper.extractMatching(filter, missingCount, true) + if (extracted.isEmpty) { + return + } + + val remaining = targetSlot.insert(player, extracted) + val moved = extracted.count - remaining.count + + if (moved > 0) { + wrapper.extractMatching(filter, moved, false) + } + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.REFILL_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) + + enum class TargetSlot { + ANY { + override fun getMissingCount(player: EntityPlayer, filter: ItemStack): Int { + var count = 0 + for (slot in 0 until player.inventory.mainInventory.size) { + val stack = player.inventory.getStackInSlot(slot) + if (stack.isEmpty) { + count += filter.maxStackSize + } else if (ItemHandlerHelper.canItemStacksStack(stack, filter)) { + count += stack.maxStackSize - stack.count + } + } + return count + } + + override fun insert(player: EntityPlayer, stack: ItemStack): ItemStack { + val remaining = stack.copy() + for (slot in 0 until player.inventory.mainInventory.size) { + val target = player.inventory.getStackInSlot(slot) + if (!ItemHandlerHelper.canItemStacksStack(target, remaining)) { + continue + } + val moved = minOf(remaining.count, target.maxStackSize - target.count) + if (moved > 0) { + target.grow(moved) + remaining.shrink(moved) + } + if (remaining.isEmpty) { + return ItemStack.EMPTY + } + } + for (slot in 0 until player.inventory.mainInventory.size) { + if (!player.inventory.getStackInSlot(slot).isEmpty) { + continue + } + player.inventory.setInventorySlotContents(slot, remaining.copy()) + return ItemStack.EMPTY + } + return remaining + } + }, + MAIN_HAND { + override fun getMissingCount(player: EntityPlayer, filter: ItemStack): Int = + getSlotMissingCount(player.heldItemMainhand, filter) + + override fun insert(player: EntityPlayer, stack: ItemStack): ItemStack = + refillSlot(player.heldItemMainhand, stack) { player.inventory.setInventorySlotContents(player.inventory.currentItem, it) } + }, + OFF_HAND { + override fun getMissingCount(player: EntityPlayer, filter: ItemStack): Int = + getSlotMissingCount(player.heldItemOffhand, filter) + + override fun insert(player: EntityPlayer, stack: ItemStack): ItemStack = + refillSlot(player.heldItemOffhand, stack) { player.setHeldItem(net.minecraft.util.EnumHand.OFF_HAND, it) } + }, + HOTBAR_1, HOTBAR_2, HOTBAR_3, HOTBAR_4, HOTBAR_5, HOTBAR_6, HOTBAR_7, HOTBAR_8, HOTBAR_9; + + open fun getMissingCount(player: EntityPlayer, filter: ItemStack): Int { + val slot = ordinal - HOTBAR_1.ordinal + return getSlotMissingCount(player.inventory.getStackInSlot(slot), filter) + } + + open fun insert(player: EntityPlayer, stack: ItemStack): ItemStack { + val slot = ordinal - HOTBAR_1.ordinal + return refillSlot(player.inventory.getStackInSlot(slot), stack) { + player.inventory.setInventorySlotContents(slot, it) + } + } + + companion object { + private fun getSlotMissingCount(stack: ItemStack, filter: ItemStack): Int = + if (stack.isEmpty) filter.maxStackSize + else if (ItemHandlerHelper.canItemStacksStack(stack, filter)) stack.maxStackSize - stack.count + else 0 + + private fun refillSlot(stack: ItemStack, toAdd: ItemStack, setter: (ItemStack) -> Unit): ItemStack { + if (stack.isEmpty) { + setter(toAdd.copy()) + return ItemStack.EMPTY + } + if (!ItemHandlerHelper.canItemStacksStack(stack, toAdd)) { + return toAdd + } + val moved = minOf(toAdd.count, stack.maxStackSize - stack.count) + stack.grow(moved) + return if (moved == toAdd.count) ItemStack.EMPTY else ItemHandlerHelper.copyStackWithSize(toAdd, toAdd.count - moved) + } + } + } +} + +class AdvancedRefillUpgradeWrapper : RefillUpgradeWrapper(12) { + companion object { + private const val TARGET_SLOTS_TAG = "TargetSlots" + private const val SLOT_TAG = "Slot" + private const val TARGET_TAG = "Target" + } + + override val settingsLangKey = "gui.advanced_refill_settings".asTranslationKey() + private val targetSlots = mutableMapOf() + + override fun getTargetSlot(filterSlot: Int): TargetSlot = + targetSlots[filterSlot] ?: TargetSlot.ANY + + fun setTargetSlot(filterSlot: Int, targetSlot: TargetSlot) { + targetSlots[filterSlot] = targetSlot + } + + fun pickBlock(player: EntityPlayer, wrapper: BackpackWrapper, pickedStack: ItemStack): Boolean { + if (!enabled || pickedStack.isEmpty) { + return false + } + + val extracted = wrapper.extractMatching(pickedStack, pickedStack.maxStackSize, true) + if (extracted.isEmpty || !moveHeldStackAway(player, wrapper)) { + return false + } + + player.setHeldItem(EnumHand.MAIN_HAND, wrapper.extractMatching(pickedStack, extracted.count, false)) + player.inventoryContainer.detectAndSendChanges() + return true + } + + private fun moveHeldStackAway(player: EntityPlayer, wrapper: BackpackWrapper): Boolean { + val held = player.heldItemMainhand + if (held.isEmpty) { + return true + } + + if (wrapper.insertStack(held.copy(), true).isEmpty) { + wrapper.insertStack(held.copy(), false) + player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY) + return true + } + + val remaining = held.copy() + val currentSlot = player.inventory.currentItem + for (slot in 0 until player.inventory.mainInventory.size) { + if (slot == currentSlot) { + continue + } + val target = player.inventory.getStackInSlot(slot) + if (!ItemHandlerHelper.canItemStacksStack(target, remaining)) { + continue + } + val moved = minOf(remaining.count, target.maxStackSize - target.count) + if (moved > 0) { + target.grow(moved) + remaining.shrink(moved) + } + if (remaining.isEmpty) { + break + } + } + for (slot in 0 until player.inventory.mainInventory.size) { + if (remaining.isEmpty) { + break + } + if (slot != currentSlot && player.inventory.getStackInSlot(slot).isEmpty) { + player.inventory.setInventorySlotContents(slot, remaining.copy()) + remaining.count = 0 + } + } + + if (!remaining.isEmpty) { + return false + } + + player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY) + return true + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + val list = NBTTagList() + for ((slot, target) in targetSlots) { + val entry = NBTTagCompound() + entry.setInteger(SLOT_TAG, slot) + entry.setByte(TARGET_TAG, target.ordinal.toByte()) + list.appendTag(entry) + } + nbt.setTag(TARGET_SLOTS_TAG, list) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + targetSlots.clear() + val list = nbt.getTagList(TARGET_SLOTS_TAG, Constants.NBT.TAG_COMPOUND) + for (entry in list) { + val compound = entry as NBTTagCompound + val targetOrdinal = compound.getByte(TARGET_TAG).toInt() + targetSlots[compound.getInteger(SLOT_TAG)] = TargetSlot.entries.getOrElse(targetOrdinal) { TargetSlot.ANY } + } + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ADVANCED_REFILL_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt new file mode 100644 index 0000000..4600a6d --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt @@ -0,0 +1,218 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler +import com.cleanroommc.retrosophisticatedbackpacks.item.TankUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.FluidUtil +import net.minecraftforge.fluids.capability.IFluidTankProperties +import net.minecraftforge.fluids.capability.FluidTankProperties +import net.minecraftforge.items.IItemHandler +import net.minecraftforge.items.ItemHandlerHelper + +class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { + companion object { + private const val FLUID_TAG = "Fluid" + private const val INVENTORY_TAG = "Inventory" + private const val INPUT_SLOT = 0 + private const val OUTPUT_SLOT = 1 + private const val INPUT_RESULT_SLOT = 2 + private const val OUTPUT_RESULT_SLOT = 3 + private const val BUCKET = 1000 + private const val CAPACITY_PER_ROW = 4000 + private const val MAX_INPUT_OUTPUT_PER_ROW = 20 + } + + override val settingsLangKey = "gui.tank_settings".asTranslationKey() + override val tankCapacity = CAPACITY_PER_ROW * 3 + private var fluid: FluidStack? = null + private val inventory = object : ExposedItemStackHandler(4) { + override fun isItemValid(slot: Int, stack: ItemStack): Boolean = + slot == INPUT_RESULT_SLOT || slot == OUTPUT_RESULT_SLOT || stack.isEmpty || FluidUtil.getFluidHandler(stack) != null + + override fun onContentsChanged(slot: Int) { + super.onContentsChanged(slot) + } + } + + override fun getFluid(): FluidStack? = + fluid?.copy() + + override fun getTankCapacity(wrapper: BackpackWrapper): Int = + maxOf(BUCKET, getSlotRows(wrapper) * CAPACITY_PER_ROW * getStackMultiplier(wrapper)) + + private fun getMaxInOut(wrapper: BackpackWrapper): Int = + maxOf(BUCKET, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * getStackMultiplier(wrapper)) + + private fun getSlotRows(wrapper: BackpackWrapper): Int = + maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) + + private fun getStackMultiplier(wrapper: BackpackWrapper): Int = + maxOf(1, wrapper.getTotalStackMultiplier()) + + override fun fill(wrapper: BackpackWrapper, resource: FluidStack, doFill: Boolean, ignoreInOutLimit: Boolean): Int { + val current = fluid + if (resource.amount <= 0 || current != null && !current.isFluidEqual(resource)) { + return 0 + } + + val accepted = minOf(resource.amount, getTankCapacity(wrapper) - (current?.amount ?: 0), if (ignoreInOutLimit) Int.MAX_VALUE else getMaxInOut(wrapper)) + if (doFill && accepted > 0) { + fluid = if (current == null) FluidStack(resource.fluid, accepted, resource.tag?.copy()) + else current.also { it.amount += accepted } + } + return accepted + } + + override fun drain(wrapper: BackpackWrapper, maxDrain: Int, doDrain: Boolean, ignoreInOutLimit: Boolean): FluidStack? { + val current = fluid ?: return null + val drained = minOf(maxDrain, current.amount, if (ignoreInOutLimit) Int.MAX_VALUE else getMaxInOut(wrapper)) + if (drained <= 0) { + return null + } + + val result = FluidStack(current.fluid, drained, current.tag?.copy()) + if (doDrain) { + current.amount -= drained + if (current.amount <= 0) { + fluid = null + } + } + return result + } + + override fun drain(wrapper: BackpackWrapper, resource: FluidStack, doDrain: Boolean, ignoreInOutLimit: Boolean): FluidStack? { + val current = fluid ?: return null + if (!current.isFluidEqual(resource)) { + return null + } + return drain(wrapper, resource.amount, doDrain, ignoreInOutLimit) + } + + override fun tick(wrapper: BackpackWrapper, world: World) { + if (world.totalWorldTime % 20L != 0L) { + return + } + tryDrainInput(wrapper) + tryFillOutput(wrapper) + } + + override fun getInventory(): IItemHandler = + inventory + + override fun interactWithCursorStack(player: EntityPlayer, wrapper: BackpackWrapper) { + val cursor = player.inventory.itemStack + if (cursor.isEmpty) { + return + } + val handler = FluidUtil.getFluidHandler(cursor.copy()) ?: return + val current = fluid + if (current != null && fillHandler(wrapper, handler, false)) { + player.inventory.itemStack = handler.container + } else if (drainHandler(wrapper, handler, false)) { + player.inventory.itemStack = handler.container + } + } + + private fun tryDrainInput(wrapper: BackpackWrapper): Boolean { + val stack = inventory.getStackInSlot(INPUT_SLOT) + if (stack.isEmpty) { + return false + } + val single = ItemHandlerHelper.copyStackWithSize(stack, 1) + val handler = FluidUtil.getFluidHandler(single) ?: return false + if (!drainHandler(wrapper, handler, true)) { + return false + } + stack.shrink(1) + if (stack.isEmpty) { + inventory.setStackInSlot(INPUT_SLOT, ItemStack.EMPTY) + } + inventory.insertItem(INPUT_RESULT_SLOT, handler.container, false) + return true + } + + private fun tryFillOutput(wrapper: BackpackWrapper): Boolean { + val stack = inventory.getStackInSlot(OUTPUT_SLOT) + if (stack.isEmpty) { + return false + } + val single = ItemHandlerHelper.copyStackWithSize(stack, 1) + val handler = FluidUtil.getFluidHandler(single) ?: return false + if (!fillHandler(wrapper, handler, true)) { + return false + } + stack.shrink(1) + if (stack.isEmpty) { + inventory.setStackInSlot(OUTPUT_SLOT, ItemStack.EMPTY) + } + inventory.insertItem(OUTPUT_RESULT_SLOT, handler.container, false) + return true + } + + private fun drainHandler(wrapper: BackpackWrapper, handler: net.minecraftforge.fluids.capability.IFluidHandlerItem, moveResult: Boolean): Boolean { + val extracted = if (fluid == null) handler.drain(getMaxInOut(wrapper), false) else handler.drain(FluidStack(fluid!!.fluid, getTankCapacity(wrapper) - fluid!!.amount), false) + if (extracted == null || extracted.amount <= 0 || fill(wrapper, extracted, false) <= 0) { + return false + } + if (moveResult) { + val preview = FluidUtil.getFluidHandler(handler.container.copy()) ?: return false + val filled = fill(wrapper, extracted, false) + preview.drain(FluidStack(extracted.fluid, filled, extracted.tag?.copy()), true) + if (!inventory.insertItem(INPUT_RESULT_SLOT, preview.container, true).isEmpty) { + return false + } + } + val filled = fill(wrapper, extracted, true) + handler.drain(FluidStack(extracted.fluid, filled, extracted.tag?.copy()), true) + return true + } + + private fun fillHandler(wrapper: BackpackWrapper, handler: net.minecraftforge.fluids.capability.IFluidHandlerItem, moveResult: Boolean): Boolean { + val current = fluid ?: return false + val filled = handler.fill(FluidStack(current.fluid, minOf(getMaxInOut(wrapper), current.amount), current.tag?.copy()), false) + if (filled <= 0 || drain(wrapper, filled, false) == null) { + return false + } + if (moveResult) { + val preview = FluidUtil.getFluidHandler(handler.container.copy()) ?: return false + val drained = drain(wrapper, filled, false) ?: return false + preview.fill(drained, true) + if (!inventory.insertItem(OUTPUT_RESULT_SLOT, preview.container, true).isEmpty) { + return false + } + } + val drained = drain(wrapper, filled, true) ?: return false + handler.fill(drained, true) + return true + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + fluid?.let { nbt.setTag(FLUID_TAG, it.writeToNBT(NBTTagCompound())) } + nbt.setTag(INVENTORY_TAG, inventory.serializeNBT()) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + fluid = if (nbt.hasKey(FLUID_TAG)) FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag(FLUID_TAG)) else null + inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.TANK_UPGRADE_CAPABILITY || + capability == Capabilities.ITANK_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) + + fun getTankProperties(wrapper: BackpackWrapper): Array = + arrayOf(FluidTankProperties(getFluid(), getTankCapacity(wrapper), true, true)) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt new file mode 100644 index 0000000..70c47cd --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt @@ -0,0 +1,271 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem +import com.cleanroommc.retrosophisticatedbackpacks.item.ToolSwapperUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.block.Block +import net.minecraft.block.material.Material +import net.minecraft.block.state.IBlockState +import net.minecraft.entity.Entity +import net.minecraft.entity.SharedMonsterAttributes +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.init.Blocks +import net.minecraft.item.ItemAxe +import net.minecraft.item.ItemShears +import net.minecraft.item.ItemStack +import net.minecraft.item.ItemSword +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.IShearable +import net.minecraftforge.common.capabilities.Capability +import java.util.LinkedList + +open class ToolSwapperUpgradeWrapper( + private val hasSettingsTab: Boolean = false, + private val swapToolOnKeyPress: Boolean = false, +) : BasicUpgradeWrapper(8), IToolSwapperUpgrade { + companion object { + private const val SHOULD_SWAP_WEAPON_TAG = "ShouldSwapWeapon" + private const val TOOL_SWAP_MODE_TAG = "ToolSwapMode" + } + + override val settingsLangKey = "gui.tool_swapper_settings".asTranslationKey() + var shouldSwapWeapon = true + var toolSwapMode = ToolSwapMode.ANY + private var lastMinedBlock: Block = Blocks.AIR + private var toolCacheFor: String? = null + private val toolCache = LinkedList() + + override fun onBlockClick(player: EntityPlayer, wrapper: BackpackWrapper, pos: BlockPos, state: IBlockState): Boolean { + if (!enabled || player.isCreative || player.isSpectator || toolSwapMode == ToolSwapMode.NO_SWAP || state.material == Material.AIR) { + return false + } + + val held = player.heldItemMainhand + if (held.item is BackpackItem || (toolSwapMode == ToolSwapMode.ONLY_TOOLS && isWeapon(held, player)) || (!isWeapon(held, player) && isNotTool(held)) || !matchesAllowEmpty(held)) { + return false + } + + val heldSpeed = if (isGoodAtBreaking(player, pos, state, held)) { + if (lastMinedBlock == state.block || state.getBlockHardness(player.world, pos) == 0f) { + return true + } + held.getDestroySpeed(state) + } else 0f + lastMinedBlock = state.block + val selectedSlot = findBestToolSlot(wrapper, player, pos, state, heldSpeed) ?: return false + return swapMainHandWithBackpackSlot(player, wrapper, selectedSlot) + } + + override fun onAttackEntity(player: EntityPlayer, wrapper: BackpackWrapper): Boolean { + if (!enabled || !shouldSwapWeapon) { + return false + } + + val held = player.heldItemMainhand + if (isWeapon(held, player)) { + return true + } + if (held.item is BackpackItem || isNotTool(held) || !matchesAllowEmpty(held)) { + return false + } + + val selectedSlot = findBestWeaponSlot(wrapper, player) ?: return false + return swapMainHandWithBackpackSlot(player, wrapper, selectedSlot) + } + + override fun onBlockInteract(player: EntityPlayer, wrapper: BackpackWrapper, world: World, pos: BlockPos, state: IBlockState): Boolean { + if (!enabled || !swapToolOnKeyPress || player.heldItemMainhand.item is BackpackItem) { + return false + } + return tryToSwapTool(player, wrapper, state.block.registryName?.toString()) { + itemWorksOnBlock(world, pos, state, player, it) + } + } + + override fun onEntityInteract(player: EntityPlayer, wrapper: BackpackWrapper, entity: Entity): Boolean { + if (!enabled || !swapToolOnKeyPress || player.heldItemMainhand.item is BackpackItem) { + return false + } + return tryToSwapTool(player, wrapper, entity.javaClass.name) { itemWorksOnEntity(entity, it) } + } + + private fun findBestToolSlot(wrapper: BackpackWrapper, player: EntityPlayer, pos: BlockPos, state: IBlockState, heldSpeed: Float): Int? { + var bestSlot: Int? = null + var bestSpeed = heldSpeed + for (slot in 0 until wrapper.slots) { + val stack = wrapper.getStackInSlot(slot) + if (stack.isEmpty || !matchesAllowEmpty(stack) || !isGoodAtBreaking(player, pos, state, stack)) { + continue + } + val speed = stack.getDestroySpeed(state) + if (speed > bestSpeed || state.getPlayerRelativeBlockHardness(player, player.world, pos) >= 1f) { + bestSpeed = speed + bestSlot = slot + } + } + return bestSlot + } + + private fun findBestWeaponSlot(wrapper: BackpackWrapper, player: EntityPlayer): Int? { + var bestSlot: Int? = null + var bestDamage = getAttackDamage(player.heldItemMainhand, player) + for (slot in 0 until wrapper.slots) { + val stack = wrapper.getStackInSlot(slot) + if (stack.isEmpty || !matchesAllowEmpty(stack) || !isWeapon(stack, player)) { + continue + } + val damage = getAttackDamage(stack, player) + if (damage > bestDamage) { + bestDamage = damage + bestSlot = slot + } + } + return bestSlot + } + + private fun tryToSwapTool( + player: EntityPlayer, + wrapper: BackpackWrapper, + targetRegistryName: String?, + predicate: (ItemStack) -> Boolean + ): Boolean { + if (toolCacheFor != targetRegistryName) { + toolCache.clear() + toolCacheFor = targetRegistryName + } + + val held = player.heldItemMainhand + if (!held.isEmpty && predicate(held) && toolCache.none { isSameTool(it, held) }) { + toolCache.offer(held.copy().also { it.count = 1 }) + } + + val selectedSlot = findToolToSwapSlot(wrapper, predicate) ?: return false + val selectedTool = wrapper.getStackInSlot(selectedSlot).copy().also { it.count = 1 } + if (!swapMainHandWithBackpackSlot(player, wrapper, selectedSlot)) { + return false + } + toolCache.offer(selectedTool) + return true + } + + private fun findToolToSwapSlot(wrapper: BackpackWrapper, predicate: (ItemStack) -> Boolean): Int? { + val alreadyGivenBefore = mutableListOf() + for (slot in 0 until wrapper.slots) { + val stack = wrapper.getStackInSlot(slot) + if (!stack.isEmpty && matchesAllowEmpty(stack) && predicate(stack)) { + if (toolCache.none { isSameTool(it, stack) }) { + return slot + } + alreadyGivenBefore.add(stack.copy().also { it.count = 1 }) + } + } + + while (toolCache.peek() != null) { + val cached = toolCache.poll() + if (alreadyGivenBefore.any { isSameTool(it, cached) }) { + return findSlotWithSameTool(wrapper, cached, predicate) + } + } + return null + } + + private fun findSlotWithSameTool(wrapper: BackpackWrapper, tool: ItemStack, predicate: (ItemStack) -> Boolean): Int? { + for (slot in 0 until wrapper.slots) { + val stack = wrapper.getStackInSlot(slot) + if (!stack.isEmpty && matchesAllowEmpty(stack) && predicate(stack) && isSameTool(stack, tool)) { + return slot + } + } + return null + } + + private fun isSameTool(first: ItemStack, second: ItemStack): Boolean = + !first.isEmpty && !second.isEmpty && first.item == second.item + + private fun swapMainHandWithBackpackSlot(player: EntityPlayer, wrapper: BackpackWrapper, slot: Int): Boolean { + val held = player.heldItemMainhand + val tool = wrapper.extractItem(slot, 1, true) + if (tool.isEmpty || (!held.isEmpty && !wrapper.insertStack(held.copy(), true).isEmpty && tool.count != 1)) { + return false + } + + player.setHeldItem(net.minecraft.util.EnumHand.MAIN_HAND, wrapper.extractItem(slot, 1, false)) + if (!held.isEmpty) { + wrapper.insertStack(held.copy(), false) + } + return true + } + + private fun isGoodAtBreaking(player: EntityPlayer, pos: BlockPos, state: IBlockState, stack: ItemStack): Boolean = + stack.getDestroySpeed(state) > 1.5f || state.getPlayerRelativeBlockHardness(player, player.world, pos) >= 1f + + private fun isNotTool(stack: ItemStack): Boolean = + stack.isEmpty || stack.getDestroySpeed(Blocks.STONE.defaultState) <= 1f && stack.getDestroySpeed(Blocks.DIRT.defaultState) <= 1f && + stack.getDestroySpeed(Blocks.LOG.defaultState) <= 1f && stack.item !is ItemShears && stack.item !is ItemAxe + + private fun isWeapon(stack: ItemStack, player: EntityPlayer): Boolean = + stack.item is ItemSword || getAttackDamage(stack, player) > getAttackDamage(ItemStack.EMPTY, player) + + private fun getAttackDamage(stack: ItemStack, player: EntityPlayer): Double { + if (stack.isEmpty) { + return player.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).baseValue + } + var damage = 0.0 + stack.getAttributeModifiers(net.minecraft.inventory.EntityEquipmentSlot.MAINHAND).get(SharedMonsterAttributes.ATTACK_DAMAGE.name) + .forEach { damage += it.amount } + return damage + } + + private fun itemWorksOnBlock(world: World, pos: BlockPos, state: IBlockState, player: EntityPlayer, stack: ItemStack): Boolean { + if (stack.item is ItemShears && state.block is IShearable) { + return (state.block as IShearable).isShearable(stack, world, pos) + } + return isGoodAtBreaking(player, pos, state, stack) + } + + private fun itemWorksOnEntity(entity: Entity, stack: ItemStack): Boolean = + stack.item is ItemShears && entity is IShearable && entity.isShearable(stack, entity.world, entity.position) + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setBoolean(SHOULD_SWAP_WEAPON_TAG, shouldSwapWeapon) + nbt.setByte(TOOL_SWAP_MODE_TAG, toolSwapMode.ordinal.toByte()) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + shouldSwapWeapon = !nbt.hasKey(SHOULD_SWAP_WEAPON_TAG) || nbt.getBoolean(SHOULD_SWAP_WEAPON_TAG) + toolSwapMode = ToolSwapMode.entries.getOrElse(nbt.getByte(TOOL_SWAP_MODE_TAG).toInt()) { ToolSwapMode.ANY } + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.TOOL_SWAPPER_UPGRADE_CAPABILITY || + capability == Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) + + fun hasSettingsTab(): Boolean = hasSettingsTab +} + +class AdvancedToolSwapperUpgradeWrapper : ToolSwapperUpgradeWrapper(true, true) { + override val settingsLangKey = "gui.advanced_tool_swapper_settings".asTranslationKey() + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ADVANCED_TOOL_SWAPPER_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} + +enum class ToolSwapMode { + ANY, + ONLY_TOOLS, + NO_SWAP; + + fun next(): ToolSwapMode = + entries[(ordinal + 1) % entries.size] +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeFilterUtils.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeFilterUtils.kt new file mode 100644 index 0000000..56ea6db --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeFilterUtils.kt @@ -0,0 +1,13 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import net.minecraft.item.ItemStack + +object UpgradeFilterUtils { + fun IBasicFilterable.matchesAllowEmpty(stack: ItemStack): Boolean { + if (filterItems.inventory.all(ItemStack::isEmpty)) { + return filterType == IBasicFilterable.FilterType.BLACKLIST + } + + return checkFilter(stack) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeWrapper.kt index 57457a3..d392537 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/UpgradeWrapper.kt @@ -20,6 +20,8 @@ abstract class UpgradeWrapper : INBTSerializable, ISidelessCa abstract val settingsLangKey: String + open fun onBeforeRemoved() {} + override fun serializeNBT(): NBTTagCompound { val nbt = NBTTagCompound() nbt.setBoolean(TAB_STATE_TAG, isTabOpened) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt new file mode 100644 index 0000000..7b1ce1d --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt @@ -0,0 +1,110 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.item.VoidUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability + +class VoidUpgradeWrapper : BasicUpgradeWrapper(), IVoidUpgrade { + companion object { + private const val VOID_TYPE_TAG = "VoidType" + private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" + } + + override val settingsLangKey = "gui.void_settings".asTranslationKey() + var voidType = VoidType.ALWAYS + var shouldWorkInGui = false + + init { + filterType = IBasicFilterable.FilterType.BLACKLIST + } + + override fun shouldVoid(stack: ItemStack): Boolean = + enabled && voidType == VoidType.ALWAYS && matchesAllowEmpty(stack) + + fun toggleWorkInGui() { + shouldWorkInGui = !shouldWorkInGui + } + + fun shouldVoidOverflow(stack: ItemStack, storageFull: Boolean, hasMatchingStack: Boolean): Boolean = + enabled && matchesAllowEmpty(stack) && when (voidType) { + VoidType.ALWAYS -> true + VoidType.SLOT_OVERFLOW -> hasMatchingStack + VoidType.STORAGE_OVERFLOW -> storageFull + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setByte(VOID_TYPE_TAG, voidType.ordinal.toByte()) + nbt.setBoolean(SHOULD_WORK_IN_GUI_TAG, shouldWorkInGui) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + voidType = VoidType.entries.getOrElse(nbt.getByte(VOID_TYPE_TAG).toInt()) { VoidType.ALWAYS } + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.VOID_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} + +class AdvancedVoidUpgradeWrapper : AdvancedUpgradeWrapper(), IVoidUpgrade { + companion object { + private const val VOID_TYPE_TAG = "VoidType" + private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" + } + + override val settingsLangKey = "gui.advanced_void_settings".asTranslationKey() + var voidType = VoidType.ALWAYS + var shouldWorkInGui = false + + init { + filterType = IBasicFilterable.FilterType.BLACKLIST + } + + override fun shouldVoid(stack: ItemStack): Boolean = + enabled && voidType == VoidType.ALWAYS && matchesAllowEmpty(stack) + + fun toggleWorkInGui() { + shouldWorkInGui = !shouldWorkInGui + } + + fun shouldVoidOverflow(stack: ItemStack, storageFull: Boolean, hasMatchingStack: Boolean): Boolean = + enabled && matchesAllowEmpty(stack) && when (voidType) { + VoidType.ALWAYS -> true + VoidType.SLOT_OVERFLOW -> hasMatchingStack + VoidType.STORAGE_OVERFLOW -> storageFull + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setByte(VOID_TYPE_TAG, voidType.ordinal.toByte()) + nbt.setBoolean(SHOULD_WORK_IN_GUI_TAG, shouldWorkInGui) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + voidType = VoidType.entries.getOrElse(nbt.getByte(VOID_TYPE_TAG).toInt()) { VoidType.ALWAYS } + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + } + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.ADVANCED_VOID_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) || + super.hasCapability(capability, facing) +} + +enum class VoidType { + ALWAYS, + SLOT_OVERFLOW, + STORAGE_OVERFLOW; +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackBlockEntityRenderer.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackBlockEntityRenderer.kt new file mode 100644 index 0000000..73ba51c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackBlockEntityRenderer.kt @@ -0,0 +1,46 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client + +import com.cleanroommc.retrosophisticatedbackpacks.block.BackpackBlock +import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer +import net.minecraft.util.EnumFacing +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly + +@SideOnly(Side.CLIENT) +class BackpackBlockEntityRenderer : TileEntitySpecialRenderer() { + override fun render( + te: BackpackTileEntity, + x: Double, + y: Double, + z: Double, + partialTicks: Float, + destroyStage: Int, + alpha: Float + ) { + if (te.wrapper.getDisplayItem() == null) { + return + } + + val state = te.world.getBlockState(te.pos) + if (state.block !is BackpackBlock) { + return + } + + GlStateManager.pushMatrix() + GlStateManager.translate(x + 0.5, y, z + 0.5) + GlStateManager.rotate(facingRotation(state.getValue(BackpackBlock.FACING)), 0f, 1f, 0f) + BackpackDisplayItemRenderer.render(te.wrapper) + GlStateManager.popMatrix() + } + + private fun facingRotation(facing: EnumFacing): Float = + when (facing) { + EnumFacing.NORTH -> 180f + EnumFacing.SOUTH -> 0f + EnumFacing.WEST -> 90f + EnumFacing.EAST -> -90f + else -> 0f + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDisplayItemRenderer.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDisplayItemRenderer.kt new file mode 100644 index 0000000..fa91367 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDisplayItemRenderer.kt @@ -0,0 +1,77 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client + +import com.cleanroommc.retrosophisticatedbackpacks.backpack.DisplaySide +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.client.renderer.block.model.ItemCameraTransforms +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly +import org.lwjgl.opengl.GL11 + +@SideOnly(Side.CLIENT) +object BackpackDisplayItemRenderer { + private const val MODEL_CENTER = 0.5 + private const val CENTER_Y = 0.6 + private const val FRONT_Z = -0.314 + private const val SIDE_X = 0.455 + private const val SCALE = 0.5f + + fun render( + wrapper: BackpackWrapper, + modelScale: Double = 1.0, + itemScale: Float = 1.0f, + originAtCenter: Boolean = true + ) { + val displayItem = wrapper.getDisplayItem() ?: return + + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + GlStateManager.pushMatrix() + try { + applySideTransform(displayItem.side, modelScale, originAtCenter) + GlStateManager.rotate(displayItem.rotation.toFloat(), 0f, 0f, 1f) + val scale = SCALE * itemScale + GlStateManager.scale(scale, scale, scale) + GlStateManager.color(1f, 1f, 1f, 1f) + GlStateManager.enableRescaleNormal() + GlStateManager.enableDepth() + GlStateManager.enableBlend() + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA) + RenderHelper.enableStandardItemLighting() + Minecraft.getMinecraft().renderItem.renderItem(displayItem.stack, ItemCameraTransforms.TransformType.FIXED) + } finally { + RenderHelper.disableStandardItemLighting() + GlStateManager.disableRescaleNormal() + GlStateManager.color(1f, 1f, 1f, 1f) + GlStateManager.popMatrix() + GL11.glPopAttrib() + RenderStateHelper.syncGlStateManagerCache() + } + } + + private fun applySideTransform(side: DisplaySide, modelScale: Double, originAtCenter: Boolean) { + val invScale = 1.0 / modelScale + fun x(relative: Double) = + if (originAtCenter) relative * invScale else MODEL_CENTER + relative * invScale + + fun z(relative: Double) = + if (originAtCenter) relative * invScale else MODEL_CENTER + relative * invScale + + when (side) { + DisplaySide.FRONT -> { + GlStateManager.translate(x(0.0), CENTER_Y * invScale, z(FRONT_Z)) + } + + DisplaySide.LEFT -> { + GlStateManager.translate(x(SIDE_X), CENTER_Y * invScale, z(0.0)) + GlStateManager.rotate(-90f, 0f, 1f, 0f) + } + + DisplaySide.RIGHT -> { + GlStateManager.translate(x(-SIDE_X), CENTER_Y * invScale, z(0.0)) + GlStateManager.rotate(90f, 0f, 1f, 0f) + } + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDynamicModel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDynamicModel.kt index 98530fa..4581e59 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDynamicModel.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackDynamicModel.kt @@ -4,6 +4,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.Tags import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackTier import com.cleanroommc.retrosophisticatedbackpacks.block.BackpackBlock import com.cleanroommc.retrosophisticatedbackpacks.block.Blocks +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.google.common.collect.ImmutableMap import net.minecraft.block.state.IBlockState import net.minecraft.client.renderer.block.model.* @@ -32,7 +33,7 @@ class BackpackDynamicModel private constructor( ) : IModel { companion object { private val BACKPACK_MODELS_RESOURCE_LOCATION = ModelPart.entries.filter { - it == ModelPart.BASE || it.name.endsWith("POUCH") + it == ModelPart.BASE || it.name.endsWith("POUCH") || it.name.endsWith("TANK") }.associateBy({ it }, { val path = "block/backpack_${it.name.lowercase(Locale.ENGLISH)}" @@ -41,6 +42,7 @@ class BackpackDynamicModel private constructor( private val BACKPACK_CLOTH_RESOURCE_LOCATION = ResourceLocation(Tags.MOD_ID, "block/backpack_cloth") private val BACKPACK_BORDER_RESOURCE_LOCATION = ResourceLocation(Tags.MOD_ID, "block/backpack_border") + private val BACKPACK_MODULES_RESOURCE_LOCATION = ResourceLocation(Tags.MOD_ID, "block/backpack_modules") private val BACKPACK_CLIP_RESOURCE_LOCATIONS = BackpackTier.entries.associateBy( { it }, { ResourceLocation(Tags.MOD_ID, "block/${it.registryName}_clips") } @@ -48,6 +50,7 @@ class BackpackDynamicModel private constructor( private val BACKPACK_TEXTURE_RESOURCE_LOCATIONS = listOf( BACKPACK_CLOTH_RESOURCE_LOCATION, BACKPACK_BORDER_RESOURCE_LOCATION, + BACKPACK_MODULES_RESOURCE_LOCATION, *BACKPACK_CLIP_RESOURCE_LOCATIONS.values.toTypedArray() ) } @@ -125,6 +128,12 @@ class BackpackDynamicModel private constructor( ret.addAll(models[ModelPart.FRONT_POUCH]!!.getQuads(state, side, rand)) ret.addAll(models[ModelPart.LEFT_POUCH]!!.getQuads(state, side, rand)) ret.addAll(models[ModelPart.RIGHT_POUCH]!!.getQuads(state, side, rand)) + if (state?.getValue(BackpackBlock.LEFT_TANK) ?: tankLeft) { + ret.addAll(models[ModelPart.LEFT_TANK]!!.getQuads(state, side, rand)) + } + if (state?.getValue(BackpackBlock.RIGHT_TANK) ?: tankRight) { + ret.addAll(models[ModelPart.RIGHT_TANK]!!.getQuads(state, side, rand)) + } if (state != null) { val facing = state.getValue(BackpackBlock.FACING) @@ -142,7 +151,7 @@ class BackpackDynamicModel private constructor( true override fun isBuiltInRenderer(): Boolean = - false + true override fun getParticleTexture(): TextureAtlasSprite = models[ModelPart.BASE]!!.particleTexture @@ -164,6 +173,11 @@ class BackpackDynamicModel private constructor( backpackModel.tankLeft = false backpackModel.tankRight = false backpackModel.battery = false + stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null)?.let { + val (left, right) = it.tankRenderSides() + backpackModel.tankLeft = left + backpackModel.tankRight = right + } return backpackModel } @@ -196,4 +210,4 @@ class BackpackDynamicModel private constructor( RIGHT_POUCH, RIGHT_TANK, } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackItemStackRenderer.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackItemStackRenderer.kt index bd9dac4..b1fa3fe 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackItemStackRenderer.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/BackpackItemStackRenderer.kt @@ -1,5 +1,6 @@ package com.cleanroommc.retrosophisticatedbackpacks.client +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import net.minecraft.client.Minecraft import net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer import net.minecraft.item.ItemStack @@ -11,9 +12,12 @@ class BackpackItemStackRenderer : TileEntityItemStackRenderer() { private val mc = Minecraft.getMinecraft() override fun renderByItem(itemStackIn: ItemStack, partialTicks: Float) { - mc.itemRenderer val model = mc.renderItem.getItemModelWithOverrides(itemStackIn, null, null) - mc.renderItem.renderItem(itemStackIn, model) + mc.renderItem.renderModel(model, itemStackIn) + + itemStackIn.getCapability(Capabilities.BACKPACK_CAPABILITY, null)?.let { + BackpackDisplayItemRenderer.render(it, itemScale = 0.7f, originAtCenter = false) + } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt index 45cd0b3..f3f20a6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt @@ -1,9 +1,8 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui -import com.cleanroommc.modularui.api.IPanelHandler +import com.cleanroommc.modularui.api.drawable.IDrawable import com.cleanroommc.modularui.api.drawable.IKey import com.cleanroommc.modularui.api.widget.Interactable -import com.cleanroommc.modularui.drawable.AdaptableUITexture import com.cleanroommc.modularui.drawable.ItemDrawable import com.cleanroommc.modularui.drawable.UITexture import com.cleanroommc.modularui.drawable.text.StringKey @@ -11,6 +10,7 @@ import com.cleanroommc.modularui.screen.ModularPanel import com.cleanroommc.modularui.screen.RichTooltip import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetTheme +import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.value.sync.PanelSyncManager import com.cleanroommc.modularui.widgets.ButtonWidget import com.cleanroommc.modularui.widgets.SlotGroupWidget @@ -24,7 +24,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.* import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.* -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.BackpackSlot +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade.* import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData @@ -40,6 +40,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.ceilDiv +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.setEnabledIfAndEnabled import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.Loader @@ -51,17 +52,17 @@ class BackpackPanel( internal val player: EntityPlayer, internal val tileEntity: BackpackTileEntity?, internal val syncManager: PanelSyncManager, - internal val backpackWrapper: BackpackWrapper + internal val backpackWrapper: BackpackWrapper, + private val openedBackpackSlotIndex: Int? = null ) : ModularPanel("backpack_gui") { companion object { private const val SLOT_SIZE = 18 - private val LAYERED_TAB_TEXTURE = UITexture.builder() - .location(Tags.MOD_ID, "gui/gui_controls") - .imageSize(256, 256) - .xy(132, 0, 124, 256) - .adaptable(4) - .tiled() - .build() as AdaptableUITexture + private const val HEIGHT_WITHOUT_STORAGE_SLOTS = 114 + private const val STORAGE_INVENTORY_X = 7 + private const val STORAGE_INVENTORY_Y = 17 + internal const val VISIBLE_BACKPACK_ROWS = 5 + internal const val PLAYER_INVENTORY_BOTTOM = 8 + internal const val INVENTORY_CONTROL_COLUMNS = 2 private val SORT_TYPE_VARIANTS = listOf( CyclicVariantButtonWidget.Variant( IKey.lang("gui.sort_by_name".asTranslationKey()), @@ -90,34 +91,195 @@ class BackpackPanel( height: Int, backpackSlotIndex: Int? = null, ): BackpackPanel { - val panel = - BackpackPanel(player, tileEntity, syncManager, wrapper) - .size(width, height) as BackpackPanel + val panel = BackpackPanel(player, tileEntity, syncManager, wrapper, backpackSlotIndex) + panel.background(IDrawable.EMPTY) syncManager.bindPlayerInventory(player) - panel.bindPlayerInventory() + panel.recalculateLayout() + panel.size(panel.panelWidth, panel.panelHeight) return panel } } val upgradeSlotWidgets = mutableListOf() - val upgradeSlotGroupWidget = UpgradeSlotGroupWidget(this, backpackWrapper.upgradeSlotsSize()) + var upgradeSlotGroupWidget = UpgradeSlotGroupWidget(this, backpackWrapper.upgradeSlotsSize()) + private set val tabWidgets = mutableListOf() - val rowSize = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 - val colSize = backpackWrapper.backpackInventorySize().ceilDiv(rowSize) - - val backpackSyncHandler: BackpackSH = BackpackSH(PlayerMainInvWrapper(player.inventory), backpackWrapper) + var tankInventoryControlCount = 0 + private set + var batteryInventoryControlCount = 0 + private set + var inventoryColumnsTaken = 0 + private set + var backgroundRowSize = 0 + private set + var rowSize = 0 + private set + var colSize = 0 + private set + var visibleColSize = 0 + private set + var backpackSlotsWidth = 0 + private set + var inventoryScrollbarWidth = 0 + private set + var inventoryAreaWidth = 0 + private set + var storageInventoryHeight = 0 + private set + private var playerInventoryXOffset = 0 + private var storageBackgroundTexture: UITexture = RSBTextures.STORAGE_BACKGROUND_9 + val playerInventoryLabelX: Int + get() = 8 + playerInventoryXOffset + val playerInventoryLabelY: Int + get() = area.height - 94 + val panelWidth: Int + get() = 14 + backgroundRowSize * SLOT_SIZE + inventoryScrollbarWidth + val panelHeight: Int + get() = HEIGHT_WITHOUT_STORAGE_SLOTS + visibleColSize * SLOT_SIZE + + val backpackSyncHandler: BackpackSH = BackpackSH(PlayerMainInvWrapper(player.inventory), backpackWrapper, tileEntity) val backpackSlotSyncHandlers: Array val upgradeSlotSyncHandlers: Array val upgradeSlotGroups: Array - val settingPanel: IPanelHandler var isMemorySettingTabOpened: Boolean = false var shouldMemorizeRespectNBT: Boolean = false var isSortingSettingTabOpened: Boolean = false + var isBackpackSettingTabOpened: Boolean = false + var isItemDisplaySettingTabOpened: Boolean = false + var currentItemDisplaySelectedSlot: Int = -1 + private set + private lateinit var backpackSettingTabWidget: TabWidget + private lateinit var memorySettingTabWidget: TabWidget + private lateinit var sortingSettingTabWidget: TabWidget + private lateinit var itemDisplaySettingTabWidget: TabWidget + private var rebuildWidgetsQueued = false + private var lastUpgradeStructureSignature = emptyList() + private var reopenBackpackQueued = false + var isSettingMode: Boolean = false + set(value) { + if (field == value) + return + + field = value + if (value) { + resetTabState() + closeUpgradeTabs(syncToServer = true) + tabWidgets.forEach { it.isEnabled = false } + closeSettingTabs() + } else { + closeSettingTabs() + updateUpgradeWidgets() + } + scheduleResize() + } + + override fun onUpdate() { + super.onUpdate() + if (!rebuildWidgetsQueued) + queueRebuildIfUpgradeStructureChanged() + if (reopenBackpackQueued) { + reopenBackpackQueued = false + rebuildWidgetsQueued = false + upgradeSlotSyncHandlers.firstOrNull()?.syncToServer(UpgradeSlotSH.UPDATE_REOPEN_BACKPACK) {} + return + } + if (rebuildWidgetsQueued) { + rebuildWidgetsQueued = false + rebuildWidgets() + } + } + + fun refreshUpgradeWidgetsAfterSlotChange() { + if (!isValid) + return + + if (!queueRebuildIfUpgradeStructureChanged() && !rebuildWidgetsQueued) + updateUpgradeWidgets() + } + + private fun queueRebuildIfUpgradeStructureChanged(): Boolean { + if (!isValid) + return false + + val signature = upgradeStructureSignature() + if (signature == lastUpgradeStructureSignature) + return false + + lastUpgradeStructureSignature = signature + rebuildWidgetsQueued = true + if (syncManager.isClient && lastUpgradeStructureSignature.isNotEmpty()) + reopenBackpackQueued = true + return true + } + + fun rebuildWidgets() { + rebuildWidgetsQueued = false + reopenBackpackQueued = false + if (isValid) { + removeAll() + } + + recalculateLayout() + size(panelWidth, panelHeight) + upgradeSlotWidgets.clear() + tabWidgets.clear() + upgradeSlotGroupWidget = UpgradeSlotGroupWidget(this, backpackWrapper.upgradeSlotsSize()) + currentItemDisplaySelectedSlot = -1 + + addPlayerInventoryWidgets() + addSortingButtons() + addTransferButtons() + addBackpackInventorySlots() + addUpgradeSlots() + addSettingTab() + addUpgradeTabs() + addTexts(player) + closeSettingTabs() + lastUpgradeStructureSignature = upgradeStructureSignature() + updateUpgradeWidgets() + scheduleResize() + } + + private fun upgradeStructureSignature(): List = + (0 until backpackWrapper.upgradeSlotsSize()).map { slotIndex -> + val stack = backpackWrapper.upgradeItemStackHandler.getStackInSlot(slotIndex) + if (stack.isEmpty) "empty" + else stack.item.registryName?.toString() ?: stack.item.javaClass.name + } + + private fun recalculateLayout() { + tankInventoryControlCount = min(backpackWrapper.tankUpgradeSlots().size, 2) + batteryInventoryControlCount = min(backpackWrapper.batteryUpgradeSlots().size, 1) + inventoryColumnsTaken = (tankInventoryControlCount + batteryInventoryControlCount) * INVENTORY_CONTROL_COLUMNS + backgroundRowSize = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 + rowSize = (backgroundRowSize - inventoryColumnsTaken).coerceAtLeast(1) + colSize = backpackWrapper.backpackInventorySize().ceilDiv(rowSize) + visibleColSize = min(colSize, VISIBLE_BACKPACK_ROWS) + backpackSlotsWidth = rowSize * SLOT_SIZE + inventoryScrollbarWidth = if (colSize > visibleColSize) BackpackInventoryScrollWidget.SCROLLBAR_WIDTH else 0 + inventoryAreaWidth = backgroundRowSize * SLOT_SIZE + inventoryScrollbarWidth + storageInventoryHeight = visibleColSize * SLOT_SIZE + playerInventoryXOffset = + when { + backgroundRowSize > 9 && inventoryScrollbarWidth > 0 -> 30 + backgroundRowSize > 9 -> 27 + inventoryScrollbarWidth > 0 -> 3 + else -> 0 + } + storageBackgroundTexture = + when { + backgroundRowSize > 9 && inventoryScrollbarWidth > 0 -> RSBTextures.STORAGE_BACKGROUND_12_WIDER + backgroundRowSize > 9 -> RSBTextures.STORAGE_BACKGROUND_12 + inventoryScrollbarWidth > 0 -> RSBTextures.STORAGE_BACKGROUND_9_WIDER + else -> RSBTextures.STORAGE_BACKGROUND_9 + } + } init { + recalculateLayout() syncManager.syncValue("backpack_wrapper", backpackSyncHandler) // Backpack slots @@ -138,11 +300,12 @@ class BackpackPanel( backpackWrapper, it ).slotGroup("upgrade_inventory") - val syncHandler = UpgradeSlotSH(upgradeSlot) - val index = it - upgradeSlot.changeListener { lastStack, _, isClient, init -> + val syncHandler = UpgradeSlotSH(upgradeSlot) { + refreshUpgradeWidgetsAfterSlotChange() + } + upgradeSlot.changeListener { _, _, isClient, _ -> if (isClient) - updateUpgradeWidgets(index, lastStack) + refreshUpgradeWidgetsAfterSlotChange() } syncManager.syncValue("upgrades", it, syncHandler) @@ -156,15 +319,17 @@ class BackpackPanel( UpgradeSlotUpdateGroup(this, backpackWrapper, it) } - settingPanel = syncManager.syncedPanel("setting_panel", true) { syncManager, syncHandler -> - BackpackSettingPanel(this) - } } fun getBackpackContainer(): BackpackContainer { return syncManager.container as BackpackContainer } + override fun onInit() { + super.onInit() + updateUpgradeWidgets() + } + // Currently only main hand slot will be locked if it's the backpack being opened internal fun modifyPlayerSlot( syncManager: PanelSyncManager, @@ -201,7 +366,7 @@ class BackpackPanel( } } .setEnabledIf { - !settingPanel.isPanelOpen + !isSettingMode } .top(4) .right(rightAnchor) @@ -212,7 +377,7 @@ class BackpackPanel( .size(12) .overlay(RSBTextures.SOLID_UP_ARROW_ICON) .setEnabledIf { - !settingPanel.isPanelOpen + !isSettingMode } .onMousePressed { mouseButton -> if (mouseButton == 0) { @@ -236,18 +401,15 @@ class BackpackPanel( } internal fun addTransferButtons() { - val rightAnchor = if (Loader.isModLoaded("bogosorter")) { - if (backpackWrapper.backpackInventorySize() > 81) 57 - else 30 - } else 7 + val transferButtonsShiftX = if (Loader.isModLoaded("bogosorter")) -23 else 0 val transferToBackpackButton = TransferButtonWidget(RSBTextures.DOT_UP_ARROW_ICON, RSBTextures.SOLID_UP_ARROW_ICON) - .top(17 + colSize * 18) - .right(rightAnchor) + .top(playerInventoryLabelY - 2) + .left(playerInventoryLabelX + 137 + transferButtonsShiftX) .size(12) .setEnabledIf { - !settingPanel.isPanelOpen + !isSettingMode } .onMousePressed { mouseButton -> if (mouseButton == 0) { @@ -276,11 +438,11 @@ class BackpackPanel( } val transferToPlayerButton = TransferButtonWidget(RSBTextures.DOT_DOWN_ARROW_ICON, RSBTextures.SOLID_DOWN_ARROW_ICON) - .top(17 + colSize * 18) - .right(rightAnchor + 14) + .top(playerInventoryLabelY - 2) + .left(playerInventoryLabelX + 149 + transferButtonsShiftX) .size(12) .setEnabledIf { - !settingPanel.isPanelOpen + !isSettingMode } .onMousePressed { mouseButton -> if (mouseButton == 0) { @@ -312,28 +474,71 @@ class BackpackPanel( .child(transferToBackpackButton) } + internal fun addPlayerInventoryWidgets() { + child( + SlotGroupWidget.playerInventory(PLAYER_INVENTORY_BOTTOM - 1, false) { _, _ -> + NoBackgroundItemSlot() + } + .left(playerInventoryLabelX - 1) + ) + } + internal fun addBackpackInventorySlots() { - val backpackSlotGroupWidget = SlotGroupWidget().name("backpack_inventory") - backpackSlotGroupWidget.coverChildren().leftRel(0.5F).top(17) + val inventoryArea = SlotGroupWidget().disableSortButtons() + .size(inventoryAreaWidth, storageInventoryHeight) + .pos(STORAGE_INVENTORY_X, STORAGE_INVENTORY_Y) + + inventoryArea.child( + if (inventoryScrollbarWidth > 0) BackpackInventoryScrollWidget(this).pos(0, 0) + else BackpackInventoryScrollWidget.createSlots(this, visibleColSize).pos(0, 0) + ) - for (i in 0 until backpackWrapper.backpackInventorySize()) { - val itemSlot = BackpackSlot(this, backpackWrapper) - .syncHandler("backpack", i) - .pos(i % rowSize * SLOT_SIZE, i / rowSize * SLOT_SIZE) - .name("slot_${i}") + val tankSlots = backpackWrapper.tankUpgradeSlots().take(tankInventoryControlCount) + var controlIndex = 0 + for ((index, slot) in tankSlots.withIndex()) { + if (backpackWrapper.upgradeItemStackHandler.inventory[slot] + .getCapability(Capabilities.TANK_UPGRADE_CAPABILITY, null) == null + ) continue + inventoryArea.child( + TankInventoryControlWidget( + upgradeSlotSyncHandlers[slot], + slot, + backpackWrapper, + storageInventoryHeight + ) + .pos(backpackSlotsWidth + inventoryScrollbarWidth + controlIndex * TankInventoryControlWidget.WIDTH, 0) + .name("tank_inventory_control_$slot") + ) + controlIndex++ + } - backpackSlotGroupWidget.child(itemSlot) + val batterySlots = backpackWrapper.batteryUpgradeSlots().take(batteryInventoryControlCount) + for (slot in batterySlots) { + if (backpackWrapper.upgradeItemStackHandler.inventory[slot] + .getCapability(Capabilities.BATTERY_UPGRADE_CAPABILITY, null) == null + ) continue + inventoryArea.child( + BatteryInventoryControlWidget( + slot, + backpackWrapper, + storageInventoryHeight + ) + .pos(backpackSlotsWidth + inventoryScrollbarWidth + controlIndex * BatteryInventoryControlWidget.WIDTH, 0) + .name("battery_inventory_control_$slot") + ) + controlIndex++ } - child(backpackSlotGroupWidget) + child(inventoryArea) } internal fun addUpgradeSlots() { upgradeSlotGroupWidget.name("upgrade_inventory") - upgradeSlotGroupWidget.size(23, 10 + backpackWrapper.upgradeSlotsSize() * 18).left(-21) + upgradeSlotGroupWidget.size(25, 13 + backpackWrapper.upgradeSlotsSize() * 16).left(-21) + upgradeSlotGroupWidget.setEnabledIf { !isSettingMode } for (i in 0 until backpackWrapper.upgradeSlotsSize()) { - val itemSlot = ItemSlot().syncHandler("upgrades", i).pos(5, 5 + i * 18).name("slot_${i}") + val itemSlot = NoBackgroundItemSlot().syncHandler("upgrades", i).pos(5, 5 + i * 16).name("slot_${i}") upgradeSlotWidgets.add(itemSlot) upgradeSlotGroupWidget.child(itemSlot) @@ -343,7 +548,76 @@ class BackpackPanel( } internal fun addSettingTab() { - child(SettingTabWidget()) + val backToBackpackTab = BackToBackpackTabWidget() + .setEnabledIfAndEnabled({ isSettingMode }, false) + + backpackSettingTabWidget = TabWidget(1).name("backpack_setting_tab") + backpackSettingTabWidget.isEnabled = false + backpackSettingTabWidget.expandedWidget = BackpackMainSettingsWidget(this, backpackSettingTabWidget) + backpackSettingTabWidget.tabIcon = RSBTextures.BACKPACK_SETTINGS_ICON + backpackSettingTabWidget.tooltipDynamic { + it.clearText() + .addLine(IKey.lang("gui.backpack_settings.tooltip".asTranslationKey())) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + sortingSettingTabWidget = TabWidget(2).name("sorting_setting_tab") + sortingSettingTabWidget.isEnabled = false + sortingSettingTabWidget.expandedWidget = SortingSettingWidget(this, sortingSettingTabWidget) + sortingSettingTabWidget.tabIcon = RSBTextures.NO_SORT_ICON + sortingSettingTabWidget.tooltipDynamic { + it.clearText() + .addLine(IKey.lang("gui.sorting_settings.tooltip".asTranslationKey())) + .addLine( + IKey.lang( + if (sortingSettingTabWidget.showExpanded) + "gui.sorting_settings.tooltip_open_detail".asTranslationKey() + else "gui.sorting_settings.tooltip_detail".asTranslationKey() + ).style(IKey.GRAY) + ) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + memorySettingTabWidget = TabWidget(3).name("memory_setting_tab") + memorySettingTabWidget.isEnabled = false + memorySettingTabWidget.expandedWidget = MemorySettingWidget(this, memorySettingTabWidget) + memorySettingTabWidget.tabIcon = RSBTextures.BRAIN_ICON + memorySettingTabWidget.tooltipDynamic { + it.clearText() + .addLine(IKey.lang("gui.memory_settings.tooltip".asTranslationKey())) + .addLine( + IKey.lang( + if (memorySettingTabWidget.showExpanded) + "gui.memory_settings.tooltip_open_detail".asTranslationKey() + else "gui.memory_settings.tooltip_detail".asTranslationKey() + ).style(IKey.GRAY) + ) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + itemDisplaySettingTabWidget = TabWidget(4).name("item_display_setting_tab") + itemDisplaySettingTabWidget.isEnabled = false + itemDisplaySettingTabWidget.expandedWidget = ItemDisplaySettingsWidget(this, itemDisplaySettingTabWidget) + itemDisplaySettingTabWidget.tabIcon = RSBTextures.ITEM_DISPLAY_SETTINGS_ICON + itemDisplaySettingTabWidget.tooltipDynamic { + it.clearText() + .addLine(IKey.lang("gui.item_display_settings.tooltip".asTranslationKey())) + .addLine( + IKey.lang( + if (itemDisplaySettingTabWidget.showExpanded) + "gui.item_display_settings.tooltip_open_detail".asTranslationKey() + else "gui.item_display_settings.tooltip_detail".asTranslationKey() + ).style(IKey.GRAY) + ) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + child(SettingTabWidget().setEnabledIf { !isSettingMode }) + .child(itemDisplaySettingTabWidget) + .child(memorySettingTabWidget) + .child(sortingSettingTabWidget) + .child(backpackSettingTabWidget) + .child(backToBackpackTab) } internal fun addUpgradeTabs() { @@ -362,15 +636,143 @@ class BackpackPanel( internal fun addTexts(player: EntityPlayer) { // TODO: Delegates to itemstack or tileentity's display name - child(TextWidget(StringKey(backpackWrapper.getDisplayName().formattedText)).pos(8, 6)) - child(TextWidget(StringKey(player.inventory.displayName.formattedText)).pos(8, 18 + colSize * 18)) + val titleWidget = TextWidget(StringKey(backpackWrapper.getDisplayName().formattedText)) + .pos(8, 6) + .setEnabledIf { !isSettingMode } + val settingsTitleWidget = IKey.lang("gui.settings".asTranslationKey()).asWidget() + .pos(8, 6) + .setEnabledIf { isSettingMode } + settingsTitleWidget.isEnabled = false + child(titleWidget) + child(settingsTitleWidget) + child(TextWidget(StringKey(player.inventory.displayName.formattedText)).pos(playerInventoryLabelX, playerInventoryLabelY)) + } + + fun openMemorySettings(tabWidget: TabWidget, open: Boolean) { + if (!isSettingMode) + return + + memorySettingTabWidget.showExpanded = open + isMemorySettingTabOpened = open + shouldMemorizeRespectNBT = + open && (memorySettingTabWidget.expandedWidget as? MemorySettingWidget)?.isRespectNBT() == true + + if (open) + closeOtherSettingTabs(memorySettingTabWidget) + updateSettingTabEnabledStates(memorySettingTabWidget, open) + } + + fun openSortingSettings(tabWidget: TabWidget, open: Boolean) { + if (!isSettingMode) + return + + sortingSettingTabWidget.showExpanded = open + isSortingSettingTabOpened = open + + if (open) + closeOtherSettingTabs(sortingSettingTabWidget) + updateSettingTabEnabledStates(sortingSettingTabWidget, open) + } + + fun openBackpackSettings(tabWidget: TabWidget, open: Boolean) { + if (!isSettingMode) + return + + backpackSettingTabWidget.showExpanded = open + isBackpackSettingTabOpened = open + + if (open) + closeOtherSettingTabs(backpackSettingTabWidget) + updateSettingTabEnabledStates(backpackSettingTabWidget, open) + } + + fun openItemDisplaySettings(tabWidget: TabWidget, open: Boolean) { + if (!isSettingMode) + return + + itemDisplaySettingTabWidget.showExpanded = open + isItemDisplaySettingTabOpened = open + currentItemDisplaySelectedSlot = if (open) backpackWrapper.getFirstItemDisplaySlot() else -1 + + if (open) + closeOtherSettingTabs(itemDisplaySettingTabWidget) + updateSettingTabEnabledStates(itemDisplaySettingTabWidget, open) + } + + fun setCurrentItemDisplaySelectedSlot(slotIndex: Int) { + currentItemDisplaySelectedSlot = slotIndex + } + + private fun closeSettingTabs() { + if (!this::memorySettingTabWidget.isInitialized || !this::sortingSettingTabWidget.isInitialized || + !this::backpackSettingTabWidget.isInitialized || !this::itemDisplaySettingTabWidget.isInitialized) + return + + backpackSettingTabWidget.showExpanded = false + memorySettingTabWidget.showExpanded = false + sortingSettingTabWidget.showExpanded = false + itemDisplaySettingTabWidget.showExpanded = false + backpackSettingTabWidget.isEnabled = isSettingMode + memorySettingTabWidget.isEnabled = isSettingMode + sortingSettingTabWidget.isEnabled = isSettingMode + itemDisplaySettingTabWidget.isEnabled = isSettingMode + isBackpackSettingTabOpened = false + isMemorySettingTabOpened = false + shouldMemorizeRespectNBT = false + isSortingSettingTabOpened = false + isItemDisplaySettingTabOpened = false + currentItemDisplaySelectedSlot = -1 + } + + private fun closeOtherSettingTabs(openTab: TabWidget) { + if (openTab != backpackSettingTabWidget) { + backpackSettingTabWidget.showExpanded = false + isBackpackSettingTabOpened = false + } + if (openTab != sortingSettingTabWidget) { + sortingSettingTabWidget.showExpanded = false + isSortingSettingTabOpened = false + } + if (openTab != memorySettingTabWidget) { + memorySettingTabWidget.showExpanded = false + isMemorySettingTabOpened = false + shouldMemorizeRespectNBT = false + } + if (openTab != itemDisplaySettingTabWidget) { + itemDisplaySettingTabWidget.showExpanded = false + isItemDisplaySettingTabOpened = false + currentItemDisplaySelectedSlot = -1 + } + } + + private fun updateSettingTabEnabledStates(openTab: TabWidget, open: Boolean) { + listOf(backpackSettingTabWidget, sortingSettingTabWidget, memorySettingTabWidget, itemDisplaySettingTabWidget) + .forEach { it.isEnabled = !open || it == openTab } + } + + private fun closeUpgradeTabs(syncToServer: Boolean) { + for (slotIndex in 0 until backpackWrapper.upgradeSlotsSize()) { + val wrapper = backpackWrapper.upgradeItemStackHandler.getStackInSlot(slotIndex) + .getCapability(Capabilities.UPGRADE_CAPABILITY, null) ?: continue + + if (!wrapper.isTabOpened) + continue + + wrapper.isTabOpened = false + tabWidgets.getOrNull(slotIndex)?.showExpanded = false + if (syncToServer) { + upgradeSlotSyncHandlers[slotIndex].syncToServer(UpgradeSlotSH.UPDATE_UPGRADE_TAB_STATE) { + it.writeBoolean(false) + } + } + } } private inline fun , reified U : UpgradeWrapper<*>> updateAndCheckRecreation( widget: ExpandedTabWidget?, wrapper: U ): Boolean { - if (widget is V) { + if (widget is V && widget::class == V::class && widget.wrapper::class == wrapper::class) { widget.wrapper = wrapper return false } @@ -381,21 +783,41 @@ class BackpackPanel( widget: ExpandedTabWidget?, wrapper: Any ): Boolean { - if (widget is V) { + if (widget is V && widget::class == V::class) { return !widget.consumePossibleWrapper(wrapper) } return true } + private fun clearUpgradeTab(tabWidget: TabWidget) { + tabWidget.showExpanded = false + tabWidget.isEnabled = false + tabWidget.expandedWidget = null + tabWidget.tabIcon = null + tabWidget.tooltip().reset() + } + + + private fun updateUpgradeWidgets() { + if (!isValid) + return + + if (isSettingMode) { + tabWidgets.forEach { + clearUpgradeTab(it) + } + syncToggles() + scheduleResize() + return + } - private fun updateUpgradeWidgets(index: Int?, lastStack: ItemStack?) { var tabIndex = 0 var openedTabIndex: Int? = null resetTabState() - for ((slotIndex, slotWidget) in upgradeSlotWidgets.withIndex()) { - val stack: ItemStack = slotWidget.slot.stack + for (slotIndex in 0 until backpackWrapper.upgradeSlotsSize()) { + val stack: ItemStack = backpackWrapper.upgradeItemStackHandler.getStackInSlot(slotIndex) val item = stack.item if (!(item is UpgradeItem && item.hasTab)) @@ -409,8 +831,7 @@ class BackpackPanel( upgradeSlotSyncHandlers[slotIndex].syncToServer(UpgradeSlotSH.UPDATE_UPGRADE_TAB_STATE) { it.writeBoolean(false) } - - return + continue } openedTabIndex = slotIndex @@ -421,26 +842,28 @@ class BackpackPanel( // Sync all tabs to their corresponding upgrade for (slotIndex in 0 until backpackWrapper.upgradeSlotsSize()) { - val slot = upgradeSlotWidgets[slotIndex] - val stack: ItemStack = slot.slot.stack + val stack: ItemStack = backpackWrapper.upgradeItemStackHandler.getStackInSlot(slotIndex) val item = stack.item val tabWidget = tabWidgets[tabIndex] if (!(item is UpgradeItem && item.hasTab)) { - tabWidget.isEnabled = false - tabWidget.expandedWidget = null + clearUpgradeTab(tabWidget) tabIndex++ continue } val upgradeSlotGroup = upgradeSlotGroups[slotIndex] - val wrapper: UpgradeWrapper<*> = stack.getCapability(Capabilities.UPGRADE_CAPABILITY, null) ?: continue + val wrapper: UpgradeWrapper<*> = stack.getCapability(Capabilities.UPGRADE_CAPABILITY, null) ?: run { + clearUpgradeTab(tabWidget) + tabIndex++ + continue + } tabWidget.showExpanded = wrapper.isTabOpened tabWidget.isEnabled = true // Ensure correct tab position tabWidget.tabOrder = tabDisplayIndex - tabWidget.tabIcon = ItemDrawable(slot.slot.stack) + tabWidget.tabIcon = ItemDrawable(stack) tabWidget.tooltip { it.clearText() .addLine(IKey.str(item.getItemStackDisplayName(stack))) @@ -498,6 +921,144 @@ class BackpackPanel( tabWidget.expandedWidget = FilterUpgradeWidget(slotIndex, wrapper) } + is AdvancedVoidUpgradeWrapper -> { + upgradeSlotGroup.updateAdvancedFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = AdvancedVoidUpgradeWidget(slotIndex, wrapper, stack) + } + + is VoidUpgradeWrapper -> { + upgradeSlotGroup.updateFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = VoidUpgradeWidget(slotIndex, wrapper, stack) + } + + is AdvancedRefillUpgradeWrapper -> { + upgradeSlotGroup.updateFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = AdvancedRefillUpgradeWidget(slotIndex, wrapper, stack) + } + + is RefillUpgradeWrapper -> { + upgradeSlotGroup.updateFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = RefillUpgradeWidget(slotIndex, wrapper, stack) + } + + is AdvancedCompactingUpgradeWrapper -> { + upgradeSlotGroup.updateAdvancedFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = AdvancedCompactingUpgradeWidget(slotIndex, wrapper, stack) + } + + is CompactingUpgradeWrapper -> { + upgradeSlotGroup.updateFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = CompactingUpgradeWidget(slotIndex, wrapper, stack) + } + + is AdvancedJukeboxUpgradeWrapper -> { + upgradeSlotGroup.updateJukeboxDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, 12) + } + + is JukeboxUpgradeWrapper -> { + upgradeSlotGroup.updateJukeboxDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, 1) + } + + is AdvancedToolSwapperUpgradeWrapper -> { + upgradeSlotGroup.updateFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = AdvancedToolSwapperUpgradeWidget(slotIndex, wrapper, stack) + } + + is TankUpgradeWrapper -> { + upgradeSlotGroup.updateTankDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = TankUpgradeWidget(slotIndex, wrapper, stack) + } + + is AdvancedPumpUpgradeWrapper -> { + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = AdvancedPumpUpgradeWidget(slotIndex, wrapper, stack) + } + + is PumpUpgradeWrapper -> { + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = PumpUpgradeWidget(slotIndex, wrapper, stack) + } + + is BatteryUpgradeWrapper -> { + upgradeSlotGroup.updateBatteryDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = BatteryUpgradeWidget(slotIndex, wrapper, stack, backpackWrapper) + } + + is AnvilUpgradeWrapper -> { + upgradeSlotGroup.updateAnvilDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = AnvilUpgradeWidget(slotIndex, wrapper, stack) + } + is IAdvancedFilterable -> { upgradeSlotGroup.updateAdvancedFilterDelegate(wrapper) if (updateAndCheckRecreation>(tabWidget.expandedWidget, wrapper)) @@ -521,7 +1082,7 @@ class BackpackPanel( } } - context.recipeViewerSettings.addExclusionArea(tabWidget.expandedWidget) + tabWidget.expandedWidget?.let { context.recipeViewerSettings.addExclusionArea(it) } tabIndex++ tabDisplayIndex++ } @@ -544,6 +1105,9 @@ class BackpackPanel( } private fun resetTabState() { + if (!isValid) + return + for (tabWidget in tabWidgets) { if (tabWidget.expandedWidget != null) { context.recipeViewerSettings.removeExclusionArea(tabWidget.expandedWidget) @@ -553,7 +1117,7 @@ class BackpackPanel( private fun disableUnusedTabWidgets(startTabIndex: Int) { for (i in startTabIndex until backpackWrapper.upgradeSlotsSize()) { - tabWidgets[i].isEnabled = false + clearUpgradeTab(tabWidgets[i]) } } @@ -566,6 +1130,7 @@ class BackpackPanel( toggleWidget.isToggleEnabled = wrapper.enabled toggleWidget.isEnabled = true } else { + toggleWidget.isToggleEnabled = false toggleWidget.isEnabled = false } } @@ -574,11 +1139,53 @@ class BackpackPanel( override fun shouldAnimate(): Boolean = ClientConfig.enableAnimation && super.shouldAnimate() - override fun postDraw(context: ModularGuiContext, transformed: Boolean) { - super.postDraw(context, transformed) + override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + renderStorageBackground(widgetTheme.theme) + } - // Nasty hack to draw over upgrade tabs - LAYERED_TAB_TEXTURE.draw(context, area.width - 6, 0, 6, area.height, WidgetTheme.getDefault().theme) + private fun renderStorageBackground(theme: WidgetTheme) { + val slotsTopBottomHeight = min(storageInventoryHeight / 2, 150) + var yOffset = 0 + + storageBackgroundTexture.drawSubArea( + 0f, + 0f, + area.width.toFloat(), + (STORAGE_INVENTORY_Y + slotsTopBottomHeight).toFloat(), + 0f, + 0f, + area.width / 256f, + (STORAGE_INVENTORY_Y + slotsTopBottomHeight) / 256f, + theme + ) + + if (storageInventoryHeight / 2 > 150) { + val middleHeight = (storageInventoryHeight / 2 - 150) * 2 + storageBackgroundTexture.drawSubArea( + 0f, + (STORAGE_INVENTORY_Y + slotsTopBottomHeight).toFloat(), + area.width.toFloat(), + middleHeight.toFloat(), + 0f, + STORAGE_INVENTORY_Y / 256f, + area.width / 256f, + (STORAGE_INVENTORY_Y + middleHeight) / 256f, + theme + ) + yOffset = middleHeight + } + + storageBackgroundTexture.drawSubArea( + 0f, + (yOffset + STORAGE_INVENTORY_Y + slotsTopBottomHeight).toFloat(), + area.width.toFloat(), + (97 + slotsTopBottomHeight).toFloat(), + 0f, + (256 - (97 + slotsTopBottomHeight)) / 256f, + area.width / 256f, + 1f, + theme + ) } fun getOpenCraftingUpgradeSlot(): Int? { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackSettingPanel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackSettingPanel.kt deleted file mode 100644 index 240c3de..0000000 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackSettingPanel.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.cleanroommc.retrosophisticatedbackpacks.client.gui - -import com.cleanroommc.modularui.api.drawable.IKey -import com.cleanroommc.modularui.drawable.AdaptableUITexture -import com.cleanroommc.modularui.drawable.UITexture -import com.cleanroommc.modularui.screen.ModularPanel -import com.cleanroommc.modularui.screen.ModularScreen -import com.cleanroommc.modularui.screen.RichTooltip -import com.cleanroommc.modularui.screen.viewport.ModularGuiContext -import com.cleanroommc.modularui.theme.WidgetTheme -import com.cleanroommc.modularui.widgets.TextWidget -import com.cleanroommc.modularui.widgets.layout.Column -import com.cleanroommc.retrosophisticatedbackpacks.Tags -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.ExpandDirection -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.MemorySettingWidget -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.SortingSettingWidget -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.TabWidget -import com.cleanroommc.retrosophisticatedbackpacks.config.ClientConfig -import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey - -class BackpackSettingPanel(private val parent: BackpackPanel) : ModularPanel("backpack_settings") { - companion object { - private const val HEIGHT: Int = 95 - private val LAYERED_TAB_TEXTURE = UITexture.builder() - .location(Tags.MOD_ID, "gui/gui_controls") - .imageSize(256, 256) - .xy(128, 0, 124, 256) - .adaptable(4) - .tiled() - .build() as AdaptableUITexture - } - - private val memoryTab: TabWidget - private val sortTab: TabWidget - - init { - size(parent.area.width, HEIGHT) - .relative(parent) - .bottom(0) - - memoryTab = TabWidget(0, expandDirection = ExpandDirection.LEFT) - .tooltipStatic { - it.addLine(IKey.lang("gui.memory_settings".asTranslationKey())) - .pos(RichTooltip.Pos.NEXT_TO_MOUSE) - } - memoryTab.expandedWidget = MemorySettingWidget(parent, this, memoryTab) - memoryTab.tabIcon = RSBTextures.BRAIN_ICON - - sortTab = TabWidget(1, expandDirection = ExpandDirection.LEFT) - .tooltipStatic { - it.addLine(IKey.lang("gui.sorting_settings".asTranslationKey())) - .pos(RichTooltip.Pos.NEXT_TO_MOUSE) - } - sortTab.expandedWidget = SortingSettingWidget(parent, this, sortTab) - sortTab.tabIcon = RSBTextures.NO_SORT_ICON - - val grid = Column() - .size(parent.area.width - 14, HEIGHT - 14) - .margin(7) - .child(TextWidget(IKey.lang("gui.configuration_tab".asTranslationKey())).leftRel(0.5f)) - - child(grid) - .child(memoryTab) - .child(sortTab) - } - - internal fun updateTabState(fromIndex: Int) { - memoryTab.isEnabled = true - sortTab.isEnabled = true - - when (fromIndex) { - 0 -> { - sortTab.showExpanded = false - parent.isSortingSettingTabOpened = false - sortTab.isEnabled = !memoryTab.showExpanded - } - - 1 -> { - memoryTab.showExpanded = false - parent.isMemorySettingTabOpened = false - } - } - } - - override fun shouldAnimate(): Boolean = - ClientConfig.enableAnimation && super.shouldAnimate() - - override fun isDraggable(): Boolean = - false - - override fun onOpen(screen: ModularScreen) { - super.onOpen(screen) - parent.isMemorySettingTabOpened = memoryTab.showExpanded - parent.shouldMemorizeRespectNBT = (memoryTab.expandedWidget as MemorySettingWidget).isRespectNBT() - parent.isSortingSettingTabOpened = sortTab.showExpanded - } - - override fun onClose() { - super.onClose() - parent.isMemorySettingTabOpened = false - parent.shouldMemorizeRespectNBT = false - parent.isSortingSettingTabOpened = false - } - - override fun postDraw(context: ModularGuiContext, transformed: Boolean) { - super.postDraw(context, transformed) - - // Nasty hack to draw over upgrade tabs - LAYERED_TAB_TEXTURE.draw(context, 0, 0, 6, area.height, WidgetTheme.getDefault().theme) - } -} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt index 76acc9f..5c068bf 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt @@ -32,6 +32,14 @@ object RSBTextures { val IN_OUT_ICON = icon("in_out", 0, 32) val IN_ICON = icon("in", 16, 32) val OUT_ICON = icon("out", 32, 32) + val PUMP_INPUT_ICON = controlIcon(144, 0) + val PUMP_OUTPUT_ICON = controlIcon(160, 0) + val PUMP_WORLD_ICON = controlIcon(176, 0) + val PUMP_NO_WORLD_ICON = controlIcon(192, 0) + val PUMP_HAND_ICON = controlIcon(208, 0) + val PUMP_NO_HAND_ICON = controlIcon(224, 0) + val PUMP_FLUID_HANDLER_ICON = controlIcon(0, 112) + val PUMP_NO_FLUID_HANDLER_ICON = controlIcon(16, 112) val ADD_ICON = icon("add", 96, 32) val REMOVE_ICON = icon("remove", 112, 32) @@ -41,6 +49,7 @@ object RSBTextures { val ALL_FOUR_SLOT_ICON = icon("all_in_four_slot", 16, 80) val NO_SORT_ICON = icon("no_sort", 32, 80) val NONE_FOUR_SLOT_ICON = icon("none_in_four_slot", 48, 80) + val BACK_TO_BACKPACK_ICON = icon("back_to_backpack", 64, 80) val SETTING_ICON = icon("setting", 16, 96) @@ -62,6 +71,12 @@ object RSBTextures { val LEFT_ARROW_ICON = icon("left_arrow", 32, 48) val DOWN_ARROW_ICON = icon("down_arrow", 48, 48) + val BACKPACK_SETTINGS_ICON = icon("backpack_settings", 64, 48) + val ITEM_DISPLAY_SETTINGS_ICON = icon("item_display_settings", 112, 64) + val ITEM_DISPLAY_ROTATE_ICON = icon("item_display_rotate", 128, 64) + val DISPLAY_SIDE_FRONT_ICON = icon("display_side_front", 144, 64) + val DISPLAY_SIDE_LEFT_ICON = icon("display_side_left", 160, 64) + val DISPLAY_SIDE_RIGHT_ICON = icon("display_side_right", 176, 64) val STANDARD_BUTTON = UITexture.builder() .location(Tags.MOD_ID, "gui/gui_controls.png") @@ -73,6 +88,12 @@ object RSBTextures { .imageSize(256, 256) .xy(47, 0, 18, 18) .build() + val CONTEXT_BUTTON_LEFT = buttonPiece(29, 0, 16, 18) + val CONTEXT_BUTTON_LEFT_HOVERED = buttonPiece(47, 0, 16, 18) + val CONTEXT_BUTTON_MIDDLE = buttonPiece(31, 0, 14, 18) + val CONTEXT_BUTTON_MIDDLE_HOVERED = buttonPiece(49, 0, 14, 18) + val CONTEXT_BUTTON_RIGHT = buttonPiece(31, 0, 16, 18) + val CONTEXT_BUTTON_RIGHT_HOVERED = buttonPiece(49, 0, 16, 18) val BIG_SLOT_TEXTURE = UITexture.builder() .location(Tags.MOD_ID, "gui/gui_controls.png") @@ -85,6 +106,63 @@ object RSBTextures { .imageSize(256, 256) .xy(97, 209, 16, 16) .build() + val TANK_ARROW = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(97, 216, 15, 8) + .build() + val MEMORIZED_SLOT_OVERLAY = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(77, 0, 16, 16) + .build() + val SLOT_SELECTION = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(93, 0, 24, 24) + .build() + val SLOT_BACKGROUND = UITexture.builder() + .location(Tags.MOD_ID, "gui/slots_background.png") + .imageSize(256, 256) + .xy(0, 0, 18, 18) + .build() + val SLOTS_BACKGROUND = UITexture.fullImage(Tags.MOD_ID, "gui/slots_background.png") + val STORAGE_BACKGROUND_9 = UITexture.fullImage(Tags.MOD_ID, "gui/storage_background_9.png") + val STORAGE_BACKGROUND_9_WIDER = UITexture.fullImage(Tags.MOD_ID, "gui/storage_background_9_wider.png") + val STORAGE_BACKGROUND_12 = UITexture.fullImage(Tags.MOD_ID, "gui/storage_background_12.png") + val STORAGE_BACKGROUND_12_WIDER = UITexture.fullImage(Tags.MOD_ID, "gui/storage_background_12_wider.png") + val EMPTY_TANK_INPUT_SLOT = UITexture.fullImage(Tags.MOD_ID, "item/empty_tank_input_slot.png") + val EMPTY_TANK_OUTPUT_SLOT = UITexture.fullImage(Tags.MOD_ID, "item/empty_tank_output_slot.png") + val EMPTY_BATTERY_INPUT_SLOT = UITexture.fullImage(Tags.MOD_ID, "item/empty_battery_input_slot.png") + val EMPTY_BATTERY_OUTPUT_SLOT = UITexture.fullImage(Tags.MOD_ID, "item/empty_battery_output_slot.png") + val EMPTY_UPGRADE_SLOT = UITexture.fullImage(Tags.MOD_ID, "item/empty_upgrade_slot.png") + + val TANK_OVERLAY = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(47, 30, 16, 18) + .build() + val BATTERY_OVERLAY = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(47, 56, 16, 18) + .build() + val BATTERY_CHARGE = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(47, 74, 16, 6) + .build() + val BAR_BACKGROUND_TOP = barBackground(29, 30) + val BAR_BACKGROUND_MIDDLE = barBackground(29, 48) + val BAR_BACKGROUND_BOTTOM = barBackground(29, 66) + val SHIFT_CLICK_OPEN_TAB_ON = controlIcon(80, 32) + val SHIFT_CLICK_OPEN_TAB_OFF = controlIcon(64, 96) + val KEEP_TAB_OPEN_ON = controlIcon(80, 80) + val KEEP_TAB_OPEN_OFF = controlIcon(80, 96) + val KEEP_SEARCH_PHRASE_ON = controlIcon(208, 32) + val KEEP_SEARCH_PHRASE_OFF = controlIcon(224, 32) + val ANOTHER_PLAYER_CAN_OPEN_ON = controlIcon(176, 32) + val ANOTHER_PLAYER_CAN_OPEN_OFF = controlIcon(192, 32) private fun icon(name: String, x: Int, y: Int, w: Int = 16, h: Int = 16): UITexture = UITexture.builder() @@ -93,4 +171,25 @@ object RSBTextures { .xy(x, y, w, h) .name(name) .build() + + private fun barBackground(x: Int, y: Int): UITexture = + UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(x, y, 18, 18) + .build() + + private fun buttonPiece(x: Int, y: Int, w: Int, h: Int): UITexture = + UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(x, y, w, h) + .build() + + private fun controlIcon(x: Int, y: Int, w: Int = 16, h: Int = 16): UITexture = + UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(x, y, w, h) + .build() } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt index 3e18565..ae80dd9 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt @@ -8,6 +8,10 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CraftingUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IAdvancedFilterable import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IBasicFilterable +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AnvilUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.BatteryUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.TankUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.CraftingSlotInfo import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.IndexedModularCraftingSlot import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularFilterSlot @@ -39,6 +43,18 @@ class UpgradeSlotUpdateGroup( val craftingInfo: CraftingSlotInfo + var jukeboxDiscStackHandler = DelegatedStackHandlerSH(wrapper, slotIndex, 12) + val jukeboxDiscSlots: Array + + var tankStackHandler = DelegatedStackHandlerSH(wrapper, slotIndex, 4) + val tankSlots: Array + + var batteryStackHandler = DelegatedStackHandlerSH(wrapper, slotIndex, 2) + val batterySlots: Array + + var anvilStackHandler = DelegatedStackHandlerSH(wrapper, slotIndex, 2) + val anvilSlots: Array + init { val syncManager = panel.syncManager @@ -140,6 +156,56 @@ class UpgradeSlotUpdateGroup( syncManager.registerSlotGroup(SlotGroup("crafting_result_$slotIndex", 1, false)) + syncManager.syncValue("jukebox_disc_delegation_$slotIndex", jukeboxDiscStackHandler) + jukeboxDiscSlots = Array(12) { + val slot = ModularSlot(jukeboxDiscStackHandler.delegatedStackHandler, it) + slot.slotGroup("jukebox_discs_$slotIndex") + + syncManager.syncValue( + "jukebox_discs_$slotIndex", + it, + ItemSlotSH(slot) + ) + + slot + } + syncManager.registerSlotGroup(SlotGroup("jukebox_discs_$slotIndex", 4, false)) + + syncManager.syncValue("tank_delegation_$slotIndex", tankStackHandler) + tankSlots = Array(4) { + val slot = ModularSlot(tankStackHandler.delegatedStackHandler, it) + slot.slotGroup("tank_$slotIndex") + if (it >= 2) { + slot.accessibility(false, true) + } + + syncManager.syncValue( + "tank_$slotIndex", + it, + ItemSlotSH(slot) + ) + + slot + } + syncManager.registerSlotGroup(SlotGroup("tank_$slotIndex", 2, false)) + + syncManager.syncValue("battery_delegation_$slotIndex", batteryStackHandler) + batterySlots = Array(2) { + val slot = ModularSlot(batteryStackHandler.delegatedStackHandler, it) + slot.slotGroup("battery_$slotIndex") + syncManager.syncValue("battery_$slotIndex", it, ItemSlotSH(slot)) + slot + } + syncManager.registerSlotGroup(SlotGroup("battery_$slotIndex", 2, false)) + + syncManager.syncValue("anvil_delegation_$slotIndex", anvilStackHandler) + anvilSlots = Array(2) { + val slot = ModularSlot(anvilStackHandler.delegatedStackHandler, it) + slot.slotGroup("anvil_$slotIndex") + syncManager.syncValue("anvil_$slotIndex", it, ItemSlotSH(slot)) + slot + } + syncManager.registerSlotGroup(SlotGroup("anvil_$slotIndex", 2, false)) } fun updateFilterDelegate(wrapper: IBasicFilterable) { @@ -152,9 +218,34 @@ class UpgradeSlotUpdateGroup( advancedCommonFilterStackHandler.syncToServer(DelegatedStackHandlerSH.UPDATE_FILTERABLE) } + fun updateLargeBasicFilterDelegate(wrapper: IBasicFilterable) { + advancedCommonFilterStackHandler.setDelegatedStackHandler(wrapper::filterItems) + advancedCommonFilterStackHandler.syncToServer(DelegatedStackHandlerSH.UPDATE_FILTERABLE) + } + fun updateCraftingDelegate(wrapper: CraftingUpgradeWrapper) { craftingStackHandler.setDelegatedStackHandler(wrapper::craftMatrix) craftingStackHandler.syncToServer(DelegatedCraftingStackHandlerSH.UPDATE_CRAFTING) } -} \ No newline at end of file + fun updateJukeboxDelegate(wrapper: JukeboxUpgradeWrapper) { + jukeboxDiscStackHandler.setDelegatedStackHandler(wrapper::discInventory) + jukeboxDiscStackHandler.syncToServer(DelegatedStackHandlerSH.UPDATE_JUKEBOX) + } + + fun updateTankDelegate(wrapper: TankUpgradeWrapper) { + tankStackHandler.setDelegatedStackHandler(wrapper::getInventory) + tankStackHandler.syncToServer(DelegatedStackHandlerSH.UPDATE_TANK) + } + + fun updateBatteryDelegate(wrapper: BatteryUpgradeWrapper) { + batteryStackHandler.setDelegatedStackHandler(wrapper::getInventory) + batteryStackHandler.syncToServer(DelegatedStackHandlerSH.UPDATE_BATTERY) + } + + fun updateAnvilDelegate(wrapper: AnvilUpgradeWrapper) { + anvilStackHandler.setDelegatedStackHandler(wrapper::getInventory) + anvilStackHandler.syncToServer(DelegatedStackHandlerSH.UPDATE_ANVIL) + } + +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt new file mode 100644 index 0000000..04a080e --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt @@ -0,0 +1,59 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.drawable.GuiTextures +import com.cleanroommc.modularui.drawable.TabTexture +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault + +class BackToBackpackTabWidget : Widget(), Interactable { + companion object { + val TAB_TEXTURE: TabTexture = GuiTextures.TAB_RIGHT + } + + init { + size(TAB_TEXTURE.width, TAB_TEXTURE.height) + .right(-TAB_TEXTURE.width + 4) + .top(4) + .background(TAB_TEXTURE.get(-1, false)) + .tooltipStatic { + it.addLine(IKey.lang("gui.back_to_backpack.tooltip".asTranslationKey())) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + } + + override fun onInit() { + context.recipeViewerSettings.addExclusionArea(this) + } + + override fun dispose() { + if (isValid) + context.recipeViewerSettings.removeExclusionArea(this) + super.dispose() + } + + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (!isEnabled) + return Interactable.Result.STOP + + if (mouseButton == 0) { + Interactable.playButtonClickSound() + (panel as BackpackPanel).isSettingMode = false + return Interactable.Result.SUCCESS + } + + return Interactable.Result.IGNORE + } + + override fun draw(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.draw(context, widgetTheme) + RSBTextures.BACK_TO_BACKPACK_ICON.draw(context, 8, 6, 16, 16, widgetTheme.getThemeOrDefault()) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt new file mode 100644 index 0000000..a287e5c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt @@ -0,0 +1,71 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.widget.ScrollWidget +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.modularui.widget.scroll.VerticalScrollData +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widgets.SlotGroupWidget +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.BackpackSlot + +class BackpackInventoryScrollWidget(panel: BackpackPanel) : + ScrollWidget(VerticalScrollData(false, SCROLLBAR_WIDTH)) { + init { + val scrollData = scrollArea.scrollY + scrollData.scrollSize = panel.colSize * SLOT_SIZE + scrollData.scrollSpeed = SLOT_SIZE + + size(panel.backpackSlotsWidth + panel.inventoryScrollbarWidth, panel.visibleColSize * SLOT_SIZE) + + child(createSlots(panel, panel.colSize)) + } + + companion object { + const val SCROLLBAR_WIDTH = 4 + private const val SLOT_SIZE = 18 + + fun createSlots(panel: BackpackPanel, visibleRows: Int): SlotGroupWidget { + val slots = SlotGroupWidget().name("backpack_inventory").disableSortButtons() + slots.size(panel.backpackSlotsWidth, visibleRows * SLOT_SIZE) + slots.child(BackpackSlotBackgroundWidget(panel, visibleRows)) + for (i in 0 until panel.backpackWrapper.backpackInventorySize()) { + slots.child( + BackpackSlot(panel, panel.backpackWrapper) + .syncHandler("backpack", i) + .pos(i % panel.rowSize * SLOT_SIZE, i / panel.rowSize * SLOT_SIZE) + .name("slot_$i") + ) + } + return slots + } + } + + private class BackpackSlotBackgroundWidget(private val panel: BackpackPanel, rows: Int) : + Widget() { + init { + size(panel.backpackSlotsWidth, rows * SLOT_SIZE) + } + + override fun canHover(): Boolean = false + + override fun canHoverThrough(): Boolean = true + + override fun canClickThrough(): Boolean = true + + override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + val theme = widgetTheme.theme + for (i in 0 until panel.backpackWrapper.backpackInventorySize()) { + RSBTextures.SLOT_BACKGROUND.draw( + context, + i % panel.rowSize * SLOT_SIZE, + i / panel.rowSize * SLOT_SIZE, + SLOT_SIZE, + SLOT_SIZE, + theme + ) + } + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt new file mode 100644 index 0000000..e59e266 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt @@ -0,0 +1,160 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraft.client.Minecraft +import net.minecraft.client.resources.I18n + +class BackpackMainSettingsWidget( + private val panel: BackpackPanel, + private val parentTabWidget: TabWidget +) : ExpandedTabWidget( + 2, + RSBTextures.BACKPACK_SETTINGS_ICON, + "gui.backpack_settings".asTranslationKey(), + width = 93, + expandDirection = ExpandDirection.RIGHT +) { + private val contextButton = ContextButtonWidget(panel.backpackWrapper) + .pos(4, 20) + .onMousePressed { + if (it == 0) { + panel.backpackWrapper.toggleSettingsContext() + panel.backpackSyncHandler.syncToServer(BackpackSH.UPDATE_TOGGLE_SETTINGS_CONTEXT) {} + Interactable.playButtonClickSound() + true + } else false + } + .tooltipAutoUpdate(true) + .tooltipDynamic { + val key = if (panel.backpackWrapper.settingsContext == BackpackWrapper.SettingsContext.PLAYER) + "gui.settings_button.context_player.tooltip" + else "gui.settings_button.context_backpack.tooltip" + it.addLine(IKey.lang(key.asTranslationKey())).pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + private val shiftClickButton = toggleButton( + 4, + 42, + { panel.backpackWrapper.shiftClickIntoOpenTab }, + RSBTextures.SHIFT_CLICK_OPEN_TAB_ON, + RSBTextures.SHIFT_CLICK_OPEN_TAB_OFF, + "shift_click_open_tab", + BackpackSH.UPDATE_TOGGLE_SHIFT_CLICK_INTO_OPEN_TAB, + panel.backpackWrapper::toggleShiftClickIntoOpenTab + ) + private val keepTabOpenButton = toggleButton( + 26, + 42, + { panel.backpackWrapper.keepTabOpen }, + RSBTextures.KEEP_TAB_OPEN_ON, + RSBTextures.KEEP_TAB_OPEN_OFF, + "keep_tab_open", + BackpackSH.UPDATE_TOGGLE_KEEP_TAB_OPEN, + panel.backpackWrapper::toggleKeepTabOpen + ) + private val keepSearchPhraseButton = toggleButton( + 48, + 42, + { panel.backpackWrapper.keepSearchPhrase }, + RSBTextures.KEEP_SEARCH_PHRASE_ON, + RSBTextures.KEEP_SEARCH_PHRASE_OFF, + "keep_search_phrase", + BackpackSH.UPDATE_TOGGLE_KEEP_SEARCH_PHRASE, + panel.backpackWrapper::toggleKeepSearchPhrase + ) + private val otherPlayerButton = toggleButton( + 70, + 42, + { panel.backpackWrapper.anotherPlayerCanOpen }, + RSBTextures.ANOTHER_PLAYER_CAN_OPEN_ON, + RSBTextures.ANOTHER_PLAYER_CAN_OPEN_OFF, + "another_player_can_open", + BackpackSH.UPDATE_TOGGLE_ANOTHER_PLAYER_CAN_OPEN, + panel.backpackWrapper::toggleAnotherPlayerCanOpen + ) + + init { + child(contextButton) + .child(shiftClickButton) + .child(keepTabOpenButton) + .child(keepSearchPhraseButton) + .child(otherPlayerButton) + } + + override fun updateTabState() { + panel.openBackpackSettings(parentTabWidget, !parentTabWidget.showExpanded) + } + + private fun toggleButton( + x: Int, + y: Int, + state: () -> Boolean, + onIcon: IDrawable, + offIcon: IDrawable, + tooltipName: String, + syncId: Int, + toggle: () -> Unit + ): DynamicIconButtonWidget = + DynamicIconButtonWidget({ if (state()) onIcon else offIcon }) + .pos(x, y) + .size(18) + .onMousePressed { + if (it == 0) { + toggle() + panel.backpackSyncHandler.syncToServer(syncId) {} + Interactable.playButtonClickSound() + true + } else false + } + .tooltipAutoUpdate(true) + .tooltipDynamic { + it.addLine( + IKey.lang( + "gui.settings_button.$tooltipName.${if (state()) "on" else "off"}".asTranslationKey() + ) + ).pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + private class ContextButtonWidget(private val wrapper: BackpackWrapper) : ButtonWidget() { + init { + size(84, 18) + } + + override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + val theme = widgetTheme.getThemeOrDefault() + val left = if (isHovering) RSBTextures.CONTEXT_BUTTON_LEFT_HOVERED else RSBTextures.CONTEXT_BUTTON_LEFT + val middle = + if (isHovering) RSBTextures.CONTEXT_BUTTON_MIDDLE_HOVERED else RSBTextures.CONTEXT_BUTTON_MIDDLE + val right = if (isHovering) RSBTextures.CONTEXT_BUTTON_RIGHT_HOVERED else RSBTextures.CONTEXT_BUTTON_RIGHT + left.draw(context, 0, 0, 16, 18, theme) + middle.draw(context, 16, 0, 14, 18, theme) + middle.draw(context, 30, 0, 14, 18, theme) + middle.draw(context, 44, 0, 14, 18, theme) + middle.draw(context, 58, 0, 14, 18, theme) + right.draw(context, 68, 0, 16, 18, theme) + } + + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawOverlay(context, widgetTheme) + val textKey = if (wrapper.settingsContext == BackpackWrapper.SettingsContext.PLAYER) + "gui.settings_button.context_player" + else "gui.settings_button.context_backpack" + val text = I18n.format(textKey.asTranslationKey()) + val font = Minecraft.getMinecraft().fontRenderer + font.drawStringWithShadow(text, (area.width - font.getStringWidth(text)) / 2f, 5f, 0xFFFFFF) + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt new file mode 100644 index 0000000..0c43dc7 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt @@ -0,0 +1,91 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.BatteryUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault + +class BatteryInventoryControlWidget( + private val upgradeSlot: Int, + private val backpackWrapper: BackpackWrapper, + height: Int +) : Widget() { + companion object { + const val WIDTH = 36 + private const val BATTERY_LEFT = 9 + private const val BATTERY_WIDTH = 18 + private const val OVERLAY_LEFT = BATTERY_LEFT + 1 + private const val OVERLAY_WIDTH = 16 + } + + init { + size(WIDTH, height) + tooltipAutoUpdate(true) + tooltipDynamic { + val wrapper = currentWrapper() + it.addLine(IKey.str("${wrapper?.energyStored ?: 0}/${wrapper?.getMaxEnergyStored(backpackWrapper) ?: 0} FE")) + it.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + val theme = widgetTheme.getThemeOrDefault() + val height = area.height + RSBTextures.BAR_BACKGROUND_TOP.draw(context, BATTERY_LEFT, 0, BATTERY_WIDTH, if (height < 36) height / 2 else 18, theme) + var yOffset = 18 + repeat((height - 36).coerceAtLeast(0) / 18) { + RSBTextures.BAR_BACKGROUND_MIDDLE.draw(context, BATTERY_LEFT, yOffset, BATTERY_WIDTH, 18, theme) + yOffset += 18 + } + RSBTextures.BAR_BACKGROUND_BOTTOM.draw( + context, + BATTERY_LEFT, + if (height < 36) height / 2 else yOffset, + BATTERY_WIDTH, + if (height < 36) height / 2 else 18, + theme + ) + renderCharge(context, currentWrapper(), height, theme) + yOffset = 0 + repeat(height / 18) { + RSBTextures.BATTERY_OVERLAY.draw(context, OVERLAY_LEFT, yOffset, OVERLAY_WIDTH, 18, theme) + yOffset += 18 + } + } + + private fun currentWrapper(): BatteryUpgradeWrapper? = + backpackWrapper.upgradeItemStackHandler.inventory[upgradeSlot] + .getCapability(Capabilities.BATTERY_UPGRADE_CAPABILITY, null) + + private fun renderCharge( + context: ModularGuiContext, + wrapper: BatteryUpgradeWrapper?, + height: Int, + theme: com.cleanroommc.modularui.theme.WidgetTheme + ) { + val max = wrapper?.getMaxEnergyStored(backpackWrapper) ?: 0 + if (wrapper == null || max <= 0 || wrapper.energyStored <= 0) { + return + } + val displayLevel = ((height - 2) * (wrapper.energyStored.toFloat() / max)).toInt().coerceIn(1, height - 2) + var drawn = 0 + while (drawn < displayLevel) { + val segment = minOf(6, displayLevel - drawn) + RSBTextures.BATTERY_CHARGE.draw( + context, + OVERLAY_LEFT, + height - 1 - drawn - segment, + OVERLAY_WIDTH, + segment, + theme + ) + drawn += segment + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt index a519dd4..4b39293 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt @@ -35,7 +35,8 @@ class CyclicVariantButtonWidget( mousePressedUpdater(this.index) markTooltipDirty() true - }.tooltipDynamic { + }.tooltipAutoUpdate(true) + .tooltipDynamic { it.addLine(variants[this.index].name) if (!inEffect) { @@ -67,4 +68,4 @@ class CyclicVariantButtonWidget( } data class Variant(val name: IKey, val drawable: IDrawable) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt new file mode 100644 index 0000000..8db8983 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt @@ -0,0 +1,18 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault + +class DynamicIconButtonWidget( + private val icon: () -> IDrawable, + private val iconOffset: Int = 1, + private val iconSize: Int = 16 +) : ButtonWidget() { + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawOverlay(context, widgetTheme) + icon().draw(context, iconOffset, iconOffset, iconSize, iconSize, widgetTheme.getThemeOrDefault()) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt index 74aef4a..fea6da0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt @@ -42,8 +42,8 @@ abstract class ExpandedTabWidget( right(0) upperTabRow - .child(Widget().width(4).name("placeholder")) - .child(titleKeyWidget) + .width(width - 3) + .child(titleKeyWidget.expanded()) .child(phantomTabWidget) } @@ -60,25 +60,31 @@ abstract class ExpandedTabWidget( width(width) .height(coveredTabSize * 30) .background(TAB_TEXTURE) - .child(upperTabRow) + child(upperTabRow) } abstract fun updateTabState() + override fun dispose() { + if (isValid) + context.recipeViewerSettings.removeExclusionArea(this) + super.dispose() + } + protected inner class PhantomTabWidget(tabIcon: Widget<*>) : SingleChildWidget(), Interactable { init { - size(32, 28) + size(24, 28) tabIcon.size(16).top(6) when (expandDirection) { ExpandDirection.LEFT -> { right(0) - tabIcon.right(8) + tabIcon.right(4) } ExpandDirection.RIGHT -> { - tabIcon.left(8) + tabIcon.left(4) } } @@ -98,4 +104,4 @@ abstract class ExpandedTabWidget( return Interactable.Result.STOP } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt new file mode 100644 index 0000000..3d84012 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt @@ -0,0 +1,123 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.backpack.DisplaySide +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSH +import com.cleanroommc.retrosophisticatedbackpacks.util.DyeColorUtils +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.gui.Gui +import net.minecraft.item.EnumDyeColor + +class ItemDisplaySettingsWidget( + private val panel: BackpackPanel, + private val parentTabWidget: TabWidget +) : ExpandedTabWidget( + 2, + RSBTextures.ITEM_DISPLAY_SETTINGS_ICON, + "gui.item_display_settings".asTranslationKey(), + width = 75, + expandDirection = ExpandDirection.RIGHT +) { + private val rotateButton = DynamicIconButtonWidget({ RSBTextures.ITEM_DISPLAY_ROTATE_ICON }) + .pos(3, 24) + .size(18) + .onMousePressed { + val slot = panel.currentItemDisplaySelectedSlot + if (slot < 0) { + return@onMousePressed false + } + val clockwise = it != 1 + panel.backpackWrapper.rotateItemDisplaySlot(slot, clockwise) + panel.backpackSyncHandler.syncToServer(BackpackSH.UPDATE_ITEM_DISPLAY_ROTATION) { buf -> + buf.writeInt(slot) + buf.writeBoolean(clockwise) + } + Interactable.playButtonClickSound() + true + } + .tooltipStatic { + it.addLine(IKey.lang("gui.settings_button.rotate".asTranslationKey())) + .addLine(IKey.lang("gui.settings_button.rotate_detail".asTranslationKey()).style(IKey.GRAY)) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + private val colorButton = ColorToggleButton() + .pos(21, 24) + .onMousePressed { + if (it != 0 && it != 1) { + return@onMousePressed false + } + val colors = EnumDyeColor.entries + val next = colors[(panel.backpackWrapper.itemDisplayColor.ordinal + if (it == 0) 1 else colors.size - 1) % colors.size] + panel.backpackWrapper.itemDisplayColor = next + panel.backpackSyncHandler.syncToServer(BackpackSH.UPDATE_ITEM_DISPLAY_COLOR) { buf -> + buf.writeEnumValue(next) + } + Interactable.playButtonClickSound() + true + } + .tooltipAutoUpdate(true) + .tooltipDynamic { + it.addLine(IKey.lang("gui.settings_button.item_display_color".asTranslationKey())) + .addLine(IKey.str(panel.backpackWrapper.itemDisplayColor.name.lowercase())) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + private val sideButton = DynamicIconButtonWidget({ + when (panel.backpackWrapper.itemDisplaySide) { + DisplaySide.FRONT -> RSBTextures.DISPLAY_SIDE_FRONT_ICON + DisplaySide.LEFT -> RSBTextures.DISPLAY_SIDE_LEFT_ICON + DisplaySide.RIGHT -> RSBTextures.DISPLAY_SIDE_RIGHT_ICON + } + }) + .pos(39, 24) + .size(18) + .onMousePressed { + if (it != 0 && it != 1) { + return@onMousePressed false + } + val next = if (it == 0) panel.backpackWrapper.itemDisplaySide.next() + else panel.backpackWrapper.itemDisplaySide.previous() + panel.backpackWrapper.itemDisplaySide = next + panel.backpackSyncHandler.syncToServer(BackpackSH.UPDATE_ITEM_DISPLAY_SIDE) { buf -> + buf.writeEnumValue(next) + } + Interactable.playButtonClickSound() + true + } + .tooltipAutoUpdate(true) + .tooltipDynamic { + it.addLine( + IKey.lang("gui.settings_button.display_side_${panel.backpackWrapper.itemDisplaySide.serializedName}".asTranslationKey()) + ).pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + init { + child(rotateButton) + .child(colorButton) + .child(sideButton) + } + + override fun updateTabState() { + panel.openItemDisplaySettings(parentTabWidget, !parentTabWidget.showExpanded) + } + + private inner class ColorToggleButton : ButtonWidget() { + init { + size(18, 18) + } + + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawOverlay(context, widgetTheme) + val color = DyeColorUtils.colorValue(this@ItemDisplaySettingsWidget.panel.backpackWrapper.itemDisplayColor) + Gui.drawRect(4, 4, 14, 14, color or -0x1000000) + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt index b803760..b8825b5 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt @@ -3,9 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets import com.cleanroommc.modularui.api.drawable.IKey import com.cleanroommc.modularui.screen.RichTooltip import com.cleanroommc.modularui.widgets.ButtonWidget -import com.cleanroommc.modularui.widgets.layout.Row import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackSettingPanel import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils @@ -13,14 +11,13 @@ import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey class MemorySettingWidget( private val panel: BackpackPanel, - private val settingPanel: BackpackSettingPanel, private val parentTabWidget: TabWidget ) : ExpandedTabWidget( 2, RSBTextures.BRAIN_ICON, "gui.memory_settings".asTranslationKey(), width = 75, - expandDirection = ExpandDirection.LEFT + expandDirection = ExpandDirection.RIGHT ) { companion object { private val RESPECT_NBT_VARIANTS = listOf( @@ -35,14 +32,9 @@ class MemorySettingWidget( ) } - private val buttonRow: Row = Row() - .leftRel(0.5f) - .height(20) - .coverChildrenWidth() - .childPadding(2) as Row - private val memorizeAllButton: ButtonWidget<*> = ButtonWidget() - .size(20) + .pos(3, 24) + .size(18) .overlay(RSBTextures.ALL_FOUR_SLOT_ICON) .onMousePressed { if (it == 0) { @@ -70,7 +62,8 @@ class MemorySettingWidget( } private val unmemorizeAllButton: ButtonWidget<*> = ButtonWidget() - .size(20) + .pos(21, 24) + .size(18) .overlay(RSBTextures.NONE_FOUR_SLOT_ICON) .onMousePressed { if (it == 0) { @@ -96,25 +89,20 @@ class MemorySettingWidget( } private val respectNBTButton: CyclicVariantButtonWidget = CyclicVariantButtonWidget( RESPECT_NBT_VARIANTS - ) { - this@MemorySettingWidget.panel.shouldMemorizeRespectNBT = it != 0 - } + ) { this@MemorySettingWidget.panel.shouldMemorizeRespectNBT = it != 0 } + .pos(39, 24) + .size(18) init { - buttonRow.top(28) - .child(memorizeAllButton) + child(memorizeAllButton) .child(unmemorizeAllButton) .child(respectNBTButton) - - child(buttonRow) } fun isRespectNBT(): Boolean = respectNBTButton.index != 0 override fun updateTabState() { - parentTabWidget.showExpanded = !parentTabWidget.showExpanded - panel.isMemorySettingTabOpened = parentTabWidget.showExpanded - settingPanel.updateTabState(0) + panel.openMemorySettings(parentTabWidget, !parentTabWidget.showExpanded) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt index a6e4d30..38c20cb 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt @@ -21,7 +21,7 @@ class SettingTabWidget : Widget(), Interactable { init { size(TAB_TEXTURE.width, TAB_TEXTURE.height) .right(-TAB_TEXTURE.width + 4) - .top(0) + .top(4) .background(TAB_TEXTURE.get(-1, false)) .tooltipStatic { it.addLine(IKey.lang("gui.settings".asTranslationKey())) @@ -33,16 +33,18 @@ class SettingTabWidget : Widget(), Interactable { context.recipeViewerSettings.addExclusionArea(this) } + override fun dispose() { + if (isValid) + context.recipeViewerSettings.removeExclusionArea(this) + super.dispose() + } + override fun onMousePressed(mouseButton: Int): Interactable.Result { if (mouseButton == 0) { val panel = panel as BackpackPanel Interactable.playButtonClickSound() - if (panel.settingPanel.isPanelOpen) { - panel.settingPanel.closePanel() - } else { - panel.settingPanel.openPanel() - } + panel.isSettingMode = true return Interactable.Result.SUCCESS } @@ -55,4 +57,4 @@ class SettingTabWidget : Widget(), Interactable { RSBTextures.SETTING_ICON.draw(context, 8, 6, 16, 16, widgetTheme.getThemeOrDefault()) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt index 15a07ab..d9426a3 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt @@ -3,10 +3,8 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets import com.cleanroommc.modularui.api.drawable.IKey import com.cleanroommc.modularui.screen.RichTooltip import com.cleanroommc.modularui.widgets.ButtonWidget -import com.cleanroommc.modularui.widgets.layout.Row import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackSettingPanel import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils @@ -14,23 +12,17 @@ import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey class SortingSettingWidget( private val panel: BackpackPanel, - private val settingPanel: BackpackSettingPanel, private val parentTabWidget: TabWidget ) : ExpandedTabWidget( 2, RSBTextures.NO_SORT_ICON, "gui.sorting_settings".asTranslationKey(), width = 75, - expandDirection = ExpandDirection.LEFT + expandDirection = ExpandDirection.RIGHT ) { - private val buttonRow: Row = Row() - .leftRel(0.5f) - .height(20) - .coverChildrenWidth() - .childPadding(2) as Row - private val lockAllButton: ButtonWidget<*> = ButtonWidget() - .size(20) + .pos(3, 24) + .size(18) .overlay(RSBTextures.ALL_FOUR_SLOT_ICON) .onMousePressed { if (it == 0) { @@ -57,7 +49,8 @@ class SortingSettingWidget( } private val unlockAllButton: ButtonWidget<*> = ButtonWidget() - .size(20) + .pos(21, 24) + .size(18) .overlay(RSBTextures.NONE_FOUR_SLOT_ICON) .onMousePressed { if (it == 0) { @@ -83,16 +76,11 @@ class SortingSettingWidget( } init { - buttonRow.top(28) - .child(lockAllButton) + child(lockAllButton) .child(unlockAllButton) - - child(buttonRow) } override fun updateTabState() { - parentTabWidget.showExpanded = !parentTabWidget.showExpanded - panel.isSortingSettingTabOpened = parentTabWidget.showExpanded - settingPanel.updateTabState(1) + panel.openSortingSettings(parentTabWidget, !parentTabWidget.showExpanded) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt index 5293acc..d31ce07 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt @@ -27,6 +27,7 @@ class TabWidget( expandedWidget?.isEnabled = value field = value + markTooltipDirty() } var expandedWidget: ExpandedTabWidget? = null @@ -43,9 +44,10 @@ class TabWidget( field = value } var tabIcon: IDrawable? = null + var onToggle: ((Boolean) -> Unit)? = null init { - size(TAB_TEXTURE.width, TAB_TEXTURE.height).top({ tabOrder * 30.0 }, Unit.Measure.PIXEL) + size(TAB_TEXTURE.width, TAB_TEXTURE.height).top({ 4.0 + tabOrder * 30.0 }, Unit.Measure.PIXEL) when (expandDirection) { ExpandDirection.LEFT -> left(-TAB_TEXTURE.width + 4) @@ -57,12 +59,19 @@ class TabWidget( context.recipeViewerSettings.addExclusionArea(this) } + override fun dispose() { + if (isValid) + context.recipeViewerSettings.removeExclusionArea(this) + super.dispose() + } + override fun onMousePressed(mouseButton: Int): Interactable.Result { if (!isEnabled || expandedWidget == null) return Interactable.Result.STOP if (mouseButton == 0) { expandedWidget?.updateTabState() + onToggle?.invoke(showExpanded) Interactable.playButtonClickSound() return Interactable.Result.SUCCESS } @@ -95,4 +104,4 @@ class TabWidget( .drawAtZero(context, TAB_TEXTURE.width, TAB_TEXTURE.height, widgetTheme.getThemeOrDefault()) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TankInventoryControlWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TankInventoryControlWidget.kt new file mode 100644 index 0000000..9a9c69d --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TankInventoryControlWidget.kt @@ -0,0 +1,101 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.drawable.GuiDraw +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.TankUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraftforge.fluids.FluidStack + +class TankInventoryControlWidget( + private val slotSyncHandler: UpgradeSlotSH, + private val upgradeSlot: Int, + private val backpackWrapper: BackpackWrapper, + height: Int +) : Widget(), Interactable { + companion object { + const val WIDTH = 36 + private const val TANK_LEFT = 9 + private const val TANK_WIDTH = 18 + private const val OVERLAY_LEFT = TANK_LEFT + 1 + private const val OVERLAY_WIDTH = 16 + } + + init { + size(WIDTH, height) + tooltipAutoUpdate(true) + tooltipDynamic { tooltip -> + val wrapper = currentWrapper() + wrapper?.getFluid()?.let { tooltip.addLine(IKey.str(it.localizedName)) } + tooltip.addLine(IKey.str("${wrapper?.getFluid()?.amount ?: 0}/${wrapper?.getTankCapacity(backpackWrapper) ?: 0} mB")) + tooltip.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + val theme = widgetTheme.getThemeOrDefault() + val height = area.height + RSBTextures.BAR_BACKGROUND_TOP.draw(context, TANK_LEFT, 0, TANK_WIDTH, if (height < 36) height / 2 else 18, theme) + + var yOffset = 18 + repeat((height - 36).coerceAtLeast(0) / 18) { + RSBTextures.BAR_BACKGROUND_MIDDLE.draw(context, TANK_LEFT, yOffset, TANK_WIDTH, 18, theme) + yOffset += 18 + } + + RSBTextures.BAR_BACKGROUND_BOTTOM.draw( + context, + TANK_LEFT, + if (height < 36) height / 2 else yOffset, + TANK_WIDTH, + if (height < 36) height / 2 else 18, + theme + ) + + renderFluid(context, currentWrapper(), height) + + yOffset = 0 + repeat(height / 18) { + RSBTextures.TANK_OVERLAY.draw(context, OVERLAY_LEFT, yOffset, OVERLAY_WIDTH, 18, theme) + yOffset += 18 + } + } + + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (mouseButton != 0 && mouseButton != 1) { + return Interactable.Result.IGNORE + } + slotSyncHandler.syncToServer(UpgradeSlotSH.UPDATE_TANK_CLICK) {} + Interactable.playButtonClickSound() + return Interactable.Result.SUCCESS + } + + private fun currentWrapper(): TankUpgradeWrapper? = + backpackWrapper.upgradeItemStackHandler.inventory[upgradeSlot] + .getCapability(Capabilities.TANK_UPGRADE_CAPABILITY, null) + + private fun renderFluid(context: ModularGuiContext, wrapper: TankUpgradeWrapper?, height: Int) { + val fluid = wrapper?.getFluid() + if (fluid == null || fluid.amount <= 0) { + return + } + val displayLevel = ((height - 2) * (fluid.amount.toFloat() / wrapper.getTankCapacity(backpackWrapper))).toInt() + .coerceIn(1, height - 2) + GuiDraw.drawFluidTexture( + fluid, + (TANK_LEFT + 1).toFloat(), + (height - 1 - displayLevel).toFloat(), + OVERLAY_WIDTH.toFloat(), + displayLevel.toFloat(), + context.currentDrawingZ.toFloat() + ) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt index 089ae6a..0a8ec31 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt @@ -2,11 +2,9 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets import com.cleanroommc.modularui.api.value.ISyncOrValue import com.cleanroommc.modularui.api.widget.Interactable -import com.cleanroommc.modularui.drawable.GuiDraw import com.cleanroommc.modularui.drawable.UITexture import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetThemeEntry -import com.cleanroommc.modularui.utils.Color import com.cleanroommc.modularui.widget.Widget import com.cleanroommc.modularui.widgets.SlotGroupWidget import com.cleanroommc.retrosophisticatedbackpacks.Tags @@ -18,18 +16,16 @@ import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault import net.minecraft.item.ItemStack -class UpgradeSlotGroupWidget(panel: BackpackPanel, private val slotSize: Int) : SlotGroupWidget() { +class UpgradeSlotGroupWidget(private val panel: BackpackPanel, private val slotSize: Int) : SlotGroupWidget() { companion object { + private val GUI_CONTROLS = + UITexture.fullImage(Tags.MOD_ID, "gui/gui_controls.png") private val UPPER_TAB_TEXTURE = UITexture.builder().location(Tags.MOD_ID, "gui/gui_controls.png").imageSize(256, 256) - .xy(0, 0, 25, 5).build() - private val SLOT_SURROUNDING_TEXTURE = - UITexture.builder().location(Tags.MOD_ID, "gui/gui_controls.png").imageSize(256, 256) - .xy(0, 5, 25, 18).build() + .xy(0, 0, 26, 4).build() private val LOWER_TAB_TEXTURE = UITexture.builder().location(Tags.MOD_ID, "gui/gui_controls.png").imageSize(256, 256) - .xy(0, 199, 25, 5).build() - private val SLOT_HOVERING_COLOR = Color.withAlpha(Color.WHITE.main, 0x50) + .xy(0, 198, 25, 6).build() } val toggleWidgets: List @@ -51,18 +47,36 @@ class UpgradeSlotGroupWidget(panel: BackpackPanel, private val slotSize: Int) : context.recipeViewerSettings.addExclusionArea(this) } - override fun draw(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { - super.draw(context, widgetTheme) - var y = 5 - - UPPER_TAB_TEXTURE.draw(context, 0, 0, 25, 5, widgetTheme.getThemeOrDefault()) + override fun dispose() { + if (isValid) + context.recipeViewerSettings.removeExclusionArea(this) + super.dispose() + } - for (i in 0 until slotSize) { - SLOT_SURROUNDING_TEXTURE.draw(context, 0, y, 25, 18, widgetTheme.getThemeOrDefault()) - y += 18 + override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawBackground(context, widgetTheme) + + val heightWithoutBottom = 6 + slotSize * 16 + + UPPER_TAB_TEXTURE.draw(context, 0, 0, 26, 4, widgetTheme.getThemeOrDefault()) + GUI_CONTROLS.drawSubArea( + 0f, + 4f, + 25f, + (heightWithoutBottom - 4).toFloat(), + 0f, + 4f / 256f, + 25f / 256f, + heightWithoutBottom / 256f, + widgetTheme.getThemeOrDefault() + ) + LOWER_TAB_TEXTURE.draw(context, 0, heightWithoutBottom, 25, 6, widgetTheme.getThemeOrDefault()) + + for (slot in 0 until slotSize) { + if (panel.backpackWrapper.upgradeItemStackHandler.getStackInSlot(slot).isEmpty) { + RSBTextures.EMPTY_UPGRADE_SLOT.draw(context, 6, 6 + slot * 16, 16, 16, widgetTheme.getThemeOrDefault()) + } } - - LOWER_TAB_TEXTURE.draw(context, 0, y, 25, 5, widgetTheme.getThemeOrDefault()) } class UpgradeToggleWidget(private val panel: BackpackPanel, private val slotIndex: Int) : @@ -74,7 +88,22 @@ class UpgradeSlotGroupWidget(panel: BackpackPanel, private val slotSize: Int) : private val BACKGROUND_TAB_TEXTURE = UITexture.builder() .location(Tags.MOD_ID, "gui/gui_controls.png") .imageSize(256, 256) - .xy(0, 204, WIDTH, HEIGHT) + .xy(0, 204, 7, HEIGHT) + .build() + private val CONNECTED_BACKGROUND_TAB_TEXTURE = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(0, 205, 7, HEIGHT - 1) + .build() + private val SWITCH_BACKGROUND_TEXTURE = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(65, 0, 6, 12) + .build() + private val SWITCH_HOVERED_BACKGROUND_TEXTURE = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(71, 0, 6, 12) .build() } @@ -82,7 +111,7 @@ class UpgradeSlotGroupWidget(panel: BackpackPanel, private val slotSize: Int) : private var slotSyncHandler: UpgradeSlotSH? = null init { - size(WIDTH, HEIGHT).left(-4).top(slotIndex * 18 + 4) + size(WIDTH, HEIGHT).left(-4).top(slotIndex * 16 + 5) isEnabled = false val wrapper = getWrapper() @@ -117,7 +146,7 @@ class UpgradeSlotGroupWidget(panel: BackpackPanel, private val slotSize: Int) : super.drawOverlay(context, widgetTheme) if (isHovering) - GuiDraw.drawRect(4f, 4f, 4f, 10f, SLOT_HOVERING_COLOR) + SWITCH_HOVERED_BACKGROUND_TEXTURE.draw(context, 3, 3, 6, 12, widgetTheme.getThemeOrDefault()) if (isToggleEnabled) RSBTextures.TOGGLE_ENABLE_ICON.draw(context, 4, 4, 4, 10, widgetTheme.getThemeOrDefault()) @@ -128,7 +157,14 @@ class UpgradeSlotGroupWidget(panel: BackpackPanel, private val slotSize: Int) : override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { super.drawBackground(context, widgetTheme) - BACKGROUND_TAB_TEXTURE.draw(context, 0, 0, WIDTH, HEIGHT, widgetTheme.getThemeOrDefault()) + val previousHasSwitch = slotIndex > 0 && + panel.backpackWrapper.upgradeItemStackHandler.getStackInSlot(slotIndex - 1) + .getCapability(Capabilities.TOGGLEABLE_CAPABILITY, null) != null + if (previousHasSwitch) + CONNECTED_BACKGROUND_TAB_TEXTURE.draw(context, 0, 1, 7, HEIGHT - 1, widgetTheme.getThemeOrDefault()) + else + BACKGROUND_TAB_TEXTURE.draw(context, 0, 0, 7, HEIGHT, widgetTheme.getThemeOrDefault()) + SWITCH_BACKGROUND_TEXTURE.draw(context, 3, 3, 6, 12, widgetTheme.getThemeOrDefault()) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt index 36b8f66..7627eaf 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt @@ -12,14 +12,19 @@ import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.utils.Color import com.cleanroommc.modularui.utils.NumberFormat import com.cleanroommc.modularui.utils.Platform -import com.cleanroommc.modularui.widgets.slot.ItemSlot import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlot +import com.cleanroommc.retrosophisticatedbackpacks.handler.ClientGuiStashHandler +import com.cleanroommc.retrosophisticatedbackpacks.handler.NetworkHandler +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SStashToBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSH import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.DyeColorUtils import com.cleanroommc.retrosophisticatedbackpacks.util.Utils import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.Minecraft import net.minecraft.client.gui.Gui import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager @@ -31,7 +36,7 @@ import net.minecraft.util.text.TextFormatting import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly -class BackpackSlot(private val panel: BackpackPanel, private val wrapper: BackpackWrapper) : ItemSlot() { +class BackpackSlot(private val panel: BackpackPanel, private val wrapper: BackpackWrapper) : NoBackgroundItemSlot() { companion object { val DECIMAL_TWO: NumberFormat.Params = NumberFormat.AMOUNT_TEXT.copyToBuilder() .maxLength(2) @@ -40,11 +45,13 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa } private val isInSettingMode: Boolean - get() = panel.settingPanel.isPanelOpen + get() = panel.isSettingMode private val isInMemorySettingMode: Boolean get() = panel.isMemorySettingTabOpened private val isInSortSettingMode: Boolean get() = panel.isSortingSettingTabOpened + private val isInItemDisplaySettingMode: Boolean + get() = panel.isItemDisplaySettingTabOpened override fun buildTooltip(stack: ItemStack, tooltip: RichTooltip) { val memorizedStack = wrapper.getMemorizedStack(slot.slotIndex) @@ -97,40 +104,13 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa } override fun onMousePressed(mouseButton: Int): Interactable.Result = - if (isInMemorySettingMode) { - val isMemorySet = wrapper.isSlotMemorized(slot.slotIndex) - - if (isMemorySet && mouseButton == 1) { - wrapper.unsetMemoryStack(slot.slotIndex) - syncHandler.syncToServer(BackpackSlotSH.UPDATE_UNSET_MEMORY_STACK) - Utils.invalidateSortingContext() - Interactable.Result.SUCCESS - } else if (!isMemorySet && mouseButton == 0) { - wrapper.setMemoryStack(slot.slotIndex, panel.shouldMemorizeRespectNBT) - syncHandler.syncToServer(BackpackSlotSH.UPDATE_SET_MEMORY_STACK) { - it.writeBoolean(panel.shouldMemorizeRespectNBT) - } - Utils.invalidateSortingContext() - Interactable.Result.SUCCESS - } else Interactable.Result.STOP - } else if (isInSortSettingMode) { - val isSlotLocked = wrapper.isSlotLocked(slot.slotIndex) - - if (isSlotLocked && mouseButton == 1) { - wrapper.setSlotLocked(slot.slotIndex, false) - syncHandler.syncToServer(BackpackSlotSH.UPDATE_UNSET_SLOT_LOCK) - Utils.invalidateSortingContext() - Interactable.Result.SUCCESS - } else if (!isSlotLocked && mouseButton == 0) { - wrapper.setSlotLocked(slot.slotIndex, true) - syncHandler.syncToServer(BackpackSlotSH.UPDATE_SET_SLOT_LOCK) - Utils.invalidateSortingContext() - Interactable.Result.SUCCESS - } else Interactable.Result.STOP - } else if (isInSettingMode) { - Interactable.Result.STOP - } else { - super.onMousePressed(mouseButton) + when { + isInItemDisplaySettingMode -> handleItemDisplaySlotClick(mouseButton) + isInMemorySettingMode -> handleMemorySlotClick(mouseButton) + isInSortSettingMode -> handleSortSlotClick(mouseButton) + isInSettingMode -> Interactable.Result.STOP + mouseButton == 1 && handleStashClick() -> Interactable.Result.SUCCESS + else -> super.onMousePressed(mouseButton) } override fun onMouseRelease(mouseButton: Int): Boolean = @@ -138,40 +118,148 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa else super.onMouseRelease(mouseButton) override fun onMouseDrag(mouseButton: Int, timeSinceClick: Long) { - if (isInSettingMode) + if (isInMemorySettingMode) { + handleMemorySlotClick(mouseButton) + return + } + if (isInSortSettingMode) { + handleSortSlotClick(mouseButton) + return + } + if (isInItemDisplaySettingMode) { + handleItemDisplaySlotClick(mouseButton) + return + } + if (isInSettingMode) { return + } super.onMouseDrag(mouseButton, timeSinceClick) } + private fun handleMemorySlotClick(mouseButton: Int): Interactable.Result { + val isMemorySet = wrapper.isSlotMemorized(slot.slotIndex) + + return if (isMemorySet && mouseButton == 1) { + wrapper.unsetMemoryStack(slot.slotIndex) + syncHandler.syncToServer(BackpackSlotSH.UPDATE_UNSET_MEMORY_STACK) + Utils.invalidateSortingContext() + Interactable.Result.SUCCESS + } else if (!isMemorySet && mouseButton == 0) { + wrapper.setMemoryStack(slot.slotIndex, panel.shouldMemorizeRespectNBT) + syncHandler.syncToServer(BackpackSlotSH.UPDATE_SET_MEMORY_STACK) { + it.writeBoolean(panel.shouldMemorizeRespectNBT) + } + Utils.invalidateSortingContext() + Interactable.Result.SUCCESS + } else Interactable.Result.STOP + } + + private fun handleItemDisplaySlotClick(mouseButton: Int): Interactable.Result { + val slotIndex = slot.slotIndex + return when { + mouseButton == 0 && !wrapper.isItemDisplaySlotSelected(slotIndex) -> { + wrapper.selectItemDisplaySlot(slotIndex) + if (wrapper.isItemDisplaySlotSelected(slotIndex)) { + panel.setCurrentItemDisplaySelectedSlot(slotIndex) + panel.backpackSyncHandler.syncToServer(BackpackSH.UPDATE_ITEM_DISPLAY_SLOT) { + it.writeInt(slotIndex) + it.writeBoolean(true) + } + Interactable.Result.SUCCESS + } else Interactable.Result.STOP + } + + mouseButton == 1 && wrapper.isItemDisplaySlotSelected(slotIndex) -> { + wrapper.unselectItemDisplaySlot(slotIndex) + panel.setCurrentItemDisplaySelectedSlot(wrapper.getFirstItemDisplaySlot()) + panel.backpackSyncHandler.syncToServer(BackpackSH.UPDATE_ITEM_DISPLAY_SLOT) { + it.writeInt(slotIndex) + it.writeBoolean(false) + } + Interactable.Result.SUCCESS + } + + else -> Interactable.Result.STOP + } + } + + private fun handleSortSlotClick(mouseButton: Int): Interactable.Result { + val isSlotLocked = wrapper.isSlotLocked(slot.slotIndex) + + return if (isSlotLocked && mouseButton == 1) { + wrapper.setSlotLocked(slot.slotIndex, false) + syncHandler.syncToServer(BackpackSlotSH.UPDATE_UNSET_SLOT_LOCK) + Utils.invalidateSortingContext() + Interactable.Result.SUCCESS + } else if (!isSlotLocked && mouseButton == 0) { + wrapper.setSlotLocked(slot.slotIndex, true) + syncHandler.syncToServer(BackpackSlotSH.UPDATE_SET_SLOT_LOCK) + Utils.invalidateSortingContext() + Interactable.Result.SUCCESS + } else Interactable.Result.STOP + } + @SideOnly(Side.CLIENT) override fun draw(context: ModularGuiContext?, widgetThemeEntry: WidgetThemeEntry<*>?) { context?.let { val widgetTheme = widgetThemeEntry?.theme ?: WidgetTheme.getDefault().theme - if (wrapper.isSlotLocked(slot.slotIndex)) - drawLockedSlot(it, widgetTheme) - - if (isInSettingMode) drawSettingStack(context, widgetTheme) - else { + if (isInSettingMode) { + drawSettingStack(context, widgetTheme) + drawSettingOverlays(it, widgetTheme) + } else { val slot = slot as? ModularBackpackSlot ?: return val memoryStack = slot.getMemoryStack() + if (wrapper.isSlotLocked(slot.slotIndex)) + drawLockedSlot(it, widgetTheme) + super.draw(context, widgetThemeEntry) - if (slot.stack.isEmpty && !memoryStack.isEmpty) + if (slot.stack.isEmpty && !memoryStack.isEmpty) { drawMemoryStack(memoryStack, context, widgetTheme) + drawMemorizedSlotOverlay(context, widgetTheme) + } + drawStashSign() } } } + private fun handleStashClick(): Boolean { + val player = Minecraft.getMinecraft().player ?: return false + val carried = player.inventory.itemStack + if (carried.isEmpty) { + return false + } + val action = ClientGuiStashHandler.getStashActionForSlot(player, slot, carried) ?: return false + NetworkHandler.INSTANCE.sendToServer(C2SStashToBackpackPacket(slot.slotNumber, action)) + return true + } + + @SideOnly(Side.CLIENT) + private fun drawStashSign() { + val player = Minecraft.getMinecraft().player ?: return + val carried = player.inventory.itemStack + if (carried.isEmpty) { + return + } + val (sign, result) = ClientGuiStashHandler.getStashResultForSlot(player, slot, carried) ?: return + Minecraft.getMinecraft().fontRenderer.drawStringWithShadow( + sign, + if (sign == "+") 10f else 1f, + if (sign == "+") 8f else 0f, + ClientGuiStashHandler.color(result) + ) + } + @SideOnly(Side.CLIENT) private fun drawSettingStack(context: ModularGuiContext, widgetTheme: WidgetTheme) { val slot = slot as? ModularBackpackSlot ?: return val memoryStack = slot.getMemoryStack() val guiScreen = screen.screenWrapper.guiScreen check(guiScreen is GuiContainer) { "The gui must be an instance of GuiContainer if it contains slots!" } - val guiContainer = guiScreen as GuiContainer + val guiContainer = guiScreen val renderItem = (guiScreen as GuiScreenAccessor).itemRender // makes sure items of different layers don't interfere with each other visually @@ -199,11 +287,6 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa NEAAnimationHandler.endHoverScale() } - if (!memoryStack.isEmpty) { - GlStateManager.depthFunc(516) - Gui.drawRect(1, 1, 17, 17, Color.argb(139, 139, 139, 128)) - GlStateManager.depthFunc(515) - } RenderHelper.enableStandardItemLighting() GlStateManager.disableLighting() @@ -233,11 +316,6 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa renderItem.renderItemIntoGUI(itemstack, 1, 1) Platform.endDrawItem() - if (!memoryStack.isEmpty) { - GlStateManager.depthFunc(516) - Gui.drawRect(1, 1, 17, 17, Color.argb(139, 139, 139, 128)) - GlStateManager.depthFunc(515) - } RenderHelper.enableStandardItemLighting() GlStateManager.disableLighting() @@ -245,6 +323,25 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa renderItem.zLevel = 0f } + @SideOnly(Side.CLIENT) + private fun drawSettingOverlays(context: ModularGuiContext, widgetTheme: WidgetTheme) { + if (wrapper.isSlotLocked(slot.slotIndex)) + drawLockedSlot(context, widgetTheme) + if (wrapper.isSlotMemorized(slot.slotIndex)) + drawMemorizedSlotOverlay(context, widgetTheme) + if (wrapper.isItemDisplaySlotSelected(slot.slotIndex)) + drawItemDisplayOverlay(context, widgetTheme) + } + + @SideOnly(Side.CLIENT) + private fun drawMemorizedSlotOverlay(context: ModularGuiContext, widgetTheme: WidgetTheme) { + GlStateManager.disableDepth() + GlStateManager.enableBlend() + RSBTextures.MEMORIZED_SLOT_OVERLAY.draw(context, 1, 1, 16, 16, widgetTheme) + GlStateManager.disableBlend() + GlStateManager.enableDepth() + } + @SideOnly(Side.CLIENT) private fun drawLockedSlot(context: ModularGuiContext, widgetTheme: WidgetTheme) { RSBTextures.NO_SORT_ICON.draw(context, 1, 1, 16, 16, widgetTheme) @@ -252,4 +349,19 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa Gui.drawRect(1, 1, 17, 17, Color.argb(139, 139, 139, 128)) GlStateManager.depthFunc(515) } + + @SideOnly(Side.CLIENT) + private fun drawItemDisplayOverlay(context: ModularGuiContext, widgetTheme: WidgetTheme) { + val color = DyeColorUtils.colorValue(wrapper.itemDisplayColor) + GlStateManager.disableDepth() + GlStateManager.enableBlend() + Gui.drawRect(1, 1, 17, 17, color and 0x00FFFFFF or (80 shl 24)) + if (panel.currentItemDisplaySelectedSlot == slot.slotIndex) { + GlStateManager.colorMask(true, true, true, false) + RSBTextures.SLOT_SELECTION.draw(context, -3, -3, 24, 24, widgetTheme) + GlStateManager.colorMask(true, true, true, true) + } + GlStateManager.disableBlend() + GlStateManager.enableDepth() + } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt new file mode 100644 index 0000000..b2234e6 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt @@ -0,0 +1,10 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot + +import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.widgets.slot.ItemSlot + +open class NoBackgroundItemSlot : ItemSlot() { + init { + background(IDrawable.EMPTY) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt index 472d496..f236917 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt @@ -214,9 +214,11 @@ class AdvancedFilterWidget( slotGroup.disableSortButtons() filterSlots = mutableListOf() - for (i in 0 until 16) { + val filterSlotCount = filterableWrapper.filterItems.slots + val slotsInRow = minOf(4, filterSlotCount) + for (i in 0 until filterSlotCount) { val slot = - PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % 4 * 18, i / 4 * 18) as PhantomItemSlot + PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot filterSlots.add(slot) slotGroup.child(slot) @@ -391,4 +393,4 @@ class AdvancedFilterWidget( } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt new file mode 100644 index 0000000..da98804 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt @@ -0,0 +1,91 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.drawable.GuiDraw +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.modularui.widgets.SlotGroupWidget +import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AnvilUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack + +class AnvilUpgradeWidget( + slotIndex: Int, + wrapper: AnvilUpgradeWrapper, + stack: ItemStack +) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 5, stack, wrapper.settingsLangKey, width = 103) { + init { + size(103, 92) + child(AnvilNameField().pos(5, 25).size(90, 15)) + val slots = SlotGroupWidget().name("anvil_$slotIndex").disableSortButtons() + slots.size(67, 18).pos(4, 43) + slots.child(NoBackgroundItemSlot().syncHandler("anvil_$slotIndex", 0).pos(0, 0)) + slots.child(NoBackgroundItemSlot().syncHandler("anvil_$slotIndex", 1).pos(49, 0)) + child(slots) + child(resultButton().pos(80, 43)) + child(shiftClickButton().pos(5, 68)) + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + RSBTextures.SLOT_BACKGROUND.draw(context, 4, 43, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 53, 43, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 80, 43, 18, 18, widgetTheme.theme) + RSBTextures.ADD_ICON.draw(context, 29, 45, 13, 13, widgetTheme.theme) + RSBTextures.DOWN_ARROW_ICON.draw(context, 68, 45, 12, 12, widgetTheme.theme) + GuiDraw.drawText("Cost: ${wrapper.maximumCost}", 5f, 62f, 0.75f, 0x404040, false) + super.draw(context, widgetTheme) + } + + private fun resultButton(): ButtonWidget<*> = + ButtonWidget() + .size(18) + .onMousePressed { + if (it != 0) false else { + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_TAKE_RESULT) {} + true + } + } + .tooltipDynamic { + val player = context.mc.player + val result = wrapper.updateRepairOutput(player, player.world) + if (result.isEmpty) it.addLine(IKey.lang("gui.anvil_no_result".asTranslationKey())) + else it.addLine(IKey.str(result.displayName)) + it.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + private fun shiftClickButton(): ButtonWidget<*> = + ButtonWidget() + .size(20) + .overlay(if (wrapper.shouldShiftClickIntoStorage) RSBTextures.CHECK_ICON else RSBTextures.CROSS_ICON) + .onMousePressed { + if (it != 0) false else { + wrapper.shouldShiftClickIntoStorage = !wrapper.shouldShiftClickIntoStorage + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_SHIFT_CLICK) {} + true + } + } + .tooltipStatic { + it.addLine(IKey.lang("gui.anvil_shift_click_storage".asTranslationKey())) + it.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + private inner class AnvilNameField : TextFieldWidget() { + init { + setText(wrapper.itemName) + setMaxLength(40) + } + + override fun onRemoveFocus(context: ModularGuiContext) { + super.onRemoveFocus(context) + wrapper.itemName = text + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_ITEM_NAME) { it.writeString(wrapper.itemName) } + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt index 92954e0..68594b4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt @@ -48,9 +48,11 @@ class BasicFilterWidget( slotGroup.disableSortButtons() filterSlots = mutableListOf() - for (i in 0 until 9) { + val filterSlotCount = filterableWrapper.filterItems.slots + val slotsInRow = minOf(3, filterSlotCount) + for (i in 0 until filterSlotCount) { val slot = - PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % 3 * 18, i / 3 * 18) as PhantomItemSlot + PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot filterSlots.add(slot) slotGroup.child(slot) @@ -65,4 +67,4 @@ class BasicFilterWidget( slotSyncHandler = syncHandler return slotSyncHandler != null } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt new file mode 100644 index 0000000..866fafe --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt @@ -0,0 +1,70 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.drawable.GuiDraw +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widgets.SlotGroupWidget +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.BatteryUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot +import net.minecraft.item.ItemStack +import net.minecraftforge.items.IItemHandler + +class BatteryUpgradeWidget( + slotIndex: Int, + wrapper: BatteryUpgradeWrapper, + stack: ItemStack, + private val backpackWrapper: BackpackWrapper +) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 3, stack, wrapper.settingsLangKey, width = 48) { + init { + size(48, 66) + val slots = SlotGroupWidget().name("battery_$slotIndex").disableSortButtons() + slots.size(42, 18).pos(3, 42) + slots.child(NoBackgroundItemSlot().syncHandler("battery_$slotIndex", 0).pos(0, 0)) + slots.child(NoBackgroundItemSlot().syncHandler("battery_$slotIndex", 1).pos(21, 0)) + child(slots) + } + + override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + super.drawBackground(context, widgetTheme) + RSBTextures.SLOT_BACKGROUND.draw(context, 3, 42, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 24, 42, 18, 18, widgetTheme.theme) + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + GuiDraw.drawText(energyText(wrapper), 4f, 26f, 0.5f, 0x404040, false) + super.draw(context, widgetTheme) + } + + override fun drawOverlay(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + super.drawOverlay(context, widgetTheme) + drawEmptySlotIcons(context, widgetTheme) + } + + private fun drawEmptySlotIcons(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + val inventory = wrapper.getInventory() + drawEmptySlotIcon(context, widgetTheme, inventory, 0, 4, 43, true) + drawEmptySlotIcon(context, widgetTheme, inventory, 1, 25, 43, false) + } + + private fun drawEmptySlotIcon( + context: ModularGuiContext, + widgetTheme: WidgetThemeEntry<*>, + inventory: IItemHandler, + slot: Int, + x: Int, + y: Int, + input: Boolean + ) { + if (!inventory.getStackInSlot(slot).isEmpty) { + return + } + (if (input) RSBTextures.EMPTY_BATTERY_INPUT_SLOT else RSBTextures.EMPTY_BATTERY_OUTPUT_SLOT) + .draw(context, x, y, 16, 16, widgetTheme.theme) + } + + private fun energyText(wrapper: BatteryUpgradeWrapper): String = + "${wrapper.energyStored}/${wrapper.getMaxEnergyStored(backpackWrapper)} FE" +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt new file mode 100644 index 0000000..24503d1 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt @@ -0,0 +1,65 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedCompactingUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CompactingUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack + +class CompactingUpgradeWidget(slotIndex: Int, wrapper: CompactingUpgradeWrapper, stack: ItemStack) : + BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + init { + startingRow + .height(20) + .child(createCompactModeButton(wrapper.compactNonUncraftable)) + .child(createWorkInGuiButton(wrapper.shouldWorkInGui) { + wrapper.shouldWorkInGui = !wrapper.shouldWorkInGui + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_WORK_IN_GUI) {} + }) + } + + private fun createCompactModeButton(compactNonUncraftable: Boolean): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { + wrapper.compactNonUncraftable = !wrapper.compactNonUncraftable + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_NON_UNCRAFTABLE) {} + } +} + +class AdvancedCompactingUpgradeWidget(slotIndex: Int, wrapper: AdvancedCompactingUpgradeWrapper, stack: ItemStack) : + AdvancedExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + init { + startingRow + .height(20) + .child(createCompactModeButton(wrapper.compactNonUncraftable)) + .child(createWorkInGuiButton(wrapper.shouldWorkInGui) { + wrapper.shouldWorkInGui = !wrapper.shouldWorkInGui + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_WORK_IN_GUI) {} + }) + } + + private fun createCompactModeButton(compactNonUncraftable: Boolean): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { + wrapper.compactNonUncraftable = !wrapper.compactNonUncraftable + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_NON_UNCRAFTABLE) {} + } +} + +private val COMPACT_MODE_VARIANTS = + listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.compact_uncraftable_only".asTranslationKey()), RSBTextures.CHECK_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.compact_any_recipe".asTranslationKey()), RSBTextures.CROSS_ICON), + ) + +private fun createWorkInGuiButton(shouldWorkInGui: Boolean, toggle: () -> Unit): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(WORK_IN_GUI_VARIANTS, if (shouldWorkInGui) 1 else 0) { + toggle() + } + +private val WORK_IN_GUI_VARIANTS = + listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), + ) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt new file mode 100644 index 0000000..ee5b620 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt @@ -0,0 +1,84 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.modularui.widgets.SlotGroupWidget +import com.cleanroommc.modularui.widgets.slot.ItemSlot +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RepeatMode +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack + +class JukeboxUpgradeWidget(slotIndex: Int, wrapper: JukeboxUpgradeWrapper, stack: ItemStack, private val slots: Int) : + ExpandedUpgradeTabWidget(slotIndex, wrapper, if (slots > 4) 5 else 4, stack, wrapper.settingsLangKey, width = if (slots > 4) 112 else 80) { + companion object { + private const val SLOT_SIZE = 18 + } + + init { + size(if (slots > 4) 112 else 80, if (slots > 4) 130 else 94) + + child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_PLAY, "gui.jukebox_play".asTranslationKey(), RSBTextures.CHECK_ICON).pos(8, 28)) + child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_STOP, "gui.jukebox_stop".asTranslationKey(), RSBTextures.CROSS_ICON).pos(30, 28)) + child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_PREVIOUS, "gui.jukebox_previous".asTranslationKey(), RSBTextures.LEFT_ARROW_ICON).pos(52, 28)) + child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_NEXT, "gui.jukebox_next".asTranslationKey(), RSBTextures.SOLID_UP_ARROW_ICON).pos(74, 28)) + child(createShuffleButton().pos(8, 50)) + child(createRepeatButton().pos(30, 50)) + + val discs = SlotGroupWidget().name("jukebox_discs_$slotIndex").disableSortButtons() + discs.flex().coverChildren().leftRel(0.5F).top(if (slots > 4) 74 else 72) + repeat(slots) { + discs.child(ItemSlot().syncHandler("jukebox_discs_$slotIndex", it).pos(it % 4 * SLOT_SIZE, it / 4 * SLOT_SIZE)) + } + child(discs) + } + + override fun onWrapperChange(after: JukeboxUpgradeWrapper) { + super.onWrapperChange(after) + } + + private fun createCommandButton(syncId: Int, langKey: String, icon: com.cleanroommc.modularui.api.drawable.IDrawable): ButtonWidget<*> = + ButtonWidget() + .size(20) + .overlay(icon) + .onMousePressed { + if (it != 0) { + false + } else { + slotSyncHandler?.syncToServer(syncId) {} + true + } + } + .tooltipStatic { + it.addLine(IKey.lang(langKey)).pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + + private fun createShuffleButton(): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(SHUFFLE_VARIANTS, if (wrapper.shuffleEnabled) 1 else 0) { + wrapper.toggleShuffle() + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_JUKEBOX_SHUFFLE) {} + } + + private fun createRepeatButton(): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(REPEAT_VARIANTS, wrapper.repeatMode.ordinal) { + wrapper.repeatMode = RepeatMode.entries[it] + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_JUKEBOX_REPEAT_MODE) { + it.writeEnumValue(wrapper.repeatMode) + } + } +} + +private val SHUFFLE_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_shuffle_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_shuffle_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), +) + +private val REPEAT_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_all".asTranslationKey()), RSBTextures.IN_OUT_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_one".asTranslationKey()), RSBTextures.SMALL_1_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_no".asTranslationKey()), RSBTextures.CROSS_ICON), +) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt new file mode 100644 index 0000000..d86b1cc --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt @@ -0,0 +1,104 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.drawable.GuiDraw +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.PumpUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraft.item.ItemStack + +open class PumpUpgradeWidget( + slotIndex: Int, + wrapper: PumpUpgradeWrapper, + stack: ItemStack +) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 3, stack, wrapper.settingsLangKey, width = 48) { + init { + size(48, 50) + child(toggleButton({ wrapper.isInput }, RSBTextures.PUMP_INPUT_ICON, RSBTextures.PUMP_OUTPUT_ICON, "gui.pump_input".asTranslationKey()) { + wrapper.isInput = !wrapper.isInput + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_INPUT) { it.writeBoolean(wrapper.isInput) } + }.pos(3, 24)) + } + + protected fun toggleButton( + state: () -> Boolean, + enabledIcon: IDrawable, + disabledIcon: IDrawable, + tooltip: String, + action: () -> Unit + ): ButtonWidget<*> = + ButtonWidget() + .size(20) + .overlay(if (state()) enabledIcon else disabledIcon) + .onMousePressed { + if (it != 0) false else { + action() + true + } + } + .tooltipStatic { it.addLine(IKey.lang(tooltip)).pos(RichTooltip.Pos.NEXT_TO_MOUSE) } +} + +class AdvancedPumpUpgradeWidget(slotIndex: Int, wrapper: PumpUpgradeWrapper, stack: ItemStack) : + PumpUpgradeWidget(slotIndex, wrapper, stack) { + init { + size(84, 82) + width(84) + child(toggleButton({ wrapper.interactWithFluidHandlers }, RSBTextures.PUMP_FLUID_HANDLER_ICON, RSBTextures.PUMP_NO_FLUID_HANDLER_ICON, "gui.pump_fluid_handlers".asTranslationKey()) { + wrapper.interactWithFluidHandlers = !wrapper.interactWithFluidHandlers + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_FLUID_HANDLERS) {} + }.pos(21, 24)) + child(toggleButton({ wrapper.interactWithWorld }, RSBTextures.PUMP_WORLD_ICON, RSBTextures.PUMP_NO_WORLD_ICON, "gui.pump_world".asTranslationKey()) { + wrapper.interactWithWorld = !wrapper.interactWithWorld + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_WORLD) {} + }.pos(39, 24)) + child(toggleButton({ wrapper.interactWithHand }, RSBTextures.PUMP_HAND_ICON, RSBTextures.PUMP_NO_HAND_ICON, "gui.pump_hand".asTranslationKey()) { + wrapper.interactWithHand = !wrapper.interactWithHand + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_HAND) {} + }.pos(57, 24)) + for (slot in wrapper.fluidFilters.indices) { + child(FluidFilterSlotWidget(slot, wrapper).pos(3 + slot * 18, 50)) + } + } + + private inner class FluidFilterSlotWidget( + private val filterSlot: Int, + private val pumpWrapper: PumpUpgradeWrapper + ) : Widget(), Interactable { + init { + size(18) + tooltipDynamic { + val fluid = pumpWrapper.fluidFilters.getOrNull(filterSlot) + it.addLine(if (fluid == null) IKey.lang("gui.none".asTranslationKey()) else IKey.str(fluid.localizedName)) + it.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + }.tooltipAutoUpdate(true) + } + + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (mouseButton != 0 && mouseButton != 1) { + return Interactable.Result.IGNORE + } + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_FLUID_FILTER) { it.writeInt(filterSlot) } + Interactable.playButtonClickSound() + return Interactable.Result.SUCCESS + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + RSBTextures.SLOT_BACKGROUND.draw(context, 0, 0, 18, 18, widgetTheme.getThemeOrDefault()) + val fluid = pumpWrapper.fluidFilters.getOrNull(filterSlot) + if (fluid != null) { + GuiDraw.drawFluidTexture(fluid, 1f, 1f, 16f, 16f, context.currentDrawingZ.toFloat()) + } + super.draw(context, widgetTheme) + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt new file mode 100644 index 0000000..48760f0 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt @@ -0,0 +1,67 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.drawable.ItemDrawable +import com.cleanroommc.modularui.widgets.layout.Row +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedRefillUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RefillUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.init.Items +import net.minecraft.item.ItemStack + +class RefillUpgradeWidget(slotIndex: Int, wrapper: RefillUpgradeWrapper, stack: ItemStack) : + BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + init { + startingRow.height(0) + } +} + +class AdvancedRefillUpgradeWidget(slotIndex: Int, wrapper: AdvancedRefillUpgradeWrapper, stack: ItemStack) : + BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey, width = 130) { + init { + startingRow + .height(42) + .childPadding(1) + .child(targetRow(wrapper, 0, 6)) + .child(targetRow(wrapper, 6, 12)) + } + + private fun targetRow(wrapper: AdvancedRefillUpgradeWrapper, start: Int, end: Int): Row { + val row = Row().height(20).childPadding(1) as Row + for (filterSlot in start until end) { + row.child(createTargetButton(wrapper, filterSlot)) + } + return row + } + + private fun createTargetButton(wrapper: AdvancedRefillUpgradeWrapper, filterSlot: Int): CyclicVariantButtonWidget = + CyclicVariantButtonWidget( + RefillUpgradeWrapper.TargetSlot.entries.map { CyclicVariantButtonWidget.Variant(it.langKey(), it.icon()) }, + wrapper.getTargetSlot(filterSlot).ordinal, + iconOffset = 4, + iconSize = 12, + buttonWidth = 18, + buttonHeight = 18 + ) { index -> + wrapper.setTargetSlot(filterSlot, RefillUpgradeWrapper.TargetSlot.entries[index]) + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_REFILL_TARGET_SLOT) { + it.writeInt(filterSlot) + it.writeEnumValue(RefillUpgradeWrapper.TargetSlot.entries[index]) + } + } +} + +private fun RefillUpgradeWrapper.TargetSlot.langKey(): IKey = + IKey.lang("gui.refill_target_${name.lowercase()}".asTranslationKey()) + +private fun RefillUpgradeWrapper.TargetSlot.icon(): IDrawable = + when (this) { + RefillUpgradeWrapper.TargetSlot.ANY -> RSBTextures.SMALL_A_ICON + RefillUpgradeWrapper.TargetSlot.MAIN_HAND -> RSBTextures.SMALL_M_ICON + RefillUpgradeWrapper.TargetSlot.OFF_HAND -> RSBTextures.SMALL_O_ICON + else -> ItemDrawable(ItemStack(Items.PAPER, 1, ordinal - RefillUpgradeWrapper.TargetSlot.HOTBAR_1.ordinal + 1)) + } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt new file mode 100644 index 0000000..05c97d0 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt @@ -0,0 +1,64 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widgets.SlotGroupWidget +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.TankUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot +import net.minecraft.item.ItemStack +import net.minecraftforge.items.IItemHandler + +class TankUpgradeWidget(slotIndex: Int, wrapper: TankUpgradeWrapper, stack: ItemStack) : + ExpandedUpgradeTabWidget(slotIndex, wrapper, 3, stack, wrapper.settingsLangKey, width = 48) { + init { + size(48, 80) + + val slots = SlotGroupWidget().name("tank_$slotIndex").disableSortButtons() + slots.size(42, 50).pos(3, 24) + slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 0).pos(0, 0)) + slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 1).pos(21, 0)) + slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 2).pos(0, 32)) + slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 3).pos(21, 32)) + child(slots) + } + + override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + super.drawBackground(context, widgetTheme) + RSBTextures.SLOT_BACKGROUND.draw(context, 3, 24, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 24, 24, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 3, 56, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 24, 56, 18, 18, widgetTheme.theme) + RSBTextures.TANK_ARROW.draw(context, 4, 45, 15, 8, widgetTheme.theme) + RSBTextures.TANK_ARROW.draw(context, 25, 45, 15, 8, widgetTheme.theme) + } + + override fun drawOverlay(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + super.drawOverlay(context, widgetTheme) + drawEmptySlotIcons(context, widgetTheme) + } + + private fun drawEmptySlotIcons(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + val inventory = wrapper.getInventory() + drawEmptySlotIcon(context, widgetTheme, inventory, 0, 4, 25, true) + drawEmptySlotIcon(context, widgetTheme, inventory, 1, 25, 25, false) + drawEmptySlotIcon(context, widgetTheme, inventory, 2, 4, 57, true) + drawEmptySlotIcon(context, widgetTheme, inventory, 3, 25, 57, false) + } + + private fun drawEmptySlotIcon( + context: ModularGuiContext, + widgetTheme: WidgetThemeEntry<*>, + inventory: IItemHandler, + slot: Int, + x: Int, + y: Int, + input: Boolean + ) { + if (!inventory.getStackInSlot(slot).isEmpty) { + return + } + (if (input) RSBTextures.EMPTY_TANK_INPUT_SLOT else RSBTextures.EMPTY_TANK_OUTPUT_SLOT) + .draw(context, x, y, 16, 16, widgetTheme.theme) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt new file mode 100644 index 0000000..4eac723 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt @@ -0,0 +1,51 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedToolSwapperUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.ToolSwapMode +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack + +class AdvancedToolSwapperUpgradeWidget(slotIndex: Int, wrapper: AdvancedToolSwapperUpgradeWrapper, stack: ItemStack) : + BasicExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + coveredTabSize = 4 + ) { + init { + startingRow + .height(20) + .child(createSwapWeaponButton()) + .child(createToolSwapModeButton()) + } + + private fun createSwapWeaponButton(): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(SWAP_WEAPON_VARIANTS, if (wrapper.shouldSwapWeapon) 1 else 0) { + wrapper.shouldSwapWeapon = !wrapper.shouldSwapWeapon + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_TOOL_SWAPPER_SWAP_WEAPON) {} + } + + private fun createToolSwapModeButton(): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(TOOL_SWAP_MODE_VARIANTS, wrapper.toolSwapMode.ordinal) { + wrapper.toolSwapMode = ToolSwapMode.entries[it] + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_TOOL_SWAPPER_MODE) { + it.writeEnumValue(wrapper.toolSwapMode) + } + } +} + +private val SWAP_WEAPON_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_swap_weapon_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_swap_weapon_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), +) + +private val TOOL_SWAP_MODE_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_any".asTranslationKey()), RSBTextures.IN_OUT_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_only_tools".asTranslationKey()), RSBTextures.SOLID_UP_ARROW_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_no_swap".asTranslationKey()), RSBTextures.CROSS_ICON), +) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt new file mode 100644 index 0000000..d17634d --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt @@ -0,0 +1,71 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedVoidUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidType +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack + +class VoidUpgradeWidget(slotIndex: Int, wrapper: VoidUpgradeWrapper, stack: ItemStack) : + BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + init { + startingRow + .height(20) + .child(createVoidTypeButton(wrapper.voidType)) + .child(createWorkInGuiButton(wrapper.shouldWorkInGui) { + wrapper.shouldWorkInGui = !wrapper.shouldWorkInGui + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_WORK_IN_GUI) {} + }) + } + + private fun createVoidTypeButton(current: VoidType): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(VOID_TYPE_VARIANTS, current.ordinal) { index -> + wrapper.voidType = VoidType.entries[index] + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_TYPE) { + it.writeEnumValue(VoidType.entries[index]) + } + } +} + +class AdvancedVoidUpgradeWidget(slotIndex: Int, wrapper: AdvancedVoidUpgradeWrapper, stack: ItemStack) : + AdvancedExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + init { + startingRow + .height(20) + .child(createVoidTypeButton(wrapper.voidType)) + .child(createWorkInGuiButton(wrapper.shouldWorkInGui) { + wrapper.shouldWorkInGui = !wrapper.shouldWorkInGui + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_WORK_IN_GUI) {} + }) + } + + private fun createVoidTypeButton(current: VoidType): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(VOID_TYPE_VARIANTS, current.ordinal) { index -> + wrapper.voidType = VoidType.entries[index] + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_TYPE) { + it.writeEnumValue(VoidType.entries[index]) + } + } +} + +private val VOID_TYPE_VARIANTS = + listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.void_always".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.void_slot_overflow".asTranslationKey()), RSBTextures.IN_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.void_storage_overflow".asTranslationKey()), RSBTextures.IN_OUT_ICON), + ) + +private fun createWorkInGuiButton(shouldWorkInGui: Boolean, toggle: () -> Unit): CyclicVariantButtonWidget = + CyclicVariantButtonWidget(WORK_IN_GUI_VARIANTS, if (shouldWorkInGui) 1 else 0) { + toggle() + } + +private val WORK_IN_GUI_VARIANTS = + listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), + ) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt index 513e771..91df5eb 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.common.gui import com.cleanroommc.bogosorter.api.ISlot import com.cleanroommc.bogosorter.api.ISortingContextBuilder import com.cleanroommc.modularui.ModularUI +import com.cleanroommc.modularui.factory.TileEntityGuiFactory import com.cleanroommc.modularui.screen.ModularContainer import com.cleanroommc.modularui.utils.Platform import com.cleanroommc.modularui.widgets.slot.ModularSlot @@ -19,11 +20,19 @@ import net.minecraft.inventory.Container import net.minecraft.inventory.IInventory import net.minecraft.item.ItemStack import net.minecraft.item.crafting.CraftingManager +import net.minecraft.network.play.server.SPacketSetSlot +import net.minecraft.util.math.BlockPos import net.minecraftforge.fml.common.Optional import net.minecraftforge.items.ItemHandlerHelper import kotlin.math.min -class BackpackContainer(private val wrapper: BackpackWrapper, private val backpackSlotIndex: Int?) : +class BackpackContainer( + val backpackWrapper: BackpackWrapper, + private val backpackSlotIndex: Int?, + private val backpackInventoryType: PlayerInventoryGuiData.InventoryType? = null, + private val backpackSourceSlotIndex: Int? = backpackSlotIndex, + private val tilePos: BlockPos? = null +) : ModularContainer() { companion object { private val DROP_TO_WORLD: Int = -999 @@ -31,6 +40,24 @@ class BackpackContainer(private val wrapper: BackpackWrapper, private val backpa private const val RIGHT_MOUSE: Int = 1 } + private val wrapper: BackpackWrapper + get() = backpackWrapper + + fun reopenBackpackGui(player: EntityPlayerMP) { + val carriedStack = player.inventory.itemStack.copy() + player.inventory.itemStack = ItemStack.EMPTY + try { + when { + tilePos != null -> TileEntityGuiFactory.INSTANCE.open(player, tilePos) + backpackInventoryType != null && backpackSourceSlotIndex != null -> + PlayerInventoryGuiFactory.open(player, backpackInventoryType, backpackSourceSlotIndex) + } + } finally { + player.inventory.itemStack = carriedStack + player.connection.sendPacket(SPacketSetSlot(-1, -1, carriedStack)) + } + } + /** * Internal hash table used to store wrapped crafting matrices. Intended for use alongside craftingSlotInstances, to connect an instance of wrapper and slot together. */ @@ -67,87 +94,92 @@ class BackpackContainer(private val wrapper: BackpackWrapper, private val backpa } override fun slotClick(slotId: Int, mouseButton: Int, clickTypeIn: ClickType, player: EntityPlayer): ItemStack { - val playerInventory = player.inventory - val heldStack = playerInventory.itemStack - - if (clickTypeIn == ClickType.PICKUP && - (mouseButton == LEFT_MOUSE || mouseButton == RIGHT_MOUSE) && - (slotId != DROP_TO_WORLD && slotId >= 0) - ) { - val clickedSlot = getSlot(slotId) - val slotStack = clickedSlot.stack - - if (clickedSlot is ModularBackpackSlot && !slotStack.isEmpty && heldStack.isEmpty) { - val s = min(slotStack.count, clickedSlot.getItemStackLimit(slotStack)) - val toRemove = if (mouseButton == LEFT_MOUSE) s else (s + 1) / 2 - playerInventory.itemStack = slotStack.splitStack(toRemove) - clickedSlot.putStack(slotStack) - clickedSlot.onTake(player, playerInventory.itemStack) - clickedSlot.onSlotChanged() - detectAndSendChanges() - return ItemStack.EMPTY - } - } else if (clickTypeIn == ClickType.PICKUP_ALL && slotId >= 0) { - val clickedSlot = getSlot(slotId) - val slotStack = clickedSlot.stack - val maxStackSize = clickedSlot.getItemStackLimit(slotStack) - - if (!heldStack.isEmpty && - (clickedSlot == null || !clickedSlot.hasStack || !clickedSlot.canTakeStack(player)) + backpackWrapper.isGuiInteractionInProgress = true + try { + val playerInventory = player.inventory + val heldStack = playerInventory.itemStack + + if (clickTypeIn == ClickType.PICKUP && + (mouseButton == LEFT_MOUSE || mouseButton == RIGHT_MOUSE) && + (slotId != DROP_TO_WORLD && slotId >= 0) ) { - val i = if (mouseButton == 0) 0 else inventorySlots.size - 1 - val j = if (mouseButton == 0) 1 else -1 + val clickedSlot = getSlot(slotId) + val slotStack = clickedSlot.stack + + if (clickedSlot is ModularBackpackSlot && !slotStack.isEmpty && heldStack.isEmpty) { + val s = min(slotStack.count, clickedSlot.getItemStackLimit(slotStack)) + val toRemove = if (mouseButton == LEFT_MOUSE) s else (s + 1) / 2 + playerInventory.itemStack = slotStack.splitStack(toRemove) + clickedSlot.putStack(slotStack) + clickedSlot.onTake(player, playerInventory.itemStack) + clickedSlot.onSlotChanged() + detectAndSendChanges() + return ItemStack.EMPTY + } + } else if (clickTypeIn == ClickType.PICKUP_ALL && slotId >= 0) { + val clickedSlot = getSlot(slotId) + val slotStack = clickedSlot.stack + val maxStackSize = clickedSlot.getItemStackLimit(slotStack) - for (k in 0..1) { - var l = i + if (!heldStack.isEmpty && + (clickedSlot == null || !clickedSlot.hasStack || !clickedSlot.canTakeStack(player)) + ) { + val i = if (mouseButton == 0) 0 else inventorySlots.size - 1 + val j = if (mouseButton == 0) 1 else -1 - while (l >= 0 && l < inventorySlots.size && heldStack.count < maxStackSize) { - val slot1 = inventorySlots[l] + for (k in 0..1) { + var l = i - if (slot1 is ModularSlot && slot1.isPhantom) { - l += j - continue - } + while (l >= 0 && l < inventorySlots.size && heldStack.count < maxStackSize) { + val slot1 = inventorySlots[l] - if (slot1.hasStack && Container.canAddItemToSlot(slot1, heldStack, true) && - slot1.canTakeStack(player) && canMergeSlot(heldStack, slot1) - ) { - val itemstack2 = slot1.stack + if (slot1 is ModularSlot && slot1.isPhantom) { + l += j + continue + } - if (k != 0 || itemstack2.count != maxStackSize) { - val i1 = min((maxStackSize - heldStack.count), itemstack2.count) - val itemstack3 = slot1.decrStackSize(i1) - heldStack.grow(i1) + if (slot1.hasStack && Container.canAddItemToSlot(slot1, heldStack, true) && + slot1.canTakeStack(player) && canMergeSlot(heldStack, slot1) + ) { + val itemstack2 = slot1.stack - if (itemstack3.isEmpty) { - slot1.putStack(ItemStack.EMPTY) - } + if (k != 0 || itemstack2.count != maxStackSize) { + val i1 = min((maxStackSize - heldStack.count), itemstack2.count) + val itemstack3 = slot1.decrStackSize(i1) + heldStack.grow(i1) + + if (itemstack3.isEmpty) { + slot1.putStack(ItemStack.EMPTY) + } - slot1.onTake(player, itemstack3) + slot1.onTake(player, itemstack3) + } } + l += j } - l += j } } - } - detectAndSendChanges() - return ItemStack.EMPTY - } else if (clickTypeIn == ClickType.CLONE && player.capabilities.isCreativeMode && - playerInventory.itemStack.isEmpty && slotId >= 0 - ) { - val slot = getSlot(slotId) + detectAndSendChanges() + return ItemStack.EMPTY + } else if (clickTypeIn == ClickType.CLONE && player.capabilities.isCreativeMode && + playerInventory.itemStack.isEmpty && slotId >= 0 + ) { + val slot = getSlot(slotId) - if (slot != null && slot.hasStack) - playerInventory.itemStack = slot.stack.copy() + if (slot != null && slot.hasStack) + playerInventory.itemStack = slot.stack.copy() - return ItemStack.EMPTY - } else if (clickTypeIn == ClickType.SWAP && mouseButton >= 0 && mouseButton < 9 && backpackSlotIndex == mouseButton) { - // Prevents swapping opened backpack when backpack is in player inventory - return ItemStack.EMPTY - } + return ItemStack.EMPTY + } else if (clickTypeIn == ClickType.SWAP && mouseButton >= 0 && mouseButton < 9 && backpackSlotIndex == mouseButton) { + // Prevents swapping opened backpack when backpack is in player inventory + return ItemStack.EMPTY + } - return super.slotClick(slotId, mouseButton, clickTypeIn, player) + return super.slotClick(slotId, mouseButton, clickTypeIn, player) + } finally { + backpackWrapper.isGuiInteractionInProgress = false + } } override fun transferItem(fromSlot: ModularSlot, fromStack: ItemStack): ItemStack { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackGuiHolder.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackGuiHolder.kt index aed7b16..a91990c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackGuiHolder.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackGuiHolder.kt @@ -7,18 +7,28 @@ import com.cleanroommc.modularui.screen.UISettings import com.cleanroommc.modularui.value.sync.PanelSyncManager import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.BackpackInventoryScrollWidget import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData.InventoryType import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.ceilDiv +import kotlin.math.min import net.minecraft.entity.player.EntityPlayer sealed class BackpackGuiHolder(protected val backpackWrapper: BackpackWrapper) { companion object { private const val SLOT_SIZE = 18 + private const val HEIGHT_WITHOUT_STORAGE_SLOTS = 114 } - protected val rowSize = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 + protected val tankInventoryControlCount = min(backpackWrapper.tankUpgradeSlots().size, 2) + protected val batteryInventoryControlCount = min(backpackWrapper.batteryUpgradeSlots().size, 1) + protected val inventoryColumnsTaken = + (tankInventoryControlCount + batteryInventoryControlCount) * BackpackPanel.INVENTORY_CONTROL_COLUMNS + protected val backgroundRowSize = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 + protected val rowSize = (backgroundRowSize - inventoryColumnsTaken).coerceAtLeast(1) protected val colSize = backpackWrapper.backpackInventorySize().ceilDiv(rowSize) + protected val visibleColSize = min(colSize, BackpackPanel.VISIBLE_BACKPACK_ROWS) + protected val scrollbarWidth = if (colSize > visibleColSize) BackpackInventoryScrollWidget.SCROLLBAR_WIDTH else 0 protected fun createPanel( syncManager: PanelSyncManager, @@ -32,19 +42,13 @@ sealed class BackpackGuiHolder(protected val backpackWrapper: BackpackWrapper) { player, tileEntity, backpackWrapper, - 14 + rowSize * SLOT_SIZE, - 112 + colSize * SLOT_SIZE, + 14 + backgroundRowSize * SLOT_SIZE + scrollbarWidth, + HEIGHT_WITHOUT_STORAGE_SLOTS + visibleColSize * SLOT_SIZE, inventoryType?.let { if (it == InventoryType.PLAYER_INVENTORY) slotIndex else null }, ) protected fun addCommonWidgets(panel: BackpackPanel, player: EntityPlayer) { - panel.addSortingButtons() - panel.addTransferButtons() - panel.addBackpackInventorySlots() - panel.addUpgradeSlots() - panel.addSettingTab() - panel.addUpgradeTabs() - panel.addTexts(player) + panel.rebuildWidgets() } class TileEntityGuiHolder(backpackWrapper: BackpackWrapper) : BackpackGuiHolder(backpackWrapper), @@ -69,9 +73,9 @@ sealed class BackpackGuiHolder(protected val backpackWrapper: BackpackWrapper) { uiSettings: UISettings ): ModularPanel { val panel = createPanel(syncManager, data.player, null, data.inventoryType, data.slotIndex) - addCommonWidgets(panel, data.player) panel.modifyPlayerSlot(syncManager, data.inventoryType, data.slotIndex, data.player) + addCommonWidgets(panel, data.player) return panel } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt index cf5900b..485e0c1 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt @@ -7,6 +7,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.item.ExponentialStackUpgradeI import com.cleanroommc.retrosophisticatedbackpacks.item.InceptionUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.StackUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.UpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.item.BatteryUpgradeItem import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack @@ -16,7 +17,7 @@ class ModularUpgradeSlot( index: Int, ) : ModularSlot(wrapper.upgradeItemStackHandler, index) { override fun canTakeStack(playerIn: EntityPlayer): Boolean { - if (panel.settingPanel.isPanelOpen) + if (panel.isSettingMode) return false val originalUpgradeItem = stack.item @@ -51,6 +52,7 @@ class ModularUpgradeSlot( override fun isItemValid(stack: ItemStack): Boolean = when (val item = stack.item) { is StackUpgradeItem -> wrapper.canAddStackUpgrade(item.multiplier()) is ExponentialStackUpgradeItem -> wrapper.canAddExponentialStackUpgrade() + is BatteryUpgradeItem -> wrapper.canAddBatteryUpgrade() else -> item is UpgradeItem } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt index 7229c69..16149ad 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt @@ -102,6 +102,114 @@ object CapabilityHandler { ::AdvancedFilterUpgradeWrapper ) + instance.register( + MagnetUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::MagnetUpgradeWrapper + ) + + instance.register( + AdvancedMagnetUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AdvancedMagnetUpgradeWrapper + ) + + instance.register( + VoidUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::VoidUpgradeWrapper + ) + + instance.register( + AdvancedVoidUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AdvancedVoidUpgradeWrapper + ) + + instance.register( + RefillUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::RefillUpgradeWrapper + ) + + instance.register( + AdvancedRefillUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AdvancedRefillUpgradeWrapper + ) + + instance.register( + CompactingUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::CompactingUpgradeWrapper + ) + + instance.register( + AdvancedCompactingUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AdvancedCompactingUpgradeWrapper + ) + + instance.register( + EverlastingUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::EverlastingUpgradeWrapper + ) + + instance.register( + ToolSwapperUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::ToolSwapperUpgradeWrapper + ) + + instance.register( + AdvancedToolSwapperUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AdvancedToolSwapperUpgradeWrapper + ) + + instance.register( + TankUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::TankUpgradeWrapper + ) + + instance.register( + JukeboxUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::JukeboxUpgradeWrapper + ) + + instance.register( + AdvancedJukeboxUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AdvancedJukeboxUpgradeWrapper + ) + + instance.register( + PumpUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::PumpUpgradeWrapper + ) + + instance.register( + AdvancedPumpUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AdvancedPumpUpgradeWrapper + ) + + instance.register( + BatteryUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::BatteryUpgradeWrapper + ) + + instance.register( + AnvilUpgradeWrapper::class.java, + CapabilityStorageProvider(), + ::AnvilUpgradeWrapper + ) + // Interfaces instance.register( UpgradeWrapper::class.java, @@ -152,6 +260,67 @@ object CapabilityHandler { NOPCapabilityStorage(), ::FilterUpgradeWrapper ) + + instance.register( + IMagnetUpgrade::class.java, + NOPCapabilityStorage(), + ::MagnetUpgradeWrapper + ) + + instance.register( + IVoidUpgrade::class.java, + NOPCapabilityStorage(), + ::VoidUpgradeWrapper + ) + + instance.register( + IRefillUpgrade::class.java, + NOPCapabilityStorage(), + ::RefillUpgradeWrapper + ) + + instance.register( + ICompactingUpgrade::class.java, + NOPCapabilityStorage(), + ::CompactingUpgradeWrapper + ) + + instance.register( + IEverlastingUpgrade::class.java, + NOPCapabilityStorage(), + ::EverlastingUpgradeWrapper + ) + + instance.register( + IToolSwapperUpgrade::class.java, + NOPCapabilityStorage(), + ::ToolSwapperUpgradeWrapper + ) + + instance.register( + ITankUpgrade::class.java, + NOPCapabilityStorage() + ) { TankUpgradeWrapper() } + + instance.register( + IJukeboxUpgrade::class.java, + NOPCapabilityStorage() + ) { JukeboxUpgradeWrapper() } + + instance.register( + IPumpUpgrade::class.java, + NOPCapabilityStorage() + ) { PumpUpgradeWrapper() } + + instance.register( + IBatteryUpgrade::class.java, + NOPCapabilityStorage() + ) { BatteryUpgradeWrapper() } + + instance.register( + IAnvilUpgrade::class.java, + NOPCapabilityStorage() + ) { AnvilUpgradeWrapper() } } fun cacheBackpackInventory(backpackWrapper: BackpackWrapper) { @@ -224,4 +393,4 @@ object CapabilityHandler { instance.deserializeNBT(nbt as NBTTagCompound) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt new file mode 100644 index 0000000..1b0de98 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt @@ -0,0 +1,163 @@ +package com.cleanroommc.retrosophisticatedbackpacks.handler + +import com.cleanroommc.retrosophisticatedbackpacks.Tags +import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackStashHelper +import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackStashHelper.Result +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlot +import com.cleanroommc.retrosophisticatedbackpacks.mixin.GuiContainerAccessor +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SStashToBackpackPacket +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.client.gui.inventory.GuiContainerCreative +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.inventory.Slot +import net.minecraft.item.ItemStack +import net.minecraftforge.client.event.GuiScreenEvent +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly + +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(modid = Tags.MOD_ID, value = [Side.CLIENT]) +object ClientGuiStashHandler { + private const val MATCH_AND_SPACE_COLOR = 0x55FF55 + private const val SPACE_COLOR = 0xFFFF55 + + @SubscribeEvent + @JvmStatic + fun onDrawScreenPost(event: GuiScreenEvent.DrawScreenEvent.Post) { + val screen = event.gui as? GuiContainer ?: return + if (screen is GuiContainerCreative) { + return + } + + val player = Minecraft.getMinecraft().player ?: return + val carried = player.inventory.itemStack + if (carried.isEmpty) { + return + } + + val accessor = screen as GuiContainerAccessor + for (slot in player.openContainer.inventorySlots) { + if (slot is ModularBackpackSlot || !slot.isEnabled || slot.xPos < -100 || slot.yPos < -100) { + continue + } + drawStashSign(screen, accessor, player, slot, carried) + } + } + + @JvmStatic + fun handleMouseClicked(screen: GuiContainer, mouseX: Int, mouseY: Int, mouseButton: Int): Boolean { + if (screen is GuiContainerCreative || mouseButton != 1) { + return false + } + + val player = Minecraft.getMinecraft().player ?: return false + val carried = player.inventory.itemStack + if (carried.isEmpty) { + return false + } + + val slot = (screen as GuiContainerAccessor).`rsb$getSlotAtPosition`(mouseX, mouseY) ?: return false + val action = getStashAction(player, slot, carried) ?: return false + NetworkHandler.INSTANCE.sendToServer(C2SStashToBackpackPacket(slot.slotNumber, action)) + return true + } + + @JvmStatic + fun getStashActionForSlot(player: EntityPlayer, slot: Slot, carried: ItemStack): C2SStashToBackpackPacket.Action? = + getStashAction(player, slot, carried) + + @JvmStatic + fun getStashResultForSlot(player: EntityPlayer, slot: Slot, carried: ItemStack): Pair? { + val slotStack = slot.stack + if (!slotStack.isEmpty && slotStack.count == 1 && slot.canTakeStack(player)) { + val result = BackpackStashHelper.getStashResult(slotStack, carried) + if (result != Result.NO_SPACE) { + return "+" to result + } + } + + if (!slotStack.isEmpty && carried.count == 1 && slot.canTakeStack(player) && + carried.getCapability(Capabilities.BACKPACK_CAPABILITY, null) != null + ) { + val result = BackpackStashHelper.getStashResult(carried, slotStack) + if (result != Result.NO_SPACE) { + return "-" to result + } + } + + return null + } + + private fun drawStashSign( + screen: GuiContainer, + accessor: GuiContainerAccessor, + player: EntityPlayer, + slot: Slot, + carried: ItemStack + ) { + val slotStack = slot.stack + val plusResult = if (!slotStack.isEmpty && slotStack.count == 1 && slot.canTakeStack(player)) { + BackpackStashHelper.getStashResult(slotStack, carried) + } else { + Result.NO_SPACE + } + + if (plusResult != Result.NO_SPACE) { + Minecraft.getMinecraft().fontRenderer.drawStringWithShadow( + "+", + (accessor.guiLeft + slot.xPos + 10).toFloat(), + (accessor.guiTop + slot.yPos + 8).toFloat(), + color(plusResult) + ) + return + } + + if (slotStack.isEmpty || !slot.canTakeStack(player) || carried.count != 1 || + carried.getCapability(Capabilities.BACKPACK_CAPABILITY, null) == null + ) { + return + } + + val minusResult = BackpackStashHelper.getStashResult(carried, slotStack) + if (minusResult == Result.NO_SPACE) { + return + } + + Minecraft.getMinecraft().fontRenderer.drawStringWithShadow( + "-", + (accessor.guiLeft + slot.xPos + 1).toFloat(), + (accessor.guiTop + slot.yPos).toFloat(), + color(minusResult) + ) + } + + private fun getStashAction( + player: EntityPlayer, + slot: Slot, + carried: ItemStack + ): C2SStashToBackpackPacket.Action? { + val slotStack = slot.stack + if (!slotStack.isEmpty && slotStack.count == 1 && slot.canTakeStack(player) && + BackpackStashHelper.getStashResult(slotStack, carried) != Result.NO_SPACE + ) { + return C2SStashToBackpackPacket.Action.CARRIED_TO_SLOT_BACKPACK + } + + if (!slotStack.isEmpty && carried.count == 1 && slot.canTakeStack(player) && + carried.getCapability(Capabilities.BACKPACK_CAPABILITY, null) != null && + BackpackStashHelper.getStashResult(carried, slotStack) != Result.NO_SPACE + ) { + return C2SStashToBackpackPacket.Action.SLOT_TO_CARRIED_BACKPACK + } + + return null + } + + @JvmStatic + fun color(result: Result): Int = + if (result == Result.MATCH_AND_SPACE) MATCH_AND_SPACE_COLOR else SPACE_COLOR +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt index 44b7aa9..5b76181 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt @@ -5,14 +5,24 @@ import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.Tags import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHelper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.EverlastingUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IToolSwapperUpgrade import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem +import com.cleanroommc.retrosophisticatedbackpacks.mixin.EntityItemAccessor +import net.minecraft.block.material.Material import net.minecraft.entity.item.EntityItem import net.minecraft.init.SoundEvents import net.minecraft.item.ItemStack import net.minecraft.util.EnumActionResult import net.minecraft.util.SoundCategory +import net.minecraft.util.math.BlockPos +import net.minecraftforge.event.entity.EntityJoinWorldEvent +import net.minecraftforge.event.entity.item.ItemExpireEvent import net.minecraftforge.event.entity.player.EntityItemPickupEvent +import net.minecraftforge.event.entity.player.AttackEntityEvent import net.minecraftforge.event.entity.player.PlayerInteractEvent +import net.minecraftforge.event.world.ExplosionEvent import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.items.IItemHandler @@ -73,12 +83,7 @@ object EntityEventHandler { if (!wrapper.canPickupItem(stack)) continue - var slotIndex = 0 - while (!stack.isEmpty && slotIndex < wrapper.slots) { - stack = wrapper.backpackItemStackHandler.prioritizedInsertion(slotIndex, stack, false) - - slotIndex++ - } + stack = wrapper.insertStack(stack, false, true) if (stack.isEmpty) break @@ -87,6 +92,90 @@ object EntityEventHandler { return stack } + @SubscribeEvent + @JvmStatic + fun onItemExpire(event: ItemExpireEvent) { + val stack = event.entityItem.item + val wrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return + if (wrapper.hasEverlastingUpgrade()) { + event.extraLife = Int.MAX_VALUE + event.isCanceled = true + } + } + + @SubscribeEvent + @JvmStatic + fun onEntityJoinWorld(event: EntityJoinWorldEvent) { + val entity = event.entity as? EntityItem ?: return + if (entity.item.getCapability(Capabilities.BACKPACK_CAPABILITY, null)?.hasEverlastingUpgrade() == true) { + keepEverlastingItemAlive(entity) + } + } + + @SubscribeEvent + @JvmStatic + fun onWorldTick(event: net.minecraftforge.fml.common.gameevent.TickEvent.WorldTickEvent) { + if (event.phase != net.minecraftforge.fml.common.gameevent.TickEvent.Phase.END || event.world.isRemote || event.world.totalWorldTime % 20L != 0L) { + return + } + event.world.loadedEntityList.asSequence() + .filterIsInstance() + .filter { it.item.getCapability(Capabilities.BACKPACK_CAPABILITY, null)?.hasEverlastingUpgrade() == true } + .forEach { entity -> + keepEverlastingItemAlive(entity) + if (entity.posY < 0) { + entity.setPosition(entity.posX, 1.0, entity.posZ) + entity.motionY = 0.2 + } + val material = entity.world.getBlockState(BlockPos(entity)).material + if (material == Material.WATER || material == Material.LAVA) { + entity.motionY = 0.08 + entity.fallDistance = 0f + } + } + } + + @SubscribeEvent + @JvmStatic + fun onExplosionDetonate(event: ExplosionEvent.Detonate) { + event.affectedBlocks.removeIf { pos -> + val tile = event.world.getTileEntity(pos) as? com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity + tile?.wrapper?.hasEverlastingUpgrade() == true + } + event.affectedEntities.removeIf { entity -> + entity is EntityItem && entity.item.getCapability(Capabilities.BACKPACK_CAPABILITY, null)?.hasEverlastingUpgrade() == true + } + } + + @SubscribeEvent + @JvmStatic + fun onLeftClickBlock(event: PlayerInteractEvent.LeftClickBlock) { + if (event.world.isRemote) { + return + } + val state = event.world.getBlockState(event.pos) + if (forEachBackpack(event.entityPlayer) { wrapper -> + wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY) + .any { it.onBlockClick(event.entityPlayer, wrapper, event.pos, state) } + }) { + event.entityPlayer.inventoryContainer.detectAndSendChanges() + } + } + + @SubscribeEvent + @JvmStatic + fun onAttackEntity(event: AttackEntityEvent) { + if (event.entityPlayer.world.isRemote) { + return + } + if (forEachBackpack(event.entityPlayer) { wrapper -> + wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY) + .any { it.onAttackEntity(event.entityPlayer, wrapper) } + }) { + event.entityPlayer.inventoryContainer.detectAndSendChanges() + } + } + @SubscribeEvent @JvmStatic fun onPlayerInteract(event: PlayerInteractEvent.EntityInteract) { @@ -117,5 +206,57 @@ object EntityEventHandler { } } } + + if (!player.world.isRemote && forEachBackpack(player) { wrapper -> + wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY) + .filterIsInstance() + .any { it.onEntityInteract(player, wrapper, entity) } + }) { + player.inventoryContainer.detectAndSendChanges() + } + } + + @SubscribeEvent + @JvmStatic + fun onRightClickBlock(event: PlayerInteractEvent.RightClickBlock) { + if (event.world.isRemote) { + return + } + val state = event.world.getBlockState(event.pos) + if (forEachBackpack(event.entityPlayer) { wrapper -> + wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY) + .filterIsInstance() + .any { it.onBlockInteract(event.entityPlayer, wrapper, event.world, event.pos, state) } + }) { + event.entityPlayer.inventoryContainer.detectAndSendChanges() + } + } + + private fun BackpackWrapper.hasEverlastingUpgrade(): Boolean = + gatherCapabilityUpgrades(Capabilities.EVERLASTING_UPGRADE_CAPABILITY) + .filterIsInstance() + .isNotEmpty() + + private fun keepEverlastingItemAlive(entity: EntityItem) { + entity.lifespan = Int.MAX_VALUE + entity.setEntityInvulnerable(true) + (entity as EntityItemAccessor).`rsb$setAge`(0) + } + + private fun forEachBackpack(player: net.minecraft.entity.player.EntityPlayer, action: (BackpackWrapper) -> Boolean): Boolean { + if (forEachBackpackIn(InvWrapper(player.inventory), action)) { + return true + } + return RetroSophisticatedBackpacks.baublesLoaded && forEachBackpackIn(BaublesApi.getBaublesHandler(player), action) + } + + private fun forEachBackpackIn(inventory: IItemHandler, action: (BackpackWrapper) -> Boolean): Boolean { + for (slot in 0 until inventory.slots) { + val wrapper = inventory.getStackInSlot(slot).getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: continue + if (action(wrapper)) { + return true + } + } + return false } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt index f4ababc..a52945f 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt @@ -6,15 +6,20 @@ import com.cleanroommc.modularui.screen.ClientScreenHandler import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.Tags import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedRefillUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData import com.cleanroommc.retrosophisticatedbackpacks.network.C2SOpenBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SRefillBlockPickPacket import com.cleanroommc.retrosophisticatedbackpacks.proxy.RSBProxy import net.minecraft.client.Minecraft import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.inventory.IInventory import net.minecraft.item.ItemStack +import net.minecraft.util.math.RayTraceResult import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.gameevent.InputEvent +import net.minecraftforge.items.IItemHandler import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly @@ -66,6 +71,74 @@ object KeyInputHandler { ) } } + + if (mc.gameSettings.keyBindPickBlock.isPressed) { + sendRefillBlockPickPacket(mc) + } + } + + @SubscribeEvent + @JvmStatic + fun onMouseInput(event: InputEvent.MouseInputEvent) { + val mc = Minecraft.getMinecraft() + if (mc.gameSettings.keyBindPickBlock.isPressed) { + sendRefillBlockPickPacket(mc) + } + } + + private fun sendRefillBlockPickPacket(mc: Minecraft) { + val player = mc.player ?: return + val target = mc.objectMouseOver ?: return + if (player.isCreative || target.typeOfHit != RayTraceResult.Type.BLOCK || !hasAdvancedRefillBackpack(player.inventory) && + (!RetroSophisticatedBackpacks.baublesLoaded || !hasAdvancedRefillBackpack(BaublesApi.getBaublesHandler(player)))) { + return + } + + val pos = target.blockPos + val state = mc.world.getBlockState(pos) + if (state.block.isAir(state, mc.world, pos)) { + return + } + + val pickedStack = state.block.getPickBlock(state, target, mc.world, pos, player) + if (!pickedStack.isEmpty && !hasMatchingStack(player.inventory, pickedStack)) { + NetworkHandler.INSTANCE.sendToServer(C2SRefillBlockPickPacket(pickedStack)) + } + } + + private fun hasAdvancedRefillBackpack(inventory: IInventory): Boolean { + for (slot in 0 until inventory.sizeInventory) { + val wrapper = inventory.getStackInSlot(slot).getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: continue + if (wrapper.gatherCapabilityUpgrades(Capabilities.ADVANCED_REFILL_UPGRADE_CAPABILITY) + .filterIsInstance() + .any { it.enabled } + ) { + return true + } + } + return false + } + + private fun hasMatchingStack(inventory: IInventory, stack: ItemStack): Boolean { + for (slot in 0 until inventory.sizeInventory) { + if (net.minecraftforge.items.ItemHandlerHelper.canItemStacksStack(inventory.getStackInSlot(slot), stack)) { + return true + } + } + return false + } + + private fun hasAdvancedRefillBackpack(inventory: IItemHandler): Boolean { + for (slot in 0 until inventory.slots) { + val wrapper = inventory.getStackInSlot(slot).getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: continue + if (wrapper.gatherCapabilityUpgrades(Capabilities.ADVANCED_REFILL_UPGRADE_CAPABILITY) + .filterIsInstance() + .any { it.enabled } + ) { + return true + } + } + return false } @JvmStatic @@ -108,4 +181,4 @@ object KeyInputHandler { ) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt index 4ded0f6..3251a0f 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt @@ -1,6 +1,8 @@ package com.cleanroommc.retrosophisticatedbackpacks.handler import com.cleanroommc.retrosophisticatedbackpacks.network.C2SOpenBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SRefillBlockPickPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SStashToBackpackPacket import net.minecraftforge.fml.common.network.NetworkRegistry import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper import net.minecraftforge.fml.relauncher.Side @@ -23,5 +25,17 @@ object NetworkHandler { idGenerator.next(), Side.SERVER ) + INSTANCE.registerMessage( + C2SRefillBlockPickPacket.Handler::class.java, + C2SRefillBlockPickPacket::class.java, + idGenerator.next(), + Side.SERVER + ) + INSTANCE.registerMessage( + C2SStashToBackpackPacket.Handler::class.java, + C2SStashToBackpackPacket::class.java, + idGenerator.next(), + Side.SERVER + ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt index dce75d6..de14df0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt @@ -55,6 +55,9 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) validateSlotIndex(slot) + if (!isItemValid(slot, stack)) + return stack + val existing = stacks[slot] var limit = getStackLimit(slot, stack) @@ -79,6 +82,7 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) } onContentsChanged(slot) + if (wrapper.shouldHandleSlotChangeFromGui()) wrapper.onGuiSlotChanged(slot) else wrapper.onSlotChanged(slot) } return if (reachedLimit) ItemHandlerHelper.copyStackWithSize(stack, stack.count - limit) @@ -103,6 +107,7 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) if (!simulate) { stacks[slotIndex] = ItemStack.EMPTY onContentsChanged(slotIndex) + if (wrapper.shouldHandleSlotChangeFromGui()) wrapper.onGuiSlotChanged(slotIndex) else wrapper.onSlotChanged(slotIndex) } return stack @@ -110,6 +115,7 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) if (!simulate) { stacks[slotIndex] = ItemHandlerHelper.copyStackWithSize(stack, stack.count - toExtract) onContentsChanged(slotIndex) + if (wrapper.shouldHandleSlotChangeFromGui()) wrapper.onGuiSlotChanged(slotIndex) else wrapper.onSlotChanged(slotIndex) } return ItemHandlerHelper.copyStackWithSize(stack, toExtract) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/DelegatedItemHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/DelegatedItemHandler.kt index 86b6df6..5a35d69 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/DelegatedItemHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/DelegatedItemHandler.kt @@ -3,46 +3,36 @@ package com.cleanroommc.retrosophisticatedbackpacks.inventory import net.minecraft.item.ItemStack import net.minecraftforge.items.IItemHandler import net.minecraftforge.items.IItemHandlerModifiable -import net.minecraftforge.items.wrapper.EmptyHandler class DelegatedItemHandler(var delegated: () -> IItemHandler, var wrappedSlotAmount: Int) : IItemHandlerModifiable { - override fun getSlots(): Int { - val delegated = delegated() - - if (delegated != EmptyHandler.INSTANCE) - check(delegated.slots == wrappedSlotAmount) { - "Mismatched delegated item handler slot amount: assumed to have $wrappedSlotAmount but actually got ${delegated().slots}" - } - - return wrappedSlotAmount - } + override fun getSlots(): Int = wrappedSlotAmount override fun getStackInSlot(slot: Int): ItemStack = - delegated().getStackInSlot(slot) + delegated().let { if (slot in 0 until it.slots) it.getStackInSlot(slot) else ItemStack.EMPTY } override fun insertItem( slot: Int, stack: ItemStack, simulate: Boolean ): ItemStack = - delegated().insertItem(slot, stack, simulate) + delegated().let { if (slot in 0 until it.slots) it.insertItem(slot, stack, simulate) else stack } override fun extractItem( slot: Int, amount: Int, simulate: Boolean ): ItemStack = - delegated().extractItem(slot, amount, simulate) + delegated().let { if (slot in 0 until it.slots) it.extractItem(slot, amount, simulate) else ItemStack.EMPTY } override fun getSlotLimit(slot: Int): Int = - delegated().getSlotLimit(slot) + delegated().let { if (slot in 0 until it.slots) it.getSlotLimit(slot) else 0 } override fun setStackInSlot(slot: Int, stack: ItemStack) { val delegated = delegated() - if (delegated is IItemHandlerModifiable) + if (delegated is IItemHandlerModifiable && slot in 0 until delegated.slots) delegated.setStackInSlot(slot, stack) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt index 89ed4db..2e9ef5d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt @@ -1,5 +1,6 @@ package com.cleanroommc.retrosophisticatedbackpacks.inventory +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import net.minecraft.item.ItemStack import net.minecraft.util.NonNullList import net.minecraftforge.items.ItemStackHandler @@ -7,4 +8,22 @@ import net.minecraftforge.items.ItemStackHandler class UpgradeItemStackHandler(size: Int) : ItemStackHandler(size) { val inventory: NonNullList = stacks -} \ No newline at end of file + + override fun setStackInSlot(slot: Int, stack: ItemStack) { + val original = getStackInSlot(slot) + if (!original.isEmpty && !ItemStack.areItemsEqual(original, stack)) { + original.getCapability(Capabilities.UPGRADE_CAPABILITY, null)?.onBeforeRemoved() + } + super.setStackInSlot(slot, stack) + } + + override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack { + if (!simulate && amount > 0) { + val original = getStackInSlot(slot) + if (!original.isEmpty) { + original.getCapability(Capabilities.UPGRADE_CAPABILITY, null)?.onBeforeRemoved() + } + } + return super.extractItem(slot, amount, simulate) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/AnvilUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/AnvilUpgradeItem.kt new file mode 100644 index 0000000..ea34bed --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/AnvilUpgradeItem.kt @@ -0,0 +1,15 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IAnvilUpgrade +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider + +class AnvilUpgradeItem(registryName: String, private val wrapperFactory: () -> IAnvilUpgrade) : + UpgradeItem(registryName, true) { + override fun initCapabilities(stack: ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory() + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt index da7ef71..563827e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt @@ -22,12 +22,14 @@ import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGui import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiFactory import com.cleanroommc.retrosophisticatedbackpacks.handler.CapabilityHandler import com.cleanroommc.retrosophisticatedbackpacks.handler.RegistryHandler +import com.cleanroommc.retrosophisticatedbackpacks.mixin.EntityItemAccessor import com.cleanroommc.retrosophisticatedbackpacks.util.IModelRegister import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.client.model.ModelBiped import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.util.ITooltipFlag import net.minecraft.entity.Entity +import net.minecraft.entity.item.EntityItem import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayerMP @@ -183,11 +185,35 @@ class BackpackItem( if (entityIn.ticksExisted % 20 == 0) wrapper.feed(entityIn, wrapper) + if (entityIn.ticksExisted % 5 == 0) + wrapper.tickUpgrades(entityIn, worldIn, entityIn.posX, entityIn.posY, entityIn.posZ) + if (!wrapper.isCached) CapabilityHandler.cacheBackpackInventory(wrapper) } } + override fun onEntityItemUpdate(entityItem: EntityItem): Boolean { + val wrapper = entityItem.item.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return false + if (wrapper.gatherCapabilityUpgrades(Capabilities.EVERLASTING_UPGRADE_CAPABILITY).isEmpty()) { + return false + } + + entityItem.lifespan = Int.MAX_VALUE + entityItem.setEntityInvulnerable(true) + (entityItem as EntityItemAccessor).`rsb$setAge`(0) + if (entityItem.posY < 1.0) { + entityItem.setPosition(entityItem.posX, 1.0, entityItem.posZ) + entityItem.motionY = 0.2 + } + val material = entityItem.world.getBlockState(BlockPos(entityItem)).material + if (material == net.minecraft.block.material.Material.WATER || material == net.minecraft.block.material.Material.LAVA) { + entityItem.motionY = 0.08 + entityItem.fallDistance = 0f + } + return false + } + override fun isValidArmor(stack: ItemStack, armorType: EntityEquipmentSlot, entity: Entity): Boolean = armorType == EntityEquipmentSlot.CHEST @@ -283,7 +309,7 @@ class BackpackItem( val stack = data.usedItemStack val wrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null)!! val slotIndex = if (data.inventoryType == InventoryType.PLAYER_INVENTORY) data.slotIndex else null - uiSettings.customContainer { BackpackContainer(wrapper, slotIndex) } + uiSettings.customContainer { BackpackContainer(wrapper, slotIndex, data.inventoryType, data.slotIndex) } val holder = BackpackGuiHolder.ItemStackGuiHolder(wrapper) return holder.buildUI(data, syncManager, uiSettings) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BatteryUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BatteryUpgradeItem.kt new file mode 100644 index 0000000..80fc704 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BatteryUpgradeItem.kt @@ -0,0 +1,15 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IBatteryUpgrade +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider + +class BatteryUpgradeItem(registryName: String, private val wrapperFactory: () -> IBatteryUpgrade) : + UpgradeItem(registryName, true) { + override fun initCapabilities(stack: ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory() + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CompactingUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CompactingUpgradeItem.kt new file mode 100644 index 0000000..2f17f32 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CompactingUpgradeItem.kt @@ -0,0 +1,6 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.ICompactingUpgrade + +class CompactingUpgradeItem(registryName: String, wrapperFactory: () -> ICompactingUpgrade) : + RankedUpgradeItem(registryName, wrapperFactory) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/EverlastingUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/EverlastingUpgradeItem.kt new file mode 100644 index 0000000..79e01b0 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/EverlastingUpgradeItem.kt @@ -0,0 +1,6 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IEverlastingUpgrade + +class EverlastingUpgradeItem(registryName: String, wrapperFactory: () -> IEverlastingUpgrade) : + HiddenUpgradeItem(registryName, wrapperFactory) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/HiddenUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/HiddenUpgradeItem.kt new file mode 100644 index 0000000..80db133 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/HiddenUpgradeItem.kt @@ -0,0 +1,17 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider +import net.minecraftforge.common.util.INBTSerializable + +abstract class HiddenUpgradeItem( + registryName: String, + private val wrapperFactory: () -> CP, +) : UpgradeItem(registryName, false) + where CP : ICapabilityProvider, CP : INBTSerializable { + override fun initCapabilities(stack: net.minecraft.item.ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory.invoke() + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt index a84cad0..7e29c1a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt @@ -117,4 +117,58 @@ object Items { @JvmField val advancedFilterUpgrade = FilterUpgradeItem("advanced_filter_upgrade", ::AdvancedFilterUpgradeWrapper) -} \ No newline at end of file + + @JvmField + val magnetUpgrade = MagnetUpgradeItem("magnet_upgrade", ::MagnetUpgradeWrapper) + + @JvmField + val advancedMagnetUpgrade = MagnetUpgradeItem("advanced_magnet_upgrade", ::AdvancedMagnetUpgradeWrapper) + + @JvmField + val voidUpgrade = VoidUpgradeItem("void_upgrade", ::VoidUpgradeWrapper) + + @JvmField + val advancedVoidUpgrade = VoidUpgradeItem("advanced_void_upgrade", ::AdvancedVoidUpgradeWrapper) + + @JvmField + val refillUpgrade = RefillUpgradeItem("refill_upgrade", ::RefillUpgradeWrapper) + + @JvmField + val advancedRefillUpgrade = RefillUpgradeItem("advanced_refill_upgrade", ::AdvancedRefillUpgradeWrapper) + + @JvmField + val compactingUpgrade = CompactingUpgradeItem("compacting_upgrade", ::CompactingUpgradeWrapper) + + @JvmField + val advancedCompactingUpgrade = CompactingUpgradeItem("advanced_compacting_upgrade", ::AdvancedCompactingUpgradeWrapper) + + @JvmField + val everlastingUpgrade = EverlastingUpgradeItem("everlasting_upgrade", ::EverlastingUpgradeWrapper) + + @JvmField + val jukeboxUpgrade = JukeboxUpgradeItem("jukebox_upgrade", ::JukeboxUpgradeWrapper) + + @JvmField + val advancedJukeboxUpgrade = JukeboxUpgradeItem("advanced_jukebox_upgrade", ::AdvancedJukeboxUpgradeWrapper) + + @JvmField + val toolSwapperUpgrade = ToolSwapperUpgradeItem("tool_swapper_upgrade", ::ToolSwapperUpgradeWrapper) + + @JvmField + val advancedToolSwapperUpgrade = ToolSwapperUpgradeItem("advanced_tool_swapper_upgrade", ::AdvancedToolSwapperUpgradeWrapper, hasTab = true) + + @JvmField + val tankUpgrade = TankUpgradeItem("tank_upgrade", ::TankUpgradeWrapper) + + @JvmField + val pumpUpgrade = PumpUpgradeItem("pump_upgrade", ::PumpUpgradeWrapper) + + @JvmField + val advancedPumpUpgrade = PumpUpgradeItem("advanced_pump_upgrade", ::AdvancedPumpUpgradeWrapper) + + @JvmField + val batteryUpgrade = BatteryUpgradeItem("battery_upgrade", ::BatteryUpgradeWrapper) + + @JvmField + val anvilUpgrade = AnvilUpgradeItem("anvil_upgrade", ::AnvilUpgradeWrapper) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt new file mode 100644 index 0000000..130b9fb --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt @@ -0,0 +1,16 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IJukeboxUpgrade +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider + +class JukeboxUpgradeItem( + registryName: String, + private val wrapperFactory: () -> IJukeboxUpgrade, +) : UpgradeItem(registryName, true) { + override fun initCapabilities(stack: net.minecraft.item.ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory.invoke() + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MagnetUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MagnetUpgradeItem.kt new file mode 100644 index 0000000..09ec3e3 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MagnetUpgradeItem.kt @@ -0,0 +1,6 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IMagnetUpgrade + +class MagnetUpgradeItem(registryName: String, wrapperFactory: () -> IMagnetUpgrade) : + RankedUpgradeItem(registryName, wrapperFactory) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/PumpUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/PumpUpgradeItem.kt new file mode 100644 index 0000000..67b9ccf --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/PumpUpgradeItem.kt @@ -0,0 +1,15 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IPumpUpgrade +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider + +class PumpUpgradeItem(registryName: String, private val wrapperFactory: () -> IPumpUpgrade) : + UpgradeItem(registryName, true) { + override fun initCapabilities(stack: ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory() + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/RefillUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/RefillUpgradeItem.kt new file mode 100644 index 0000000..6a3fc26 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/RefillUpgradeItem.kt @@ -0,0 +1,6 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IRefillUpgrade + +class RefillUpgradeItem(registryName: String, wrapperFactory: () -> IRefillUpgrade) : + RankedUpgradeItem(registryName, wrapperFactory) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/TankUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/TankUpgradeItem.kt new file mode 100644 index 0000000..e987a14 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/TankUpgradeItem.kt @@ -0,0 +1,16 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.ITankUpgrade +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider + +class TankUpgradeItem(registryName: String, wrapperFactory: () -> ITankUpgrade) : + UpgradeItem(registryName, true) { + private val wrapperFactory = wrapperFactory + + override fun initCapabilities(stack: net.minecraft.item.ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory.invoke() + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/ToolSwapperUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/ToolSwapperUpgradeItem.kt new file mode 100644 index 0000000..341b675 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/ToolSwapperUpgradeItem.kt @@ -0,0 +1,16 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IToolSwapperUpgrade + +class ToolSwapperUpgradeItem( + registryName: String, + private val wrapperFactory: () -> IToolSwapperUpgrade, + hasTab: Boolean = false +) : + UpgradeItem(registryName, hasTab) { + override fun initCapabilities(stack: net.minecraft.item.ItemStack, nbt: net.minecraft.nbt.NBTTagCompound?): net.minecraftforge.common.capabilities.ICapabilityProvider { + val capability = wrapperFactory.invoke() + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/VoidUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/VoidUpgradeItem.kt new file mode 100644 index 0000000..36cc077 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/VoidUpgradeItem.kt @@ -0,0 +1,6 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IVoidUpgrade + +class VoidUpgradeItem(registryName: String, wrapperFactory: () -> IVoidUpgrade) : + RankedUpgradeItem(registryName, wrapperFactory) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SRefillBlockPickPacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SRefillBlockPickPacket.kt new file mode 100644 index 0000000..556dc2a --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SRefillBlockPickPacket.kt @@ -0,0 +1,63 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import baubles.api.BaublesApi +import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedRefillUpgradeWrapper +import io.netty.buffer.ByteBuf +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.network.ByteBufUtils +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext +import net.minecraftforge.items.IItemHandler +import net.minecraftforge.items.wrapper.InvWrapper + +class C2SRefillBlockPickPacket() : IRefinedMessage { + private var pickedStack = ItemStack.EMPTY + + constructor(pickedStack: ItemStack) : this() { + this.pickedStack = pickedStack.copy() + } + + override fun toBytes(buf: ByteBuf) { + ByteBufUtils.writeItemStack(buf, pickedStack) + } + + override fun fromBytes(buf: ByteBuf) { + pickedStack = ByteBufUtils.readItemStack(buf) + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: C2SRefillBlockPickPacket, ctx: MessageContext): IRefinedMessage? { + val player = ctx.serverHandler.player + val world = player.serverWorld + + world.addScheduledTask { + if (!message.pickedStack.isEmpty) { + if (!attemptPick(player, InvWrapper(player.inventory), message.pickedStack) && RetroSophisticatedBackpacks.baublesLoaded) { + attemptPick(player, BaublesApi.getBaublesHandler(player), message.pickedStack) + } + } + } + + return null + } + + private fun attemptPick(player: EntityPlayer, targetInventory: IItemHandler, pickedStack: ItemStack): Boolean { + for (slot in 0 until targetInventory.slots) { + val wrapper = targetInventory.getStackInSlot(slot) + .getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: continue + if (tryRefill(player, wrapper, pickedStack)) { + return true + } + } + return false + } + + private fun tryRefill(player: EntityPlayer, wrapper: BackpackWrapper, pickedStack: ItemStack): Boolean = + wrapper.gatherCapabilityUpgrades(Capabilities.ADVANCED_REFILL_UPGRADE_CAPABILITY) + .filterIsInstance() + .any { it.pickBlock(player, wrapper, pickedStack) } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SStashToBackpackPacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SStashToBackpackPacket.kt new file mode 100644 index 0000000..b5ed868 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SStashToBackpackPacket.kt @@ -0,0 +1,112 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackStashHelper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import io.netty.buffer.ByteBuf +import net.minecraft.entity.player.EntityPlayerMP +import net.minecraft.item.ItemStack +import net.minecraft.network.play.server.SPacketSetSlot +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext +import net.minecraftforge.items.ItemHandlerHelper + +class C2SStashToBackpackPacket() : IRefinedMessage { + enum class Action { + CARRIED_TO_SLOT_BACKPACK, + SLOT_TO_CARRIED_BACKPACK + } + + private var slotNumber = -1 + private var action = Action.CARRIED_TO_SLOT_BACKPACK + + constructor(slotNumber: Int, action: Action) : this() { + this.slotNumber = slotNumber + this.action = action + } + + override fun toBytes(buf: ByteBuf) { + buf.writeInt(slotNumber) + buf.writeByte(action.ordinal) + } + + override fun fromBytes(buf: ByteBuf) { + slotNumber = buf.readInt() + action = Action.entries[buf.readUnsignedByte().toInt()] + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: C2SStashToBackpackPacket, ctx: MessageContext): IRefinedMessage? { + val player = ctx.serverHandler.player + player.serverWorld.addScheduledTask { + val container = player.openContainer ?: return@addScheduledTask + if (message.slotNumber !in 0 until container.inventorySlots.size) { + return@addScheduledTask + } + + when (message.action) { + Action.CARRIED_TO_SLOT_BACKPACK -> stashCarriedToSlotBackpack(player, container, message.slotNumber) + Action.SLOT_TO_CARRIED_BACKPACK -> stashSlotToCarriedBackpack(player, container, message.slotNumber) + } + } + return null + } + + private fun stashCarriedToSlotBackpack(player: EntityPlayerMP, container: net.minecraft.inventory.Container, slotNumber: Int) { + val carried = player.inventory.itemStack + if (carried.isEmpty) { + return + } + + val slot = container.getSlot(slotNumber) + val backpackStack = slot.stack + if (backpackStack.isEmpty || backpackStack.count != 1 || !slot.canTakeStack(player)) { + return + } + + val wrapper = backpackStack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return + val remaining = BackpackStashHelper.stash(wrapper, carried, false) + if (remaining.count == carried.count) { + return + } + + player.inventory.itemStack = if (remaining.isEmpty) ItemStack.EMPTY else remaining + syncCarriedStack(player) + slot.putStack(backpackStack) + slot.onSlotChanged() + container.detectAndSendChanges() + } + + private fun stashSlotToCarriedBackpack(player: EntityPlayerMP, container: net.minecraft.inventory.Container, slotNumber: Int) { + val backpackStack = player.inventory.itemStack + if (backpackStack.isEmpty || backpackStack.count != 1) { + return + } + + val wrapper = backpackStack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return + val slot = container.getSlot(slotNumber) + val slotStack = slot.stack + if (slotStack.isEmpty || !slot.canTakeStack(player)) { + return + } + + val remaining = BackpackStashHelper.stash(wrapper, slotStack, true) + val moved = slotStack.count - remaining.count + if (moved <= 0) { + return + } + + val taken = slot.decrStackSize(moved) + val remainder = BackpackStashHelper.stash(wrapper, taken, false) + if (!remainder.isEmpty) { + ItemHandlerHelper.giveItemToPlayer(player, remainder) + } + slot.onTake(player, taken) + slot.onSlotChanged() + syncCarriedStack(player) + container.detectAndSendChanges() + } + + private fun syncCarriedStack(player: EntityPlayerMP) { + player.connection.sendPacket(SPacketSetSlot(-1, -1, player.inventory.itemStack)) + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt index 0962f22..ad7e73a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt @@ -3,11 +3,14 @@ package com.cleanroommc.retrosophisticatedbackpacks.proxy import com.cleanroommc.bogosorter.BogoSortAPI import com.cleanroommc.modularui.factory.GuiManager import com.cleanroommc.retrosophisticatedbackpacks.block.Blocks +import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackBlockEntityRenderer import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackDynamicModel +import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackItemStackRenderer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiFactory import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlot import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlotWrapper import com.cleanroommc.retrosophisticatedbackpacks.item.Items +import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.client.renderer.block.model.ModelResourceLocation import net.minecraft.client.settings.KeyBinding @@ -79,6 +82,12 @@ abstract class RSBProxy { for (keyBinding in KEYBINDS) ClientRegistry.registerKeyBinding(keyBinding) + + ClientRegistry.bindTileEntitySpecialRenderer(BackpackTileEntity::class.java, BackpackBlockEntityRenderer()) + + for (backpackItem in Items.BACKPACK_ITEMS) { + backpackItem.tileEntityItemStackRenderer = BackpackItemStackRenderer() + } } override fun preInit(event: FMLPreInitializationEvent) { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt index 7b897e8..a1d9828 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt @@ -1,18 +1,34 @@ package com.cleanroommc.retrosophisticatedbackpacks.sync import com.cleanroommc.modularui.value.sync.SyncHandler +import com.cleanroommc.retrosophisticatedbackpacks.backpack.DisplaySide import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHelper import com.cleanroommc.retrosophisticatedbackpacks.backpack.SortType import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity +import net.minecraft.item.EnumDyeColor import net.minecraft.network.PacketBuffer import net.minecraftforge.items.wrapper.PlayerMainInvWrapper -class BackpackSH(private val playerInv: PlayerMainInvWrapper, private val wrapper: BackpackWrapper) : SyncHandler() { +class BackpackSH( + private val playerInv: PlayerMainInvWrapper, + private val wrapper: BackpackWrapper, + private val tileEntity: BackpackTileEntity? = null +) : SyncHandler() { companion object { const val UPDATE_SET_SORT_TYPE = 0 const val UPDATE_SORT_INV = 1 const val UPDATE_TRANSFER_TO_BACKPACK_INV = 2 const val UPDATE_TRANSFER_TO_PLAYER_INV = 3 + const val UPDATE_TOGGLE_SETTINGS_CONTEXT = 4 + const val UPDATE_TOGGLE_SHIFT_CLICK_INTO_OPEN_TAB = 5 + const val UPDATE_TOGGLE_KEEP_TAB_OPEN = 6 + const val UPDATE_TOGGLE_KEEP_SEARCH_PHRASE = 7 + const val UPDATE_TOGGLE_ANOTHER_PLAYER_CAN_OPEN = 8 + const val UPDATE_ITEM_DISPLAY_SLOT = 9 + const val UPDATE_ITEM_DISPLAY_ROTATION = 10 + const val UPDATE_ITEM_DISPLAY_COLOR = 11 + const val UPDATE_ITEM_DISPLAY_SIDE = 12 } override fun readOnClient(id: Int, buf: PacketBuffer) {} @@ -23,6 +39,21 @@ class BackpackSH(private val playerInv: PlayerMainInvWrapper, private val wrappe UPDATE_SORT_INV -> sortInventory(buf) UPDATE_TRANSFER_TO_BACKPACK_INV -> transferToBackpack(buf) UPDATE_TRANSFER_TO_PLAYER_INV -> transferToPlayerInventory(buf) + UPDATE_TOGGLE_SETTINGS_CONTEXT -> wrapper.toggleSettingsContext() + UPDATE_TOGGLE_SHIFT_CLICK_INTO_OPEN_TAB -> wrapper.toggleShiftClickIntoOpenTab() + UPDATE_TOGGLE_KEEP_TAB_OPEN -> wrapper.toggleKeepTabOpen() + UPDATE_TOGGLE_KEEP_SEARCH_PHRASE -> wrapper.toggleKeepSearchPhrase() + UPDATE_TOGGLE_ANOTHER_PLAYER_CAN_OPEN -> wrapper.toggleAnotherPlayerCanOpen() + UPDATE_ITEM_DISPLAY_SLOT -> updateItemDisplaySlot(buf) + UPDATE_ITEM_DISPLAY_ROTATION -> updateItemDisplayRotation(buf) + UPDATE_ITEM_DISPLAY_COLOR -> { + wrapper.itemDisplayColor = buf.readEnumValue(EnumDyeColor::class.java) + syncRenderState() + } + UPDATE_ITEM_DISPLAY_SIDE -> { + wrapper.itemDisplaySide = buf.readEnumValue(DisplaySide::class.java) + syncRenderState() + } else -> {} } } @@ -65,4 +96,24 @@ class BackpackSH(private val playerInv: PlayerMainInvWrapper, private val wrappe BackpackInventoryHelper.transferBackpackToPlayerInventory(wrapper, playerInv, transferMatched) } -} \ No newline at end of file + + private fun updateItemDisplaySlot(buf: PacketBuffer) { + val slotIndex = buf.readInt() + val selected = buf.readBoolean() + if (selected) { + wrapper.selectItemDisplaySlot(slotIndex) + } else { + wrapper.unselectItemDisplaySlot(slotIndex) + } + syncRenderState() + } + + private fun updateItemDisplayRotation(buf: PacketBuffer) { + wrapper.rotateItemDisplaySlot(buf.readInt(), buf.readBoolean()) + syncRenderState() + } + + private fun syncRenderState() { + tileEntity?.syncRenderState() + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/DelegatedStackHandlerSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/DelegatedStackHandlerSH.kt index ab43d58..514d289 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/DelegatedStackHandlerSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/DelegatedStackHandlerSH.kt @@ -20,6 +20,10 @@ open class DelegatedStackHandlerSH( ) : SyncHandler() { companion object { const val UPDATE_FILTERABLE = 0 + const val UPDATE_JUKEBOX = 1 + const val UPDATE_TANK = 2 + const val UPDATE_BATTERY = 3 + const val UPDATE_ANVIL = 4 } var delegatedStackHandler: DelegatedItemHandler = DelegatedItemHandler(EmptyHandler::INSTANCE, wrappedSlotAmount) @@ -40,6 +44,28 @@ open class DelegatedStackHandlerSH( setDelegatedStackHandler(wrapper::filterItems) } + + UPDATE_JUKEBOX -> { + val wrapper = stack.getCapability(Capabilities.IJUKEBOX_UPGRADE_CAPABILITY, null) ?: return + + setDelegatedStackHandler(wrapper::discInventory) + } + + UPDATE_TANK -> { + val wrapper = stack.getCapability(Capabilities.ITANK_UPGRADE_CAPABILITY, null) ?: return + + setDelegatedStackHandler(wrapper::getInventory) + } + + UPDATE_BATTERY -> { + val wrapper = stack.getCapability(Capabilities.IBATTERY_UPGRADE_CAPABILITY, null) ?: return + setDelegatedStackHandler(wrapper::getInventory) + } + + UPDATE_ANVIL -> { + val wrapper = stack.getCapability(Capabilities.IANVIL_UPGRADE_CAPABILITY, null) ?: return + setDelegatedStackHandler(wrapper::getInventory) + } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt index 9de1dcf..9dc8d18 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt @@ -6,15 +6,31 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedFeedingUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CraftingUpgradeWrapper.CraftingDestination import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IAdvancedFilterable +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IAnvilUpgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IBasicFilterable import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IFilterUpgrade +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IPumpUpgrade +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RefillUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RepeatMode +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.ToolSwapMode +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidType +import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer +import net.minecraft.entity.player.EntityPlayerMP +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound import net.minecraft.network.PacketBuffer +import net.minecraftforge.fluids.FluidUtil +import net.minecraftforge.items.IItemHandlerModifiable /** * Used to synchronize upgrade item's capability, this is only fired from client to reflect client's action to server * side. */ -class UpgradeSlotSH(slot: ModularSlot) : ItemSlotSH(slot) { +class UpgradeSlotSH( + slot: ModularSlot, + private val onClientSlotUpdate: () -> Unit = {} +) : ItemSlotSH(slot) { companion object { const val UPDATE_UPGRADE_TAB_STATE = 6 const val UPDATE_UPGRADE_TOGGLE = 7 @@ -23,6 +39,51 @@ class UpgradeSlotSH(slot: ModularSlot) : ItemSlotSH(slot) { const val UPDATE_ADVANCED_FEEDING = 10 const val UPDATE_FILTER_WAY = 11 const val UPDATE_CRAFTING_DESTINATION = 12 + const val UPDATE_VOID_TYPE = 13 + const val UPDATE_COMPACT_NON_UNCRAFTABLE = 14 + const val UPDATE_REFILL_TARGET_SLOT = 15 + const val UPDATE_VOID_WORK_IN_GUI = 16 + const val UPDATE_COMPACT_WORK_IN_GUI = 17 + const val UPDATE_JUKEBOX_PLAY = 18 + const val UPDATE_JUKEBOX_STOP = 19 + const val UPDATE_JUKEBOX_NEXT = 20 + const val UPDATE_JUKEBOX_PREVIOUS = 21 + const val UPDATE_JUKEBOX_SHUFFLE = 22 + const val UPDATE_JUKEBOX_REPEAT_MODE = 23 + const val UPDATE_TOOL_SWAPPER_SWAP_WEAPON = 24 + const val UPDATE_TOOL_SWAPPER_MODE = 25 + const val UPDATE_TANK_CLICK = 26 + const val UPDATE_PUMP_INPUT = 27 + const val UPDATE_PUMP_HAND = 28 + const val UPDATE_PUMP_WORLD = 29 + const val UPDATE_PUMP_FLUID_HANDLERS = 30 + const val UPDATE_PUMP_FLUID_FILTER = 31 + const val UPDATE_ANVIL_ITEM_NAME = 32 + const val UPDATE_ANVIL_SHIFT_CLICK = 33 + const val UPDATE_ANVIL_TAKE_RESULT = 34 + const val UPDATE_REOPEN_BACKPACK = 35 + } + + private var lastCapabilityNbt = NBTTagCompound() + + override fun onSlotUpdate(stack: ItemStack, onlyAmountChanged: Boolean, client: Boolean, init: Boolean) { + if (client && !onlyAmountChanged) { + (slot.itemHandler as? IItemHandlerModifiable)?.setStackInSlot(slot.slotIndex, stack) + } + super.onSlotUpdate(stack, onlyAmountChanged, client, init) + if (client) { + onClientSlotUpdate() + } + } + + override fun detectAndSendChanges(init: Boolean) { + super.detectAndSendChanges(init) + val wrapper = slot.stack.getCapability(Capabilities.UPGRADE_CAPABILITY, null) ?: return + val capabilityNbt = wrapper.serializeNBT() + if (init || capabilityNbt != lastCapabilityNbt) { + lastCapabilityNbt = capabilityNbt.copy() + forceSyncItem() + } } override fun readOnServer(id: Int, buf: PacketBuffer) { @@ -36,9 +97,38 @@ class UpgradeSlotSH(slot: ModularSlot) : ItemSlotSH(slot) { UPDATE_ADVANCED_FEEDING -> updateAdvanceFeedingUpgrade(buf) UPDATE_FILTER_WAY -> updateFilterUpgrade(buf) UPDATE_CRAFTING_DESTINATION -> updateCraftingDestination(buf) + UPDATE_VOID_TYPE -> updateVoidType(buf) + UPDATE_COMPACT_NON_UNCRAFTABLE -> updateCompactNonUncraftable() + UPDATE_REFILL_TARGET_SLOT -> updateRefillTargetSlot(buf) + UPDATE_VOID_WORK_IN_GUI -> updateVoidWorkInGui() + UPDATE_COMPACT_WORK_IN_GUI -> updateCompactWorkInGui() + UPDATE_JUKEBOX_PLAY -> updateJukeboxPlay() + UPDATE_JUKEBOX_STOP -> updateJukeboxStop() + UPDATE_JUKEBOX_NEXT -> updateJukeboxNext() + UPDATE_JUKEBOX_PREVIOUS -> updateJukeboxPrevious() + UPDATE_JUKEBOX_SHUFFLE -> updateJukeboxShuffle() + UPDATE_JUKEBOX_REPEAT_MODE -> updateJukeboxRepeatMode(buf) + UPDATE_TOOL_SWAPPER_SWAP_WEAPON -> updateToolSwapperSwapWeapon() + UPDATE_TOOL_SWAPPER_MODE -> updateToolSwapperMode(buf) + UPDATE_TANK_CLICK -> updateTankClick() + UPDATE_PUMP_INPUT -> updatePumpInput(buf) + UPDATE_PUMP_HAND -> updatePumpHand() + UPDATE_PUMP_WORLD -> updatePumpWorld() + UPDATE_PUMP_FLUID_HANDLERS -> updatePumpFluidHandlers() + UPDATE_PUMP_FLUID_FILTER -> updatePumpFluidFilter(buf) + UPDATE_ANVIL_ITEM_NAME -> updateAnvilItemName(buf) + UPDATE_ANVIL_SHIFT_CLICK -> updateAnvilShiftClick() + UPDATE_ANVIL_TAKE_RESULT -> updateAnvilTakeResult() + UPDATE_REOPEN_BACKPACK -> reopenBackpackGui() } } + private fun reopenBackpackGui() { + val player = syncManager.player as? EntityPlayerMP ?: return + val container = player.openContainer as? BackpackContainer ?: return + container.reopenBackpackGui(player) + } + private fun updateTabState(buf: PacketBuffer) { val wrapper = slot.stack.getCapability(Capabilities.UPGRADE_CAPABILITY, null) ?: return wrapper.isTabOpened = buf.readBoolean() @@ -92,4 +182,122 @@ class UpgradeSlotSH(slot: ModularSlot) : ItemSlotSH(slot) { wrapper.craftingDestination = buf.readEnumValue(CraftingDestination::class.java) } -} \ No newline at end of file + + private fun updateVoidType(buf: PacketBuffer) { + val voidType = buf.readEnumValue(VoidType::class.java) + slot.stack.getCapability(Capabilities.VOID_UPGRADE_CAPABILITY, null)?.voidType = voidType + slot.stack.getCapability(Capabilities.ADVANCED_VOID_UPGRADE_CAPABILITY, null)?.voidType = voidType + } + + private fun updateCompactNonUncraftable() { + slot.stack.getCapability(Capabilities.COMPACTING_UPGRADE_CAPABILITY, null)?.toggleCompactNonUncraftable() + slot.stack.getCapability(Capabilities.ADVANCED_COMPACTING_UPGRADE_CAPABILITY, null)?.toggleCompactNonUncraftable() + } + + private fun updateVoidWorkInGui() { + slot.stack.getCapability(Capabilities.VOID_UPGRADE_CAPABILITY, null)?.toggleWorkInGui() + slot.stack.getCapability(Capabilities.ADVANCED_VOID_UPGRADE_CAPABILITY, null)?.toggleWorkInGui() + } + + private fun updateCompactWorkInGui() { + slot.stack.getCapability(Capabilities.COMPACTING_UPGRADE_CAPABILITY, null)?.toggleWorkInGui() + slot.stack.getCapability(Capabilities.ADVANCED_COMPACTING_UPGRADE_CAPABILITY, null)?.toggleWorkInGui() + } + + private fun updateRefillTargetSlot(buf: PacketBuffer) { + val filterSlot = buf.readInt() + val targetSlot = buf.readEnumValue(RefillUpgradeWrapper.TargetSlot::class.java) + slot.stack.getCapability(Capabilities.ADVANCED_REFILL_UPGRADE_CAPABILITY, null)?.setTargetSlot(filterSlot, targetSlot) + } + + private fun jukebox(): JukeboxUpgradeWrapper? = + slot.stack.getCapability(Capabilities.JUKEBOX_UPGRADE_CAPABILITY, null) + ?: slot.stack.getCapability(Capabilities.ADVANCED_JUKEBOX_UPGRADE_CAPABILITY, null) + + private fun updateJukeboxPlay() { + jukebox()?.requestPlay() + } + + private fun updateJukeboxStop() { + jukebox()?.requestStop() + } + + private fun updateJukeboxNext() { + jukebox()?.next() + } + + private fun updateJukeboxPrevious() { + jukebox()?.previous() + } + + private fun updateJukeboxShuffle() { + jukebox()?.toggleShuffle() + } + + private fun updateJukeboxRepeatMode(buf: PacketBuffer) { + jukebox()?.repeatMode = buf.readEnumValue(RepeatMode::class.java) + } + + private fun updateToolSwapperSwapWeapon() { + val wrapper = slot.stack.getCapability(Capabilities.ADVANCED_TOOL_SWAPPER_UPGRADE_CAPABILITY, null) ?: return + wrapper.shouldSwapWeapon = !wrapper.shouldSwapWeapon + } + + private fun updateToolSwapperMode(buf: PacketBuffer) { + val wrapper = slot.stack.getCapability(Capabilities.ADVANCED_TOOL_SWAPPER_UPGRADE_CAPABILITY, null) ?: return + wrapper.toolSwapMode = buf.readEnumValue(ToolSwapMode::class.java) + } + + private fun updateTankClick() { + val wrapper = slot.stack.getCapability(Capabilities.TANK_UPGRADE_CAPABILITY, null) ?: return + val player = slot.getSyncHandler().syncManager.player + val backpackWrapper = (player.openContainer as? BackpackContainer)?.backpackWrapper ?: return + if (player.inventory.itemStack.count <= 1) { + wrapper.interactWithCursorStack(player, backpackWrapper) + } + } + + private fun pump(): IPumpUpgrade? = + slot.stack.getCapability(Capabilities.IPUMP_UPGRADE_CAPABILITY, null) + + private fun updatePumpInput(buf: PacketBuffer) { + pump()?.isInput = buf.readBoolean() + } + + private fun updatePumpHand() { + pump()?.let { it.interactWithHand = !it.interactWithHand } + } + + private fun updatePumpWorld() { + pump()?.let { it.interactWithWorld = !it.interactWithWorld } + } + + private fun updatePumpFluidHandlers() { + pump()?.let { it.interactWithFluidHandlers = !it.interactWithFluidHandlers } + } + + private fun updatePumpFluidFilter(buf: PacketBuffer) { + val wrapper = pump() ?: return + val slotIndex = buf.readInt() + val carried = slot.getSyncHandler().syncManager.player.inventory.itemStack + val fluid = if (carried.isEmpty) null else FluidUtil.getFluidContained(carried.copy()) + wrapper.setFluidFilter(slotIndex, fluid) + } + + private fun anvil(): IAnvilUpgrade? = + slot.stack.getCapability(Capabilities.IANVIL_UPGRADE_CAPABILITY, null) + + private fun updateAnvilItemName(buf: PacketBuffer) { + anvil()?.itemName = buf.readString(64) + } + + private fun updateAnvilShiftClick() { + anvil()?.let { it.shouldShiftClickIntoStorage = !it.shouldShiftClickIntoStorage } + } + + private fun updateAnvilTakeResult() { + val wrapper = anvil() ?: return + val player = slot.getSyncHandler().syncManager.player + wrapper.takeResult(player, player.world) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt index 44a948d..8044087 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt @@ -7,7 +7,10 @@ import com.cleanroommc.modularui.screen.ModularPanel import com.cleanroommc.modularui.screen.UISettings import com.cleanroommc.modularui.value.sync.PanelSyncManager import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks +import com.cleanroommc.retrosophisticatedbackpacks.block.BackpackBlock import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackFluidHandler +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackEnergyStorage import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackGuiHolder @@ -19,6 +22,7 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.network.NetworkManager import net.minecraft.network.play.server.SPacketUpdateTileEntity import net.minecraft.tileentity.TileEntity +import net.minecraft.util.ITickable import net.minecraft.util.EnumFacing import net.minecraft.util.math.BlockPos import net.minecraft.util.text.ITextComponent @@ -26,11 +30,14 @@ import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.items.CapabilityItemHandler +import net.minecraftforge.fluids.capability.CapabilityFluidHandler +import net.minecraftforge.energy.CapabilityEnergy import net.minecraftforge.items.IItemHandler class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : TileEntity(), IItemHandler, + ITickable, IGuiHolder { companion object { private const val BACKPACK_INVENTORY_TAG = "backpackInventory" @@ -58,10 +65,14 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : override fun getCapability(capability: Capability, facing: EnumFacing?): T? = if (capability == Capabilities.BACKPACK_CAPABILITY) wrapper as T else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) this as T + else if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade()) BackpackFluidHandler(wrapper) as T + else if (capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade()) BackpackEnergyStorage(wrapper) as T else null override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = - wrapper.hasCapability(capability, facing) + wrapper.hasCapability(capability, facing) || + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade() || + capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade() override fun writeToNBT(compound: NBTTagCompound): NBTTagCompound { compound.setTag(BACKPACK_INVENTORY_TAG, wrapper.serializeNBT()) @@ -83,15 +94,32 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : uiSettings: UISettings ): ModularPanel { val backpackInv = getCapability(Capabilities.BACKPACK_CAPABILITY, null)!! - val containerSupplier = { BackpackContainer(backpackInv, null) } + val containerSupplier = { BackpackContainer(backpackInv, null, tilePos = data.blockPos) } uiSettings.customContainer(containerSupplier) val holder: BackpackGuiHolder.TileEntityGuiHolder = BackpackGuiHolder.TileEntityGuiHolder(backpackInv) return holder.buildUI(data, syncManager, uiSettings) } + fun syncRenderState() { + if (!hasWorld()) { + return + } + markDirty() + val state = world.getBlockState(pos) + world.notifyBlockUpdate(pos, state, state, 3) + } + override fun getDisplayName(): ITextComponent = TextComponentTranslation("container.backpack".asTranslationKey()) + override fun update() { + if (!world.isRemote && world.totalWorldTime % 5L == 0L) { + wrapper.tickUpgrades(null, world, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, pos) + syncTankState() + syncBatteryState() + } + } + override fun getSlots(): Int = wrapper.slots @@ -102,9 +130,18 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : slot: Int, stack: ItemStack, simulate: Boolean - ): ItemStack = - if (wrapper.canInsert(stack)) wrapper.backpackItemStackHandler.prioritizedInsertion(slot, stack, simulate) - else stack + ): ItemStack { + if (!wrapper.canInsert(stack)) { + return stack + } + + val stack = wrapper.onBeforeInsert(stack) + if (stack.isEmpty) { + return ItemStack.EMPTY + } + val remaining = wrapper.backpackItemStackHandler.prioritizedInsertion(slot, stack, simulate) + return wrapper.onInsertRemainder(remaining) + } override fun extractItem( slot: Int, @@ -116,4 +153,30 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : override fun getSlotLimit(slot: Int): Int = wrapper.getSlotLimit(slot) -} \ No newline at end of file + + private fun syncTankState() { + val state = world.getBlockState(pos) + if (state.block !is BackpackBlock) { + return + } + val (leftTank, rightTank) = wrapper.tankRenderSides() + if (state.getValue(BackpackBlock.LEFT_TANK) != leftTank || state.getValue(BackpackBlock.RIGHT_TANK) != rightTank) { + world.setBlockState( + pos, + state.withProperty(BackpackBlock.LEFT_TANK, leftTank).withProperty(BackpackBlock.RIGHT_TANK, rightTank), + 3 + ) + } + } + + private fun syncBatteryState() { + val state = world.getBlockState(pos) + if (state.block !is BackpackBlock) { + return + } + val battery = wrapper.hasBatteryUpgrade() + if (state.getValue(BackpackBlock.BATTERY) != battery) { + world.setBlockState(pos, state.withProperty(BackpackBlock.BATTERY, battery), 3) + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/DyeColorUtils.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/DyeColorUtils.kt new file mode 100644 index 0000000..c2fb329 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/DyeColorUtils.kt @@ -0,0 +1,17 @@ +package com.cleanroommc.retrosophisticatedbackpacks.util + +import com.cleanroommc.retrosophisticatedbackpacks.mixin.EnumDyeColorAccessor +import net.minecraft.item.EnumDyeColor + +object DyeColorUtils { + private val fallbackColors = intArrayOf( + 16383998, 16351261, 13061821, 3847130, + 16701501, 8439583, 15961002, 4673362, + 10329495, 1481884, 8991416, 3949738, + 8606770, 6192150, 11546150, 1908001 + ) + + fun colorValue(color: EnumDyeColor): Int = + ((color as Any) as? EnumDyeColorAccessor)?.`rsb$getColorValue`() + ?: fallbackColors.getOrElse(color.ordinal) { 0xFF0000 } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang index 02c55e8..71808c3 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang @@ -73,25 +73,55 @@ retro_sophisticated_backpacks.tooltip.shift_to_reveal= # Gui Elements retro_sophisticated_backpacks.container.backpack=Backpack -retro_sophisticated_backpacks.gui.pickup_settings=Pickup Settings -retro_sophisticated_backpacks.gui.advanced_pickup_settings=Adv. Pickup Settings - -retro_sophisticated_backpacks.gui.feeding_settings=Feeding Settings -retro_sophisticated_backpacks.gui.advanced_feeding_settings=Adv. Feeding Settings - -retro_sophisticated_backpacks.gui.deposit_settings=Deposit Settings -retro_sophisticated_backpacks.gui.advanced_deposit_settings=Adv. Deposit Settings - -retro_sophisticated_backpacks.gui.restock_settings=Restock Settings -retro_sophisticated_backpacks.gui.advanced_restock_settings=Adv. Restock Settings - -retro_sophisticated_backpacks.gui.filter_settings=Filter Settings -retro_sophisticated_backpacks.gui.advanced_filter_settings=Adv. Filter Settings - -retro_sophisticated_backpacks.gui.crafting_settings=Crafting - -retro_sophisticated_backpacks.gui.memory_settings=Memory Settings -retro_sophisticated_backpacks.gui.sorting_settings=Sorting Settings +retro_sophisticated_backpacks.gui.pickup_settings=Pickup +retro_sophisticated_backpacks.gui.advanced_pickup_settings=Adv. Pickup + +retro_sophisticated_backpacks.gui.feeding_settings=Feeding +retro_sophisticated_backpacks.gui.advanced_feeding_settings=Adv. Feeding + +retro_sophisticated_backpacks.gui.deposit_settings=Deposit +retro_sophisticated_backpacks.gui.advanced_deposit_settings=Adv. Deposit + +retro_sophisticated_backpacks.gui.restock_settings=Restock +retro_sophisticated_backpacks.gui.advanced_restock_settings=Adv. Restock + +retro_sophisticated_backpacks.gui.filter_settings=Filter +retro_sophisticated_backpacks.gui.advanced_filter_settings=Adv. Filter + +retro_sophisticated_backpacks.gui.crafting_settings=Craft + +retro_sophisticated_backpacks.gui.memory_settings=Memory +retro_sophisticated_backpacks.gui.sorting_settings=No Sort +retro_sophisticated_backpacks.gui.backpack_settings=Backpack Settings +retro_sophisticated_backpacks.gui.item_display_settings=Item Display Settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=Backpack Settings +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Item Display Settings +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Allows selecting the backpack slot rendered on the backpack\nOpen tab to modify item display +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Allows selecting the backpack slot rendered on the backpack\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.settings_button.context_player=Player +retro_sophisticated_backpacks.gui.settings_button.context_backpack=Backpack +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Player settings context +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=Backpack settings context +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift-click into open tab +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift-click normally +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Keep tab open +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Close tab after action +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep search phrase +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Clear search phrase +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=Other players can open +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=Only owner can open +retro_sophisticated_backpacks.gui.settings_button.rotate=Rotate display item +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Left click rotates clockwise\nRight click rotates counter-clockwise +retro_sophisticated_backpacks.gui.settings_button.item_display_color=Display color +retro_sophisticated_backpacks.gui.settings_button.display_side_front=Display on front +retro_sophisticated_backpacks.gui.settings_button.display_side_left=Display on left +retro_sophisticated_backpacks.gui.settings_button.display_side_right=Display on right +retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=Count: %s / %s @@ -145,6 +175,7 @@ retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transfer Ma retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift To Transfer All retro_sophisticated_backpacks.gui.settings=Settings +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Back To Backpack retro_sophisticated_backpacks.gui.configuration_tab=Configuration Tab retro_sophisticated_backpacks.gui.memorized_slot=Memorized Slot @@ -154,3 +185,97 @@ retro_sophisticated_backpacks.gui.unmemorize_all=Forget All Slots retro_sophisticated_backpacks.gui.no_sorting_slot=No Sorting Slot retro_sophisticated_backpacks.gui.lock_all_sort=Select All Slots For No Sorting retro_sophisticated_backpacks.gui.unlock_all_sort=Select All Slots For Sorting + +item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade +item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade +item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade +item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade +retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack +retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations +retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack +retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations +retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack +retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations +retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes +retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations +retro_sophisticated_backpacks.gui.magnet_settings=Magnet +retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet +retro_sophisticated_backpacks.gui.void_settings=Void +retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void +retro_sophisticated_backpacks.gui.refill_settings=Refill +retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill +retro_sophisticated_backpacks.gui.compacting_settings=Compa... +retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting +retro_sophisticated_backpacks.gui.void_always=Void Always +retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow +retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow +retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes +retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes +retro_sophisticated_backpacks.gui.refill_target_any=Any Slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand +retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 +retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI +retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade +item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade +item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade +item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade +item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade +retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction +retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack +retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack +retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking +retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support +retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack +retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks +retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls +retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack +retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting +retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper +retro_sophisticated_backpacks.gui.tank_settings=Tank +retro_sophisticated_backpacks.gui.pump_settings=Pump +retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump +retro_sophisticated_backpacks.gui.battery_settings=Battery +retro_sophisticated_backpacks.gui.anvil_settings=Anvil +retro_sophisticated_backpacks.gui.pump_input=Pump In +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers +retro_sophisticated_backpacks.gui.pump_world=World +retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.anvil_no_result=No Result +retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage +retro_sophisticated_backpacks.gui.jukebox_play=Play +retro_sophisticated_backpacks.gui.jukebox_stop=Stop +retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc +retro_sophisticated_backpacks.gui.jukebox_next=Next Disc +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All +retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang index f4e537b..c771c8d 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang @@ -34,4 +34,105 @@ retro_sophisticated_backpacks.tooltip.inception_upgrade=Permite que las mochilas retro_sophisticated_backpacks.tooltip.shift_to_reveal= #Elementos de GUI -retro_sophisticated_backpacks.container.backpack=Mochila \ No newline at end of file +retro_sophisticated_backpacks.container.backpack=Mochila + +item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade +item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade +item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade +item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade +retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack +retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations +retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack +retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations +retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack +retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations +retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes +retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations +retro_sophisticated_backpacks.gui.magnet_settings=Magnet +retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet +retro_sophisticated_backpacks.gui.void_settings=Void +retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void +retro_sophisticated_backpacks.gui.refill_settings=Refill +retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill +retro_sophisticated_backpacks.gui.compacting_settings=Compa... +retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting +retro_sophisticated_backpacks.gui.void_always=Void Always +retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow +retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow +retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes +retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes +retro_sophisticated_backpacks.gui.refill_target_any=Any Slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand +retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 +retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI +retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade +item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade +item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade +item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade +item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade +retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction +retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack +retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack +retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking +retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support +retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack +retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks +retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls +retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack +retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting +retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper +retro_sophisticated_backpacks.gui.tank_settings=Tank +retro_sophisticated_backpacks.gui.pump_settings=Pump +retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump +retro_sophisticated_backpacks.gui.battery_settings=Battery +retro_sophisticated_backpacks.gui.anvil_settings=Anvil +retro_sophisticated_backpacks.gui.pump_input=Pump In +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers +retro_sophisticated_backpacks.gui.pump_world=World +retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.anvil_no_result=No Result +retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage +retro_sophisticated_backpacks.gui.jukebox_play=Play +retro_sophisticated_backpacks.gui.jukebox_stop=Stop +retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc +retro_sophisticated_backpacks.gui.jukebox_next=Next Disc +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All +retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Back To Backpack +retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang index 0300ade..952d930 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang @@ -73,23 +73,29 @@ retro_sophisticated_backpacks.tooltip.shift_to_reveal= # Gui Elements retro_sophisticated_backpacks.container.backpack=バックパック -retro_sophisticated_backpacks.gui.pickup_settings=収集機能の設定 -retro_sophisticated_backpacks.gui.advanced_pickup_settings=強化収集機能の設定 +retro_sophisticated_backpacks.gui.pickup_settings=収集 +retro_sophisticated_backpacks.gui.advanced_pickup_settings=強化収集 -retro_sophisticated_backpacks.gui.feeding_settings=食事機能の設定 -retro_sophisticated_backpacks.gui.advanced_feeding_settings=強化食事機能の設定 +retro_sophisticated_backpacks.gui.feeding_settings=食事 +retro_sophisticated_backpacks.gui.advanced_feeding_settings=強化食事 -retro_sophisticated_backpacks.gui.deposit_settings=収納機能の設定 -retro_sophisticated_backpacks.gui.advanced_deposit_settings=強化収納機能の設定 +retro_sophisticated_backpacks.gui.deposit_settings=収納 +retro_sophisticated_backpacks.gui.advanced_deposit_settings=強化収納 -retro_sophisticated_backpacks.gui.restock_settings=回収機能の設定 -retro_sophisticated_backpacks.gui.advanced_restock_settings=強化回収機能の設定 +retro_sophisticated_backpacks.gui.restock_settings=回収 +retro_sophisticated_backpacks.gui.advanced_restock_settings=強化回収 -retro_sophisticated_backpacks.gui.filter_settings=フィルター機能の設定 -retro_sophisticated_backpacks.gui.advanced_filter_settings=強化フィルター機能の設定 +retro_sophisticated_backpacks.gui.filter_settings=フィルター +retro_sophisticated_backpacks.gui.advanced_filter_settings=強化フィルター -retro_sophisticated_backpacks.gui.memory_settings=記憶機能の設定 -retro_sophisticated_backpacks.gui.sorting_settings=並べ替え機能の設定 +retro_sophisticated_backpacks.gui.memory_settings=記憶 +retro_sophisticated_backpacks.gui.sorting_settings=並べ替え無効 +retro_sophisticated_backpacks.gui.memory_settings.tooltip=スロット記憶設定 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=内容を記憶し、一致するアイテムのみ収納するスロットを選択します\nタブを開いてスロット設定を変更します +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=内容を記憶し、一致するアイテムのみ収納するスロットを選択します\n全選択/全解除=ボタン\n選択=左クリック/ドラッグ\n解除=右クリック/ドラッグ +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=並べ替え除外設定 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=並べ替え時に無視されるスロットを選択します\nタブを開いてスロット設定を変更します +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=並べ替え時に無視されるスロットを選択します\n全選択/全解除=ボタン\n選択=左クリック/ドラッグ\n解除=右クリック/ドラッグ # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=個数: %s / %s @@ -137,6 +143,7 @@ retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=一致す retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shiftを押してすべて移動 retro_sophisticated_backpacks.gui.settings=設定 +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=戻る retro_sophisticated_backpacks.gui.configuration_tab=構成タブ retro_sophisticated_backpacks.gui.memorized_slot=記憶スロット @@ -146,3 +153,97 @@ retro_sophisticated_backpacks.gui.unmemorize_all=全てのスロットの記憶 retro_sophisticated_backpacks.gui.no_sorting_slot=並べ替え無効スロット retro_sophisticated_backpacks.gui.lock_all_sort=全てのスロットを並べ替え無効にする retro_sophisticated_backpacks.gui.unlock_all_sort=全てのスロットの並べ替え無効を解除する + +item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade +item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade +item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade +item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade +retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack +retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations +retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack +retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations +retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack +retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations +retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes +retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations +retro_sophisticated_backpacks.gui.magnet_settings=Magnet +retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet +retro_sophisticated_backpacks.gui.void_settings=Void +retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void +retro_sophisticated_backpacks.gui.refill_settings=Refill +retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill +retro_sophisticated_backpacks.gui.compacting_settings=Compa... +retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting +retro_sophisticated_backpacks.gui.void_always=Void Always +retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow +retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow +retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes +retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes +retro_sophisticated_backpacks.gui.refill_target_any=Any Slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand +retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 +retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI +retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade +item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade +item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade +item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade +item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade +retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction +retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack +retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack +retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking +retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support +retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack +retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks +retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls +retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack +retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting +retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper +retro_sophisticated_backpacks.gui.tank_settings=Tank +retro_sophisticated_backpacks.gui.pump_settings=Pump +retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump +retro_sophisticated_backpacks.gui.battery_settings=Battery +retro_sophisticated_backpacks.gui.anvil_settings=Anvil +retro_sophisticated_backpacks.gui.pump_input=Pump In +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers +retro_sophisticated_backpacks.gui.pump_world=World +retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.anvil_no_result=No Result +retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage +retro_sophisticated_backpacks.gui.jukebox_play=Play +retro_sophisticated_backpacks.gui.jukebox_stop=Stop +retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc +retro_sophisticated_backpacks.gui.jukebox_next=Next Disc +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All +retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang index e47b57d..6094eeb 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang @@ -73,25 +73,31 @@ retro_sophisticated_backpacks.tooltip.shift_to_reveal= #Элементы интерфейса (GUI) -retro_sophisticated_backpacks.container.backpack=Рюкзак \ No newline at end of file +retro_sophisticated_backpacks.container.backpack=Рюкзак + +item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade +item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade +item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade +item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade +retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack +retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations +retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack +retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations +retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack +retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations +retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes +retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations +retro_sophisticated_backpacks.gui.magnet_settings=Magnet +retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet +retro_sophisticated_backpacks.gui.void_settings=Void +retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void +retro_sophisticated_backpacks.gui.refill_settings=Refill +retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill +retro_sophisticated_backpacks.gui.compacting_settings=Compa... +retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting +retro_sophisticated_backpacks.gui.void_always=Void Always +retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow +retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow +retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes +retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes +retro_sophisticated_backpacks.gui.refill_target_any=Any Slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand +retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 +retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI +retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade +item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade +item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade +item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade +item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade +retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction +retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack +retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack +retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking +retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support +retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack +retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks +retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls +retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack +retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting +retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper +retro_sophisticated_backpacks.gui.tank_settings=Tank +retro_sophisticated_backpacks.gui.pump_settings=Pump +retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump +retro_sophisticated_backpacks.gui.battery_settings=Battery +retro_sophisticated_backpacks.gui.anvil_settings=Anvil +retro_sophisticated_backpacks.gui.pump_input=Pump In +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers +retro_sophisticated_backpacks.gui.pump_world=World +retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.anvil_no_result=No Result +retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage +retro_sophisticated_backpacks.gui.jukebox_play=Play +retro_sophisticated_backpacks.gui.jukebox_stop=Stop +retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc +retro_sophisticated_backpacks.gui.jukebox_next=Next Disc +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All +retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Back To Backpack +retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang index c9ad4d7..68b49ab 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang @@ -73,23 +73,53 @@ retro_sophisticated_backpacks.tooltip.shift_to_reveal=<按Shift显示> # Gui Elements retro_sophisticated_backpacks.container.backpack=背包 -retro_sophisticated_backpacks.gui.pickup_settings=拾取设置 -retro_sophisticated_backpacks.gui.advanced_pickup_settings=高级拾取设置 - -retro_sophisticated_backpacks.gui.feeding_settings=喂食设置 -retro_sophisticated_backpacks.gui.advanced_feeding_settings=高级喂食设置 - -retro_sophisticated_backpacks.gui.deposit_settings=卸货设置 -retro_sophisticated_backpacks.gui.advanced_deposit_settings=高级卸货设置 - -retro_sophisticated_backpacks.gui.restock_settings=取货设置 -retro_sophisticated_backpacks.gui.advanced_restock_settings=高级取货设置 - -retro_sophisticated_backpacks.gui.filter_settings=过滤设置 -retro_sophisticated_backpacks.gui.advanced_filter_settings=高级过滤设置 - -retro_sophisticated_backpacks.gui.memory_settings=记忆设置 -retro_sophisticated_backpacks.gui.sorting_settings=整理设置 +retro_sophisticated_backpacks.gui.pickup_settings=拾取 +retro_sophisticated_backpacks.gui.advanced_pickup_settings=高级拾取 + +retro_sophisticated_backpacks.gui.feeding_settings=喂食 +retro_sophisticated_backpacks.gui.advanced_feeding_settings=高级喂食 + +retro_sophisticated_backpacks.gui.deposit_settings=卸货 +retro_sophisticated_backpacks.gui.advanced_deposit_settings=高级卸货 + +retro_sophisticated_backpacks.gui.restock_settings=取货 +retro_sophisticated_backpacks.gui.advanced_restock_settings=高级取货 + +retro_sophisticated_backpacks.gui.filter_settings=过滤 +retro_sophisticated_backpacks.gui.advanced_filter_settings=高级过滤 + +retro_sophisticated_backpacks.gui.memory_settings=记忆 +retro_sophisticated_backpacks.gui.sorting_settings=禁止整理 +retro_sophisticated_backpacks.gui.backpack_settings=背包设置 +retro_sophisticated_backpacks.gui.item_display_settings=物品显示设置 +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=背包设置 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=物品显示设置 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=选择渲染在背包上的背包槽位\n打开标签页以修改物品显示 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=选择渲染在背包上的背包槽位\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 +retro_sophisticated_backpacks.gui.settings_button.context_player=玩家 +retro_sophisticated_backpacks.gui.settings_button.context_backpack=背包 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=玩家设置上下文 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=背包设置上下文 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift点击优先进入打开的标签页 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift点击使用普通行为 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=保持标签页打开 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=操作后关闭标签页 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=保留搜索文本 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=清空搜索文本 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=其他玩家可打开 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=仅所有者可打开 +retro_sophisticated_backpacks.gui.settings_button.rotate=旋转显示物品 +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=左键顺时针旋转\n右键逆时针旋转 +retro_sophisticated_backpacks.gui.settings_button.item_display_color=显示颜色 +retro_sophisticated_backpacks.gui.settings_button.display_side_front=显示在正面 +retro_sophisticated_backpacks.gui.settings_button.display_side_left=显示在左侧 +retro_sophisticated_backpacks.gui.settings_button.display_side_right=显示在右侧 +retro_sophisticated_backpacks.gui.memory_settings.tooltip=槽位记忆设置 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=选择会记住当前物品的槽位,该槽位只接收匹配物品\n打开标签页以修改槽位设置 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=选择会记住当前物品的槽位,该槽位只接收匹配物品\n全选/取消全选槽位=按钮\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=忽略整理设置 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=选择整理时会被忽略的槽位\n打开标签页以修改槽位设置 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=选择整理时会被忽略的槽位\n全选/取消全选槽位=按钮\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=数量:%s / %s @@ -137,6 +167,7 @@ retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=转移匹 retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=按住Shift以转移所有物品 retro_sophisticated_backpacks.gui.settings=设置 +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=返回背包 retro_sophisticated_backpacks.gui.configuration_tab=设置标签页 retro_sophisticated_backpacks.gui.memorized_slot=被记忆的槽位 @@ -146,3 +177,97 @@ retro_sophisticated_backpacks.gui.unmemorize_all=遗忘所有槽位 retro_sophisticated_backpacks.gui.no_sorting_slot=禁止整理的槽位 retro_sophisticated_backpacks.gui.lock_all_sort=禁止整理所有槽位 retro_sophisticated_backpacks.gui.unlock_all_sort=允许整理所有槽位 + +item.retro_sophisticated_backpacks.magnet_upgrade.name=磁铁升级 +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=高级磁铁升级 +item.retro_sophisticated_backpacks.void_upgrade.name=虚空升级 +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=高级虚空升级 +item.retro_sophisticated_backpacks.refill_upgrade.name=补货升级 +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=高级补货升级 +item.retro_sophisticated_backpacks.compacting_upgrade.name=压缩升级 +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=高级压缩升级 +retro_sophisticated_backpacks.tooltip.magnet_upgrade=将附近物品吸入背包 +retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=将附近物品吸入背包,拥有更多过滤选项 +retro_sophisticated_backpacks.tooltip.void_upgrade=在物品进入背包前销毁匹配物品 +retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=在物品进入背包前销毁匹配物品,拥有更多过滤选项 +retro_sophisticated_backpacks.tooltip.refill_upgrade=从背包补充玩家物品栏中匹配的物品堆 +retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=从背包补充玩家物品栏中匹配的物品堆,拥有更多过滤选项 +retro_sophisticated_backpacks.tooltip.compacting_upgrade=使用 2x2 配方压缩匹配物品 +retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=使用 2x2 和 3x3 配方压缩匹配物品,拥有更多过滤选项 +retro_sophisticated_backpacks.gui.magnet_settings=磁铁 +retro_sophisticated_backpacks.gui.advanced_magnet_settings=高级磁铁 +retro_sophisticated_backpacks.gui.void_settings=虚空 +retro_sophisticated_backpacks.gui.advanced_void_settings=高级虚空 +retro_sophisticated_backpacks.gui.refill_settings=补货 +retro_sophisticated_backpacks.gui.advanced_refill_settings=高级补货 +retro_sophisticated_backpacks.gui.compacting_settings=压缩 +retro_sophisticated_backpacks.gui.advanced_compacting_settings=高级压缩 +retro_sophisticated_backpacks.gui.void_always=总是销毁 +retro_sophisticated_backpacks.gui.void_slot_overflow=槽位溢出时销毁 +retro_sophisticated_backpacks.gui.void_storage_overflow=背包满时销毁 +retro_sophisticated_backpacks.gui.compact_uncraftable_only=仅可逆配方 +retro_sophisticated_backpacks.gui.compact_any_recipe=所有压缩配方 +retro_sophisticated_backpacks.gui.refill_target_any=任意槽位 +retro_sophisticated_backpacks.gui.refill_target_main_hand=主手 +retro_sophisticated_backpacks.gui.refill_target_off_hand=副手 +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=快捷栏 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=快捷栏 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=快捷栏 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=快捷栏 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=快捷栏 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=快捷栏 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=快捷栏 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=快捷栏 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=快捷栏 9 +retro_sophisticated_backpacks.gui.work_in_gui_disabled=不在GUI中工作 +retro_sophisticated_backpacks.gui.work_in_gui_enabled=在GUI中工作 +item.retro_sophisticated_backpacks.everlasting_upgrade.name=永恒升级 +item.retro_sophisticated_backpacks.jukebox_upgrade.name=唱片机升级 +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=高级唱片机升级 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=工具切换升级 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=高级工具切换升级 +item.retro_sophisticated_backpacks.tank_upgrade.name=储罐升级 +item.retro_sophisticated_backpacks.pump_upgrade.name=泵升级 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=高级泵升级 +item.retro_sophisticated_backpacks.battery_upgrade.name=电池升级 +item.retro_sophisticated_backpacks.anvil_upgrade.name=铁砧升级 +retro_sophisticated_backpacks.tooltip.everlasting_upgrade=防止背包物品因自然消失、爆炸和方块破坏而丢失 +retro_sophisticated_backpacks.tooltip.jukebox_upgrade=从背包播放音乐唱片 +retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=从背包播放多张音乐唱片 +retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=挖掘或攻击时从背包切换工具 +retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=从背包切换工具,并支持额外交互 +retro_sophisticated_backpacks.tooltip.tank_upgrade=为背包添加流体存储 +retro_sophisticated_backpacks.tooltip.pump_upgrade=在背包储罐与世界或相邻储罐之间转移流体 +retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=带过滤和额外交互控制的流体转移升级 +retro_sophisticated_backpacks.tooltip.battery_upgrade=为背包添加能量存储 +retro_sophisticated_backpacks.tooltip.anvil_upgrade=从背包中修复和重命名物品 +retro_sophisticated_backpacks.gui.everlasting_settings=永恒 +retro_sophisticated_backpacks.gui.jukebox_settings=唱片机 +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=唱片机 +retro_sophisticated_backpacks.gui.tool_swapper_settings=工具切换 +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=高级工具切换 +retro_sophisticated_backpacks.gui.tank_settings=储罐 +retro_sophisticated_backpacks.gui.pump_settings=泵 +retro_sophisticated_backpacks.gui.advanced_pump_settings=高级泵 +retro_sophisticated_backpacks.gui.battery_settings=电池 +retro_sophisticated_backpacks.gui.anvil_settings=铁砧 +retro_sophisticated_backpacks.gui.pump_input=输入 +retro_sophisticated_backpacks.gui.pump_fluid_handlers=流体处理器 +retro_sophisticated_backpacks.gui.pump_world=世界 +retro_sophisticated_backpacks.gui.pump_hand=手持容器 +retro_sophisticated_backpacks.gui.anvil_no_result=无结果 +retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift 点击背包存储 +retro_sophisticated_backpacks.gui.jukebox_play=播放 +retro_sophisticated_backpacks.gui.jukebox_stop=停止 +retro_sophisticated_backpacks.gui.jukebox_previous=上一张唱片 +retro_sophisticated_backpacks.gui.jukebox_next=下一张唱片 +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=关闭随机播放 +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=开启随机播放 +retro_sophisticated_backpacks.gui.jukebox_repeat_all=列表循环 +retro_sophisticated_backpacks.gui.jukebox_repeat_one=单曲循环 +retro_sophisticated_backpacks.gui.jukebox_repeat_no=关闭循环 +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=不切换武器 +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=切换武器 +retro_sophisticated_backpacks.gui.tool_swapper_any=切换任意物品 +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=仅切换工具 +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=不自动切换工具 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang index 9f90e90..f751a2a 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang @@ -73,25 +73,31 @@ retro_sophisticated_backpacks.tooltip.shift_to_reveal=<按 Shift 顯示> # Gui Elements retro_sophisticated_backpacks.container.backpack=背包 -retro_sophisticated_backpacks.gui.pickup_settings=拾取設定 -retro_sophisticated_backpacks.gui.advanced_pickup_settings=進階拾取設定 +retro_sophisticated_backpacks.gui.pickup_settings=拾取 +retro_sophisticated_backpacks.gui.advanced_pickup_settings=進階拾取 -retro_sophisticated_backpacks.gui.feeding_settings=餵食設定 -retro_sophisticated_backpacks.gui.advanced_feeding_settings=進階餵食設定 +retro_sophisticated_backpacks.gui.feeding_settings=餵食 +retro_sophisticated_backpacks.gui.advanced_feeding_settings=進階餵食 -retro_sophisticated_backpacks.gui.deposit_settings=卸貨設定 -retro_sophisticated_backpacks.gui.advanced_deposit_settings=進階卸貨設定 +retro_sophisticated_backpacks.gui.deposit_settings=卸貨 +retro_sophisticated_backpacks.gui.advanced_deposit_settings=進階卸貨 -retro_sophisticated_backpacks.gui.restock_settings=取貨設定 -retro_sophisticated_backpacks.gui.advanced_restock_settings=進階取貨設定 +retro_sophisticated_backpacks.gui.restock_settings=取貨 +retro_sophisticated_backpacks.gui.advanced_restock_settings=進階取貨 -retro_sophisticated_backpacks.gui.filter_settings=過濾設定 -retro_sophisticated_backpacks.gui.advanced_filter_settings=進階過濾設定 +retro_sophisticated_backpacks.gui.filter_settings=過濾 +retro_sophisticated_backpacks.gui.advanced_filter_settings=進階過濾 retro_sophisticated_backpacks.gui.crafting_settings=合成 -retro_sophisticated_backpacks.gui.memory_settings=記憶設定 -retro_sophisticated_backpacks.gui.sorting_settings=整理設定 +retro_sophisticated_backpacks.gui.memory_settings=記憶 +retro_sophisticated_backpacks.gui.sorting_settings=禁止整理 +retro_sophisticated_backpacks.gui.memory_settings.tooltip=槽位記憶設定 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=選擇會記住目前物品的欄位,該欄位只接收匹配物品\n開啟標籤頁以修改欄位設定 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=選擇會記住目前物品的欄位,該欄位只接收匹配物品\n全選/取消全選欄位=按鈕\n選擇欄位=左鍵單擊/拖曳\n取消選擇欄位=右鍵單擊/拖曳 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=忽略整理設定 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=選擇整理時會被忽略的欄位\n開啟標籤頁以修改欄位設定 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=選擇整理時會被忽略的欄位\n全選/取消全選欄位=按鈕\n選擇欄位=左鍵單擊/拖曳\n取消選擇欄位=右鍵單擊/拖曳 # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=數量: %s / %s @@ -145,6 +151,7 @@ retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=轉移對 retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift 以轉移全部 retro_sophisticated_backpacks.gui.settings=設定 +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=返回背包 retro_sophisticated_backpacks.gui.configuration_tab=設定介面 retro_sophisticated_backpacks.gui.memorized_slot=記憶欄位 @@ -154,3 +161,97 @@ retro_sophisticated_backpacks.gui.unmemorize_all=遺忘所有欄位 retro_sophisticated_backpacks.gui.no_sorting_slot=禁止整理欄位 retro_sophisticated_backpacks.gui.lock_all_sort=禁止整理所有欄位 retro_sophisticated_backpacks.gui.unlock_all_sort=允許整理所有欄位 + +item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade +item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade +item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade +item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade +retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack +retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations +retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack +retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations +retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack +retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations +retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes +retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations +retro_sophisticated_backpacks.gui.magnet_settings=磁鐵 +retro_sophisticated_backpacks.gui.advanced_magnet_settings=進階磁鐵 +retro_sophisticated_backpacks.gui.void_settings=虛空 +retro_sophisticated_backpacks.gui.advanced_void_settings=進階虛空 +retro_sophisticated_backpacks.gui.refill_settings=補貨 +retro_sophisticated_backpacks.gui.advanced_refill_settings=進階補貨 +retro_sophisticated_backpacks.gui.compacting_settings=壓縮 +retro_sophisticated_backpacks.gui.advanced_compacting_settings=進階壓縮 +retro_sophisticated_backpacks.gui.void_always=Void Always +retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow +retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow +retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes +retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes +retro_sophisticated_backpacks.gui.refill_target_any=Any Slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand +retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 +retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI +retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade +item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade +item.retro_sophisticated_backpacks.pump_upgrade.name=泵升級 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=進階泵升級 +item.retro_sophisticated_backpacks.battery_upgrade.name=電池升級 +item.retro_sophisticated_backpacks.anvil_upgrade.name=鐵砧升級 +retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction +retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack +retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack +retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking +retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support +retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack +retro_sophisticated_backpacks.tooltip.pump_upgrade=在背包儲罐與世界或相鄰儲罐之間轉移流體 +retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=帶過濾和額外交互控制的流體轉移升級 +retro_sophisticated_backpacks.tooltip.battery_upgrade=為背包加入能量儲存 +retro_sophisticated_backpacks.tooltip.anvil_upgrade=從背包中修復和重新命名物品 +retro_sophisticated_backpacks.gui.everlasting_settings=永恆 +retro_sophisticated_backpacks.gui.jukebox_settings=唱片機 +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=唱片機 +retro_sophisticated_backpacks.gui.tool_swapper_settings=工具切換 +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=進階工具切換 +retro_sophisticated_backpacks.gui.tank_settings=儲罐 +retro_sophisticated_backpacks.gui.pump_settings=泵 +retro_sophisticated_backpacks.gui.advanced_pump_settings=進階泵 +retro_sophisticated_backpacks.gui.battery_settings=電池 +retro_sophisticated_backpacks.gui.anvil_settings=鐵砧 +retro_sophisticated_backpacks.gui.pump_input=輸入 +retro_sophisticated_backpacks.gui.pump_fluid_handlers=流體處理器 +retro_sophisticated_backpacks.gui.pump_world=世界 +retro_sophisticated_backpacks.gui.pump_hand=手持容器 +retro_sophisticated_backpacks.gui.anvil_no_result=無結果 +retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift 點擊背包儲存 +retro_sophisticated_backpacks.gui.jukebox_play=Play +retro_sophisticated_backpacks.gui.jukebox_stop=Stop +retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc +retro_sophisticated_backpacks.gui.jukebox_next=Next Disc +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All +retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_left_tank.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_left_tank.json new file mode 100644 index 0000000..3078738 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_left_tank.json @@ -0,0 +1,144 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [32, 32], + "textures": { + "particle": "retro_sophisticated_backpacks:block/backpack_cloth", + "border": "retro_sophisticated_backpacks:block/backpack_border", + "modules": "retro_sophisticated_backpacks:block/backpack_modules" + }, + "elements": [ + { + "name": "back", + "from": [12.5, 1.5, 6], + "to": [13.5, 7.5, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [2.5, 5.5, 2, 8.5], "texture": "#modules"}, + "east": {"uv": [2, 5.5, 0, 8.5], "texture": "#modules"}, + "south": {"uv": [3, 5.5, 2.5, 8.5], "texture": "#modules"}, + "west": {"uv": [5, 5, 3, 9], "texture": "#modules"}, + "up": {"uv": [5.5, 5, 5, 7], "texture": "#modules"}, + "down": {"uv": [5.5, 7, 5, 9], "texture": "#modules"} + } + }, + { + "name": "cap", + "from": [12.5, 10.5, 6.5], + "to": [15.5, 11.5, 9.5], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [8, 6.5, 6.5, 7], "texture": "#modules"}, + "east": {"uv": [8, 7, 6.5, 7.5], "texture": "#modules"}, + "south": {"uv": [8.5, 5, 8, 6.5], "rotation": 90, "texture": "#modules"}, + "west": {"uv": [8, 9, 6.5, 9.5], "texture": "#modules"}, + "up": {"uv": [8, 5, 6.5, 6.5], "texture": "#modules"}, + "down": {"uv": [8, 7.5, 6.5, 9], "texture": "#modules"} + } + }, + { + "name": "cap-bottom", + "from": [13, 9.5, 6], + "to": [16, 10.5, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [3.5, 13.5, 2, 14], "texture": "#modules"}, + "east": {"uv": [2, 12, 0, 12.5], "texture": "#modules"}, + "south": {"uv": [3.5, 12, 2, 12.5], "texture": "#modules"}, + "west": {"uv": [2, 13.5, 0, 15], "texture": "#modules"}, + "up": {"uv": [5, 12, 3.5, 14], "texture": "#modules"}, + "down": {"uv": [6.5, 12, 5, 14], "texture": "#modules"} + } + }, + { + "name": "trim", + "from": [13, 8.5, 6], + "to": [16, 9.5, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [7.5, 2, 6, 2.5], "texture": "#border", "tintindex": 1}, + "east": {"uv": [8, 2.5, 6, 3], "texture": "#border", "tintindex": 1}, + "south": {"uv": [7.5, 3, 6, 3.5], "texture": "#border", "tintindex": 1}, + "west": {"uv": [2, 13.5, 0, 15], "texture": "#border", "tintindex": 1}, + "up": {"uv": [5, 12, 3.5, 14], "texture": "#border", "tintindex": 1}, + "down": {"uv": [6.5, 12, 5, 14], "texture": "#border", "tintindex": 1} + } + }, + { + "name": "top", + "from": [13, 7.5, 6], + "to": [16, 8.5, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [3.5, 14.5, 2, 15], "texture": "#modules"}, + "east": {"uv": [2, 13, 0, 13.5], "texture": "#modules"}, + "south": {"uv": [3.5, 13, 2, 13.5], "texture": "#modules"}, + "west": {"uv": [2, 13.5, 0, 15], "texture": "#modules"}, + "up": {"uv": [5, 12, 3.5, 14], "texture": "#modules"}, + "down": {"uv": [6.5, 12, 5, 14], "texture": "#modules"} + } + }, + { + "name": "bottom", + "from": [13, 0.5, 6], + "to": [16, 1.5, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [1.5, 11, 0, 11.5], "texture": "#modules"}, + "east": {"uv": [3.5, 9, 1.5, 9.5], "texture": "#modules"}, + "south": {"uv": [1.5, 11.5, 0, 12], "texture": "#modules"}, + "west": {"uv": [3.5, 9.5, 1.5, 10], "texture": "#modules"}, + "up": {"uv": [1.5, 9, 0, 11], "texture": "#modules"}, + "down": {"uv": [3, 10, 1.5, 12], "texture": "#modules"} + } + }, + { + "name": "front-glass", + "from": [15.5, 1.5, 6.5], + "to": [15.5, 7.5, 9.5], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [4.5, 0, 2.5, 5], "texture": "#modules"}, + "east": {"uv": [2.5, 0, 0, 5], "texture": "#modules"}, + "south": {"uv": [6.5, 0, 4.5, 5], "texture": "#modules"}, + "west": {"uv": [0, 0, 2.5, 5], "texture": "#modules"}, + "up": {"uv": [8.5, 0, 6.5, 2.5], "texture": "#modules"}, + "down": {"uv": [8.5, 2.5, 6.5, 5], "texture": "#modules"} + } + }, + { + "name": "left-glass", + "from": [13.5, 1.5, 9.5], + "to": [15.5, 7.5, 9.5], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [4.5, 0, 6.5, 5], "texture": "#modules"}, + "east": {"uv": [2.5, 0, 0, 5], "texture": "#modules"}, + "south": {"uv": [6.5, 0, 4.5, 5], "texture": "#modules"}, + "west": {"uv": [2.5, 0, 0, 5], "texture": "#modules"}, + "up": {"uv": [8.5, 0, 6.5, 2.5], "texture": "#modules"}, + "down": {"uv": [8.5, 2.5, 6.5, 5], "texture": "#modules"} + } + }, + { + "name": "right-glass", + "from": [13.5, 1.5, 6.5], + "to": [15.5, 7.5, 6.5], + "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, + "faces": { + "north": {"uv": [4.5, 0, 2.5, 5], "texture": "#modules"}, + "east": {"uv": [2.5, 0, 0, 5], "texture": "#modules"}, + "south": {"uv": [2.5, 0, 4.5, 5], "texture": "#modules"}, + "west": {"uv": [2.5, 0, 0, 5], "texture": "#modules"}, + "up": {"uv": [8.5, 0, 6.5, 2.5], "texture": "#modules"}, + "down": {"uv": [8.5, 2.5, 6.5, 5], "texture": "#modules"} + } + } + ], + "groups": [ + { + "name": "left-tank", + "origin": [16, 0, 0], + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8] + } + ] +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_right_tank.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_right_tank.json new file mode 100644 index 0000000..44e661b --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/block/backpack_right_tank.json @@ -0,0 +1,135 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [32, 32], + "textures": { + "particle": "retro_sophisticated_backpacks:block/backpack_cloth", + "border": "retro_sophisticated_backpacks:block/backpack_border", + "modules": "retro_sophisticated_backpacks:block/backpack_modules" + }, + "elements": [ + { + "name": "back", + "from": [2.5, 1.5, 6], + "to": [3.5, 7.5, 10], + "faces": { + "north": {"uv": [2, 5.5, 2.5, 8.5], "texture": "#modules"}, + "east": {"uv": [3, 5, 5, 9], "texture": "#modules"}, + "south": {"uv": [2.5, 5.5, 3, 8.5], "texture": "#modules"}, + "west": {"uv": [0, 5.5, 2, 8.5], "texture": "#modules"}, + "up": {"uv": [5, 5, 5.5, 7], "texture": "#modules"}, + "down": {"uv": [5, 7, 5.5, 9], "texture": "#modules"} + } + }, + { + "name": "cap", + "from": [0.5, 10.5, 6.5], + "to": [3.5, 11.5, 9.5], + "faces": { + "north": {"uv": [6.5, 6.5, 8, 7], "texture": "#modules"}, + "east": {"uv": [6.5, 9, 8, 9.5], "texture": "#modules"}, + "south": {"uv": [8.5, 6.5, 8, 5], "rotation": 90, "texture": "#modules"}, + "west": {"uv": [6.5, 7, 8, 7.5], "texture": "#modules"}, + "up": {"uv": [6.5, 5, 8, 6.5], "texture": "#modules"}, + "down": {"uv": [6.5, 7.5, 8, 9], "texture": "#modules"} + } + }, + { + "name": "cap-bottom", + "from": [0, 9.5, 6], + "to": [3, 10.5, 10], + "faces": { + "north": {"uv": [2, 13.5, 3.5, 14], "texture": "#modules"}, + "east": {"uv": [0, 13.5, 2, 15], "texture": "#modules"}, + "south": {"uv": [2, 12, 3.5, 12.5], "texture": "#modules"}, + "west": {"uv": [0, 12, 2, 12.5], "texture": "#modules"}, + "up": {"uv": [3.5, 12, 5, 14], "texture": "#modules"}, + "down": {"uv": [5, 12, 6.5, 14], "texture": "#modules"} + } + }, + { + "name": "trim", + "from": [0, 8.5, 6], + "to": [3, 9.5, 10], + "faces": { + "north": {"uv": [6, 2, 7.5, 2.5], "texture": "#border", "tintindex": 1}, + "east": {"uv": [0, 13.5, 2, 15], "texture": "#border", "tintindex": 1}, + "south": {"uv": [6, 3, 7.5, 3.5], "texture": "#border", "tintindex": 1}, + "west": {"uv": [6, 2.5, 8, 3], "texture": "#border", "tintindex": 1}, + "up": {"uv": [3.5, 12, 5, 14], "texture": "#border", "tintindex": 1}, + "down": {"uv": [5, 12, 6.5, 14], "texture": "#border", "tintindex": 1} + } + }, + { + "name": "top", + "from": [0, 7.5, 6], + "to": [3, 8.5, 10], + "faces": { + "north": {"uv": [2, 14.5, 3.5, 15], "texture": "#modules"}, + "east": {"uv": [0, 13.5, 2, 15], "texture": "#modules"}, + "south": {"uv": [2, 13, 3.5, 13.5], "texture": "#modules"}, + "west": {"uv": [0, 13, 2, 13.5], "texture": "#modules"}, + "up": {"uv": [3.5, 12, 5, 14], "texture": "#modules"}, + "down": {"uv": [5, 12, 6.5, 14], "texture": "#modules"} + } + }, + { + "name": "bottom", + "from": [0, 0.5, 6], + "to": [3, 1.5, 10], + "faces": { + "north": {"uv": [0, 11, 1.5, 11.5], "texture": "#modules"}, + "east": {"uv": [1.5, 9.5, 3.5, 10], "texture": "#modules"}, + "south": {"uv": [0, 11.5, 1.5, 12], "texture": "#modules"}, + "west": {"uv": [1.5, 9, 3.5, 9.5], "texture": "#modules"}, + "up": {"uv": [0, 9, 1.5, 11], "texture": "#modules"}, + "down": {"uv": [1.5, 10, 3, 12], "texture": "#modules"} + } + }, + { + "name": "front-glass", + "from": [0.5, 1.5, 6.5], + "to": [0.5, 7.5, 9.5], + "faces": { + "north": {"uv": [2.5, 0, 4.5, 5], "texture": "#modules"}, + "east": {"uv": [2.5, 0, 0, 5], "texture": "#modules"}, + "south": {"uv": [4.5, 0, 6.5, 5], "texture": "#modules"}, + "west": {"uv": [0, 0, 2.5, 5], "texture": "#modules"}, + "up": {"uv": [6.5, 0, 8.5, 2.5], "texture": "#modules"}, + "down": {"uv": [6.5, 2.5, 8.5, 5], "texture": "#modules"} + } + }, + { + "name": "right-glass", + "from": [0.5, 1.5, 9.5], + "to": [2.5, 7.5, 9.5], + "faces": { + "north": {"uv": [6.5, 0, 4.5, 5], "texture": "#modules"}, + "east": {"uv": [0, 0, 2.5, 5], "texture": "#modules"}, + "south": {"uv": [4.5, 0, 6.5, 5], "texture": "#modules"}, + "west": {"uv": [0, 0, 2.5, 5], "texture": "#modules"}, + "up": {"uv": [6.5, 0, 8.5, 2.5], "texture": "#modules"}, + "down": {"uv": [6.5, 2.5, 8.5, 5], "texture": "#modules"} + } + }, + { + "name": "left-glass", + "from": [0.5, 1.5, 6.5], + "to": [2.5, 7.5, 6.5], + "faces": { + "north": {"uv": [2.5, 0, 4.5, 5], "texture": "#modules"}, + "east": {"uv": [0, 0, 2.5, 5], "texture": "#modules"}, + "south": {"uv": [4.5, 0, 2.5, 5], "texture": "#modules"}, + "west": {"uv": [0, 0, 2.5, 5], "texture": "#modules"}, + "up": {"uv": [6.5, 0, 8.5, 2.5], "texture": "#modules"}, + "down": {"uv": [6.5, 2.5, 8.5, 5], "texture": "#modules"} + } + } + ], + "groups": [ + { + "name": "right-tank", + "origin": [16, 0, 0], + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8] + } + ] +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_compacting_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_compacting_upgrade.json new file mode 100644 index 0000000..70a0681 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_compacting_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_compacting_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_jukebox_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_jukebox_upgrade.json new file mode 100644 index 0000000..bb0429b --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_jukebox_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_jukebox_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_magnet_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_magnet_upgrade.json new file mode 100644 index 0000000..0ba3697 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_magnet_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_magnet_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_pump_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_pump_upgrade.json new file mode 100644 index 0000000..9df2bad --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_pump_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_pump_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_refill_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_refill_upgrade.json new file mode 100644 index 0000000..e0b5537 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_refill_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_refill_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_tool_swapper_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_tool_swapper_upgrade.json new file mode 100644 index 0000000..7b54a68 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_tool_swapper_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_tool_swapper_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_void_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_void_upgrade.json new file mode 100644 index 0000000..be702d2 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_void_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_void_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/anvil_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/anvil_upgrade.json new file mode 100644 index 0000000..18a9f3c --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/anvil_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/anvil_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/battery_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/battery_upgrade.json new file mode 100644 index 0000000..05a160b --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/battery_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/battery_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/compacting_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/compacting_upgrade.json new file mode 100644 index 0000000..81a594f --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/compacting_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/compacting_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/everlasting_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/everlasting_upgrade.json new file mode 100644 index 0000000..b022c53 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/everlasting_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/everlasting_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/jukebox_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/jukebox_upgrade.json new file mode 100644 index 0000000..28244a8 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/jukebox_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/jukebox_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/magnet_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/magnet_upgrade.json new file mode 100644 index 0000000..8fa2e4c --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/magnet_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/magnet_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/pump_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/pump_upgrade.json new file mode 100644 index 0000000..b57b348 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/pump_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/pump_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/refill_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/refill_upgrade.json new file mode 100644 index 0000000..f605406 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/refill_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/refill_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/tank_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/tank_upgrade.json new file mode 100644 index 0000000..13b3959 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/tank_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/tank_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/tool_swapper_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/tool_swapper_upgrade.json new file mode 100644 index 0000000..aa5e342 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/tool_swapper_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/tool_swapper_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/void_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/void_upgrade.json new file mode 100644 index 0000000..4ba262a --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/void_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/void_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_compacting_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_compacting_upgrade.json new file mode 100644 index 0000000..90a863f --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_compacting_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "D": { + "item": "minecraft:diamond" + }, + "G": { + "item": "minecraft:gold_ingot" + }, + "R": { + "item": "minecraft:redstone" + }, + "C": { + "item": "retro_sophisticated_backpacks:compacting_upgrade" + } + }, + "pattern": [ + " D ", + "GCG", + "RRR" + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_compacting_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_jukebox_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_jukebox_upgrade.json new file mode 100644 index 0000000..da5fa43 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_jukebox_upgrade.json @@ -0,0 +1,22 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "D": { + "item": "minecraft:diamond" + }, + "R": { + "item": "minecraft:redstone" + }, + "J": { + "item": "retro_sophisticated_backpacks:jukebox_upgrade" + } + }, + "pattern": [ + " D ", + "RJR", + " R " + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_jukebox_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_magnet_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_magnet_upgrade.json new file mode 100644 index 0000000..597899e --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_magnet_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "D": { + "item": "minecraft:diamond" + }, + "G": { + "item": "minecraft:gold_ingot" + }, + "R": { + "item": "minecraft:redstone" + }, + "M": { + "item": "retro_sophisticated_backpacks:magnet_upgrade" + } + }, + "pattern": [ + " D ", + "GMG", + "RRR" + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_magnet_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_refill_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_refill_upgrade.json new file mode 100644 index 0000000..c7fed95 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_refill_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "D": { + "item": "minecraft:diamond" + }, + "G": { + "item": "minecraft:gold_ingot" + }, + "R": { + "item": "minecraft:redstone" + }, + "F": { + "item": "retro_sophisticated_backpacks:refill_upgrade" + } + }, + "pattern": [ + " D ", + "GFG", + "RRR" + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_refill_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_tool_swapper_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_tool_swapper_upgrade.json new file mode 100644 index 0000000..46c9cf9 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_tool_swapper_upgrade.json @@ -0,0 +1,22 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "D": { + "item": "minecraft:diamond" + }, + "S": { + "item": "minecraft:iron_sword" + }, + "T": { + "item": "retro_sophisticated_backpacks:tool_swapper_upgrade" + } + }, + "pattern": [ + " D ", + "STS", + " D " + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_tool_swapper_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_void_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_void_upgrade.json new file mode 100644 index 0000000..9abfa8a --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_void_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "D": { + "item": "minecraft:diamond" + }, + "G": { + "item": "minecraft:gold_ingot" + }, + "R": { + "item": "minecraft:redstone" + }, + "V": { + "item": "retro_sophisticated_backpacks:void_upgrade" + } + }, + "pattern": [ + " D ", + "GVG", + "RRR" + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_void_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/compacting_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/compacting_upgrade.json new file mode 100644 index 0000000..ba31349 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/compacting_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "I": { + "item": "minecraft:iron_ingot" + }, + "P": { + "item": "minecraft:piston" + }, + "R": { + "item": "minecraft:redstone" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + } + }, + "pattern": [ + "IPI", + "PBP", + "RPR" + ], + "result": { + "item": "retro_sophisticated_backpacks:compacting_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/everlasting_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/everlasting_upgrade.json new file mode 100644 index 0000000..f6cddbf --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/everlasting_upgrade.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "N": { + "item": "minecraft:nether_star" + }, + "O": { + "item": "minecraft:obsidian" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + } + }, + "pattern": [ + "O O", + "OBO", + " N " + ], + "result": { + "item": "retro_sophisticated_backpacks:everlasting_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/jukebox_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/jukebox_upgrade.json new file mode 100644 index 0000000..e1e6c99 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/jukebox_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "J": { + "item": "minecraft:jukebox" + }, + "N": { + "item": "minecraft:noteblock" + }, + "R": { + "item": "minecraft:redstone" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + } + }, + "pattern": [ + " N ", + "RBR", + " J " + ], + "result": { + "item": "retro_sophisticated_backpacks:jukebox_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/magnet_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/magnet_upgrade.json new file mode 100644 index 0000000..fc547e1 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/magnet_upgrade.json @@ -0,0 +1,29 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "E": { + "item": "minecraft:ender_pearl" + }, + "I": { + "item": "minecraft:iron_ingot" + }, + "R": { + "item": "minecraft:redstone" + }, + "L": { + "item": "minecraft:dye", + "data": 4 + }, + "P": { + "item": "retro_sophisticated_backpacks:pickup_upgrade" + } + }, + "pattern": [ + "EIE", + "IPI", + "R L" + ], + "result": { + "item": "retro_sophisticated_backpacks:magnet_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/refill_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/refill_upgrade.json new file mode 100644 index 0000000..ae5b726 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/refill_upgrade.json @@ -0,0 +1,28 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "E": { + "item": "minecraft:ender_pearl" + }, + "I": { + "item": "minecraft:iron_ingot" + }, + "R": { + "item": "minecraft:redstone" + }, + "C": { + "item": "minecraft:chest" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + } + }, + "pattern": [ + " E ", + "IBI", + "RCR" + ], + "result": { + "item": "retro_sophisticated_backpacks:refill_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/tank_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/tank_upgrade.json new file mode 100644 index 0000000..2396ce1 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/tank_upgrade.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "G": { + "type": "forge:ore_dict", + "ore": "blockGlass" + }, + "I": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + } + }, + "pattern": [ + "GIG", + "GBG", + "GIG" + ], + "result": { + "item": "retro_sophisticated_backpacks:tank_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/tool_swapper_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/tool_swapper_upgrade.json new file mode 100644 index 0000000..a27c01c --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/tool_swapper_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "P": { + "item": "minecraft:iron_pickaxe" + }, + "A": { + "item": "minecraft:iron_axe" + }, + "S": { + "item": "minecraft:iron_shovel" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + } + }, + "pattern": [ + " P ", + "ABA", + " S " + ], + "result": { + "item": "retro_sophisticated_backpacks:tool_swapper_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/void_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/void_upgrade.json new file mode 100644 index 0000000..9ca38e6 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/void_upgrade.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "E": { + "item": "minecraft:ender_pearl" + }, + "O": { + "item": "minecraft:obsidian" + }, + "R": { + "item": "minecraft:redstone" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + } + }, + "pattern": [ + " E ", + "OBO", + "ROR" + ], + "result": { + "item": "retro_sophisticated_backpacks:void_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/slots_background.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/slots_background.png index a631fe7c4f64f2c7b44ff605d5fcc7717e253e97..f1577755d2b1fa6e3a1e1901c394f03a89e821cc 100644 GIT binary patch literal 7615 zcmeHsRZtv2wB_IuJP8TzK?nE2o#5`l-NN95lK_L0;Dlhog1gJ$?k9t007`BD#&O807(BJ5&#qZpD_j(+W-Kh zj1X;o4^4A#>d#}h=jZO^XcS3)h zt~_=6EsbUElMf(D;uTniowZDj3?_W&wys_E4%elU+%MUYEJFOi% z<1P)LK4ISXDQP@pWkw+OsnGjsVB^(^kLhBYQ-ovMtm``onKFtdlCs4gK#R2x89;*{ zF_Lj4Puhr8VOKIzPMSp*t30xO+TkJHg*~33vfE{|_|y>MH-yH$irl0nOd}7$PxRT< zxunMDL{d6x38 zG+Co{*-h>}b}8!lSBx)#b&HxK<#jEVVy){vl(%*J?I-ms2w}v!rP{PRM>`%5XThfY zd$;^=@+6)Xjx#FaJuy6EA|qw%hOPG38jgFZds&WSt96B>m&XBz@{Vnp(+dnS-HPfz zbGeRjN!3b_aF$EP8=Tr2ON8c@blFr1*$jCklV@TbaB%;cJEiRzd5dTGl?Y%x)3qeemISXFbMwAe(K4J?Z*+@|IMZ$}V6C4~b$ zcpy;cqY?M58tV+=eW#fQp_uprXh)1IuYfH@oB2F&fmnp~hEPd*zN;}bNBSha$jq0e zW4v#S}k4f*WA%nGVw8@s|zD%(d7DsNL*>DdjDI7j12j`Io+1%R(#JS zmN{C^1fhDHCqoAUK!kLgHR1s-4BazlFo_6A<6;%3{l#yPTB?(TzRXBZc$?sVOzAyq zt;`5R*n#RhzU*SI8;u?Wa$Gp_I0g7@JIrSrE!|b4)*~vc3YJ5-3Z}I#+@o7hv+Oo- zsJ@Xmg~6|vM`c7S5axf|?~|%>zuNBwzmtItSmV5bi>R&2Z1rmpBGn+OL5(i- z;2-Au&aabtv1WEYS~IWWz5^jsv9+y4v8Cq71BY}`Ve<`9^w6k={CXOy+U)n<)%K)( zpT+8&FxK}q%MZ|ezY(C(PK3y<65S}Q5_yHe_Iow4%TN-B{Bbb*P<|Y-%4U0(OXVy1 zb_~Dc$@)>|8;@PA|m!6*pxds@44(&NvPZ?G^eIw{=W=S(q`u zn~l{tLneFAZoDUF?TWDe;qAv0D>dlXa^*vR=&QA0B%vyG7%lWxQja#2z$3@d+)UWW ztG$}}SEpxS%omm${q^-D^d3J`9=k*4;U98dAB&!AjfST{PVU zcV$o5;U(VGqHXj@_Mfv&y(<`3-UVsd7<_93pOa00P2#^jk_xu!FI@IOR8(~x}!0>HeSD}gxsJ>`%`1>t8la`U@|aRpQV*KCR>AqX>4JT zN6-nx+pX;AM&LFVmZRN!U8X+L(1aL|AP}P&{lsddRrU%iDynMKs;V8{?Kw;?0S2hb zt75prHbF_@f+!1Qznj{6#tGe;XX+k{4VN5NS8y+G-)3mbKIu1N7!#DT#@-28SVdQ) z7pLEZ$ooT04V1?dkv$k9L4!ymMqC@pOW5R{v6_^tmB~?2J*zanqGw#HP)#SHo)9UX zRX!XZMtqUj@@-x7z|F8nWE|tNtmPqAs|4H0b1d#b9=khKk{uFW|4^I@98xh!bYFDb zZ0au}U&7TAB#C(m7%DQ@bnj3oJ_n*Pw6 zCO|XT?I^R{TH2WGkKTcP%!PX0*XV+{F?+-*K#9nCK$D=WA-%5Db06%lTFKYIwCD*= z^CDr@1kMH8XWSN7q!#KqwOt4*bf#HdhGHtX)36cdiYjOC4l#4)g;0GXZYHG+?Wgij zFk1AnpgE%nS(WbUltgZh2o3sz3dTo!LC4ym#D2yl8Wer=NJgLF$K>-4YuqBNE!{0& zvL^2)H(h%Rl4XjkOCBxnY;Z2vN~RJAi7Cdmolyrhp;_w}id;l?Iw3Ec`2nTIcTzZL z^&b1fNGIdhlg#AGf6?$3XRSo^u$!sqUlDf{qox#SBlCVsH9#L-KI6n{!qi)IIK@(t z1Q;#FT914-Yx>&zH5Q?c?XO{EWY1FyrWMFdI8&wB#4kHu$QH*ulSM|Q{ zizCK{q>DPfE%gP)<23G*^M7%Y+V8;CMHOyU#1!1>vGkzkAJqFS`1@%y`3cNQzi66a z8kH)*S2^U>T!M6A!00AfBJdo27+)++AaL(amj6 zyu6%zX3w^JA*LADmq;1tL&S3CH+se&F(i>pUp+%BbNZ1dIKODDYg2j4Op2}O>Zx|A zVwuU-;--Gn@e~x%P~C7<94Xi|oN7GytV51oXasotRruO(0aj^G2|i-^U^+NkG6%Eg zLPi@OqT4vso{GrO!?*t}G_s~*n9>p>ZRsdJy>UkC=0MUXSO+lXt1xR$bomQ~8E(a9 zC_B{@5Dg!Y#=S{+n2T!JP%FRl{@vuk?72`vheSiK9NGS@TE9}a;aHq zOk8Zi2frYro++&Y8{`8~qztq`(I9X@QBpWbx8g}KKv=0+)p-uo+`_H3xTn&J7?jty z`JT3cy$8Sqm5gk8>Bl!fYoZ=UT3<*XiySplzaEe=0)dt6S*V?0kTu?s zm-^yN=OfCF%&1JFiP~TIP7IIg30b(G8X5zeG=&jm2%X5_)pw1ia}BE%I7a1D}u@3dJ#xtaA31} zYOc<-&VkeV47KVz;K`c^BQ<^6v^_sNE$Ti7ij5XRmk2D`>)AXoIvaGO^zZ^U{_D2G za~i3ZP^T2>a8=KlbT3FRW6we|UX2%3caU7-cx_XFIH~(Rn2yi_7y|Fi& z83eoxSl}ru)M-D#tqZseJg#-bAL(S8qI|n7+O;^#W@^BY^}9rXy%*)tLY*sk*wDN& zK(G6g2DUl6g&55->A!0&#>wb(cd>547zv&8uv91{7e1=6xnrjW#m)AZQut2W{b(s` z^xaw(iB2q;8yXK z=P}tf`6<6Y0J0_}a@Q_|pJ7UbhZVYO9n78@o(*Czu}^HdJyB4$;wy}n07qoqNMHde zM8xG9vXhCZm~D|W3Z%apEl|)W-Ehg=To$f#WGV2_m7~sej!jg#@y1(O+J}AlfRmKG z-bwN7SKj!-?=LRnAINIH5mTDPyd}Hgz;0=IZ@_bSy3f|tqlhft!aiTGEbH|q94LC6 z-g|17|1eaE!)m~=l!10A1Up-9racrP`l}yy@#{u{L!TIOc`c=`2N97XnN;XTQ z{~7?~>ID7px^d?`^GO`8IZdh)F{?{M*M}Jq#*P;;R9G2OZ+2!3sgc0!LxJa~{J`@DWK?-@&K!2VmTm zQ#BuBQ~4ykkSqGW!rRGTzemH+o4*ENnnpzLym>7ah6-P{7gte)S-*lv37b(KR-Z9X zkY#85%qq-UIg6@YP0d8VCwf+FYBHZf;ivtDrPX&ZrE)by0)=?82`94v#1e_goDvE z$t2P8D@(s#YugJb93rgF!>922xXS9TSb|8Y3`NP0gTHdgkZ2MNe0MwBG5Nrz z(5u;!{uvV1-odL?WKmjWEGF)DKxMqqB~mENIAk)lT?k}fFm&UDtt+V5M2_VJV6t%jZu(w z>j8&9HYzv*HT6fU$hsE>+J#)_1OA)G({jCr8=JObxzgoNN`)@0##3hM%fj#T&w%nj zMHXoy|K{!w^)r{>*@q5ZvMUs)s^pl4NU74IWrq`AL>Bil3eG}dc@30h6Cb=#BDxp< zP<6Yo_|XrKu#~M2A7wn2cmJ)BO)5&VIJTbHMb8Z*za z>M0h_O#RteGQLudU@HpSpB86#AE^|+H5oY6+nzFz@Jt}d7?&&ET~k%dqN_8loGx!lB) z-j~hcL1}#6%?vZ-uiUOKl@Br4GKy$k`P>VPuU#GzkL4B^11j3EMohB7c$+nFqMHG{ zh|D@cgfRJvo>P-xc2!f22KsJx|jFN^oR=j=h03|sH> zB!QJdw|iroV5&riw=MdGH3rAnhT?+(mpnV!Bwv6P`o-j_7@FY9#EBB@XW=or{JbK`CO0Q>$ZC>9e44y>dKs}ob=kiRB zKbXg%=2_q{&u|*iLymA%GVCd8T}?e(bP8YB&zu(9vyROqp2&!7kz|lU(Wb36@HBuZ zn!7c!)Iktbz^xkm(R;~QZLNW>_@zX6$hkb%@sI_U>9sKfbwVztPmKGRGk|vsBYK1_ zn-_H+4_%n3%ZXkKyA}6SK74HBcAtKhx+Nf{Z{xe_1CV*DH=ThnO5oBV{1G6h{%^W$ioAJM~ll0`F#BN7%E@Zul} z+kXXzh+KFjVhDcT1~(Kaw#=$W1_Hy~kdB*ljtF@3#qRR)Y8b$%-y`ZI@gnP1CcqQZ zsF!)TbZ6J*lWdO35N9SL$LnQj|0yZ$_12?1AVv}+qxPTZx-zZ=@`j{s;TlY9T`u3B zw&1 z_sZ(^pEo%o62u?BNS91CuSz+RIUp(=ymFE_j^1PrIV$Vm|NW-9_%=7l79)1{quN{$ zrwU)7x5lUdLvk(8CDnwMyD@ai#UW!pHptgB?-U1wp&C^f7&zNjQHqZV9KFrt6q zRP!B&YHzaD^jZ}ZjomB-6~<>&>^z~fne+AadMzmwE5C1~1PjLb6SxYj;9mTP3! zMvUAtB{6a#d@1x`=WIgqC8TpC7Dk2!s=+J5NLB>J^*lFNJl2 zbFQ31Za2qK{)j;cqW6cx7b$n{SmC+Ax6^}D04MA{Pd zPgnr_p%fc@6+G!Mp(k-)6Fp-_8$U;VDY^c6Y&y^zeb?LZyl>+bN%asm1u!=6zGQy1 zo`=1xN)?Ilexa|s!G_Suu*GlfQ+rX;g}Rerbl{rcEFoKSMi+!q^0RhWtc^alEHar? z4!)tbIBBNf{_IjI#n}w@4!n24K=0h;uk84MDLYwj>XW&z(v<7y{0IjhRqb`Ev(6*m zzDW_K0>bLEtxjr}!~Z-xI`G(C5z^P%^Nt z)}sNUy`q{wc2{=cZch2BzLEmvx{@@^G@$z|O=Ab2*B>ngpG#sK{>L3B0R{D06n#*! z>z>LyxT(lJ?aVTmocjEXOCl>4)*g>EN&4b8@Ai%nvG;4oU*hQUo=J!*;jh2g$BKbu zu^;i@FOhyv?Ek0Bca6v|NbKV{Mn0k?Vk*cJBby&%_W(~UJn|Ng-#+thDK@j-{UzkN zz3ndp%yjJUVcry4y2j)7lBeh|;O}&s=f2 z15X*l3fuh4zThhk;QH2AG!XMSn1F zX8Gas^jZcW@d2@+c6+aO?1&p#@w3%q`EPRe+L>+ndbUx;M*K`l{6H(M%YO9bFT(b@ zkk)6Nv2A?Rvp7@9g2$O$=4KU@Ln^CQtQOJ3ib}VR8Qu2G_)B|q2(;ysz@OzO*!Q-% zLZgU0e2s`#zlVyR7JpGZ+@|dAX9azT_n3d|Y54KY(&BC%52t4_@Z@%k|8F04#;Ugf zRVMIvt@SD!q;j(=1hdfow{t@AH^tF3FO;K@_>Htj=jrFck4RgBHEX7Le8cO%`xz;w zvyIS`sjg{UnR>IylO8XbD%Z{t+b`npq#AP8UQjrfU^q&uNO}J%I z_Hg3JN-`@AeX)Dvhh4cv@lzPe!i|J;?h?HIC;7xOrj=n#XvNcHERF({4H|H}x-kog zahnj*qI>9QbY97z0C|adL(byyV5LabSO81_H6R!OK>lyRxzE1uTBq4S+)r1v&KCq- z0tM)017&6j-Kj^>o2zGx(Q~cu<+~HUbj6(+GsX<=YXLp#W|HnD00TTaS zA6_SSm`PhaF%+O<3aXHkMdr3`I)eXF{vUvbSj%GdHl2FZ1gF`Tzg` literal 2743 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJE)I!_nJkczmsQw+IOZVEAf z4=X-l`6d38hP(X97hVyHN(ys~nx^xp^ZeidL9XLa*w-@CPatDRp~yiA#Hy=%MGI=-ckmrjm-_u}5G9ad8Y zgW?MLU!qo$Rx_`HT>5MZ;)R4W48<8dZa@P#DcsqXpn-T}7u#e6#=@iUlCB f)ksb7VE^NIw~(rwMT;}0fXwxD^>bP0l+XkKe7q*x diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_12.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_12.png new file mode 100644 index 0000000000000000000000000000000000000000..4f804b7d070151ff393073a4151f6c7f3cc170dd GIT binary patch literal 980 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJFd*`6+rAr-gY-Z_~2*g(MH z;=+lmo|s+fU@U#u%r)`WhAW{vrn?GB+&ijtYr>YF_jIQRCe60*V)E(ow``adw3hqX zoVoQYs(uA)$u&+s%%6K>+u9#(!IaApU&TN<7-uK<}4+pr2FObb>_YL@ZWCE((_MF$LP2o zsXq5Jk>TI*`D~9Zj_q3aY{uuemd`%}g}nZ!>HXwcFy)Va{sFp*U(@vU0%F-3`h)dkmkykdbbLM-mQ3 zMoX{5vl*8Sr5n!}K0giApmm>BCh>8vrTg<694s6R3JeVl3``8z84k)hEJnxY^qFoJ z+C5XbT+U^f*-$u^0$gU2sJP; zFfnj2C@@fqK|Pb;E*efoI>`13P7Ly@jGQKMyzn}^{rvOy7~{^}d!Ev--EgJ!?mPav zy>Yd(3Vysd@C|lxsrqu~c4Osw^^%=2NfK=x9TC^Bs&`Mf`V-GyOv_2Q@et3Va{l8cDgiNv5*-XciYt?SLDHLbTOI8kexVk|%XOCg}YZ>WAVDe>Q z5MXcsrDJRijT1m!XEJB>Isl#4Z)wIPx{vF|p<~j;+sgy2Qcy?vtxwl~nj5j9cZhbaoUb40Up_IaUlPjmsl6SMH z#Jd!2g9mcJbbsN_)Bn3QD}@b~PWiM+C;#`OChdm*E(=~;y=T&YJU5Tw+838i{bJ|N b{Ig?}o_0PVWZ#ZO3_#%N>gTe~DWM4frRxEB literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_9.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/gui/storage_background_9.png new file mode 100644 index 0000000000000000000000000000000000000000..371f86d986bbc6beb4934ea6e409e3bf33519cb1 GIT binary patch literal 4816 zcmdT{RZtx4k{#R(#C;l6BFebuMBt51D(PQP@lrn0PtK%QC1rOK>7ob0GQ~1lBs98Jph1v z7@%wDt!?E;>+T7%cXG9(_4aqSqqTeI^r!i5sV3XOmtML)@@fB-J=Wov=Tt7A*t?ND zE?y)ghbOG6!4qlD=W^g zc+0c!qTSVt(;o@KTn>88(O-#@J6%DE%X&xqAI35wYm?#rUi3zi76~I6kzk4CvEBAp z89ysK`SveCcVlr4*VBG^?l8>i{p$K@vNHcB`u;CZ!-DM=C>Vzw{g-OZt@BWwGw{t1 zKZtpAyMh5L6&FSy3yoQG&UxeNYTp7z{Ak8bG}T;A{uzxQ)Wl_{X|Jvp5mQzOA@vck z3)$+5VowyJAMXp<@LC%0;j^*Es6)z*cQ7a={nV0iVV~)oo^{uelkjm(J?C9Z^R~-k zx>UA#`;9!mk4y-hwc-r$faRg$S z*?2>5u{)~!_?rU7#7QVGEG#r3q9s(g%{TF!2vX}fHsyrMA*Q@HAK6O4 z%9V?Dc`^wiyI_^teqse|9H#VQWzLeBj}yaFX$|ZOGfS>sV=WWbD!`U0XO{Pnvx0%# zfYXwBt7wXekiMju!J;_PF~-!=JS$k1eXiY{Ts5%e9-FZ_X8^r2+d{?T@Nz)whIwpE}5q#`u)gE_&C z$jl8^jX#C=o>!9eY18b%y9+My>vO=uRFcrPaRvYFo(u(B<@E(%X;b~j??{gRXnySq zLEyy(zZS96QUbPSThgRU4d1p6j;=_kXovbvV3S0IaY<9H{_aS0NC2pu)-{Y@XmQy7Fo(6egm^LBauT#4@e;} zd!Le@d|*FENgjkq5e=k#-Q(Ipz3N8pxBQ9F9Zg%!BUDjp&hhF-4xv!{(EQ&xY5ho` zc#NlW)LN{4f7sm(eU*VPU8qlf(3fXYE~@ho{n?32gVdcp&?()hkess2&u2`>mNzSM zr!STX@$G6ZP0LmxH+|kNKrN^@Pg*3yi4wm2O4XUp4gu*mT>pqfk&1yKuVa}?;L5y} zUcjtE-rvKiSyTMUC}IvL$=elv6gUAq_eA*vHqJotw@$8pW~}*|rq&R)%M4Xi0tm2YVSq zVzCDh124K0pJSb<;U&a47NdHLwW>ct%YsBUGJ5p^E;QY#M6^VU=L9x;>E%7Gm8_)E zo-`*%8R7NCEh1DSR3g*j10y<56#l__o&I`v0we>4X_{HO*L$&Ye9Oas^Pn5TL(-P{23t^ruU>{K zdar9-3l+v3bSH2qga5$el>hUjz?NwVQ=3uL28g-4@oFoeZ*rmdOPVKd6-B05JB9T& z06j$e8`}qgKK@cJx6yN^O&6D*uFIisY0bw*mU}`hXI=(}xuVs)hk+14D@>+)^00UM zTpuGj(Myh#56B*?SSv>F)(-xtaIe`|#^{hku{$V77bf)9P$cRWG;(Cssx&-5!H@ep zH$Q`FF?rlH4d)s*HscU}SCLcEXqw?f;<453I>PgO!d`w(LCZ5Nd2?DJt;GmZogOhR zAK~AYujB4V7oWZM%hkY0JC)2j@`t6xzWG$fp;Y!<(~G*FLBnH!O7=t^vg zFa@G^9tas09ln|6rwgcB$Bz6kw#H>{yv~v`Y_^+vdeo_*_7c2jTFK<&L9sudA6$|v zm%DOq#UspbU=R@XjI752rG&=Ah9#m@XCaXJsw$>c>ANNQENFWxf~hT%68-+1p4ZqS zrYMN$(|6_EfY2-C%3|nF+WAYYw!Bm)g?!QY)ZxQ0@4BXr`KD?o7LVCd`kq1dgp=c; zpG6T{6|aq7Wh^oUz%FxeHQ}|@bM%|KVAId0NxUA~F-%X(>FQ-B)igdJnl=%JFE~b~ zDlz%VmElHTSlbGDYN%)Su=Ds*n`_hWNOicvPuzY~B;Qr7FHwZZ?gv$u#U3CL<~Q*Z zY^hf2`;qjPN)(<=WTd-phsZp6A0F|rghuW}01>=nmR)|L!*0E5iWE^h-#+V}D=1UT zthAKFw~*GaH?xq2;k1mG4i_X3az*NkYy(#bhFZGl9HDRN@AAFIGbl{fY{wa9&t4@P zq!PwYN53PJS_JAtW@miU`ZpD1k}X8Efw>1-DkbqgLug}jsEx|dXHfGS<^AtB7QQ1A zsutJZWgE_&CAGhDhD^lxs?Q7fKa!#bLqN^`@P$C?EYyOXIiJ9lMN;Z(Lhj5 zJeEtCCdp_MG$ut6@^QI`GqNp>mxM}{sxg~Cv?N`Yfq1AU_TJ&;=IbkFRYEhA1ko+^ z{brQih}cXWzvAP5*CsUFkNz>q8JBhu!U9CGEH%U(a_JEqHeQV32h3HcjmZ2+HFo4u z#>7efMd=7wjSwM7E~Q6$C&^^=Vi&q;QZ$tocR=}tOi6&KJ#*@?PAYBRfLafaQ%y{m z@rAm(sm+JME@CCLL#nPLfu2*osP(Rl!vp!>zleIq0qu7Hy>S9ab63lG9{&Zh^%W6J ziu9KFk>P?02BIzP1|7+a9{lNf`y#8?zhJ4t*HB5jS@EeQxXac*&G*b7dv(SZ zJqyAXBBNhK8F~%usEEG5(zy;u`%dZ`G-V!NVl)FB&Yv#m?<3_^e)g>KSKiuWYbtch zyB05dtfmuYnEi3un{bzRv|Qp$_)bPEw{22Hl|f!{+MOKO_MSl|6A5LOt>DKv>4-Hx z`;69OVN2KESY}Yv6t7*D=cuCqmyao8KU&#*mUD-56;-*lX&UMp7WlqwbTix;yRCA8 zAIxVt|6z!82>L+Q{bh}J zvI?triK2)zle6GzN(nyqinT%I&FlA-P?5PHZ!z>;DqOU|GXeuC=~GZTq5r^~4V!P& z$yBnzP3jA^ zN^u7g<^1~n636q_OQE;sr}j->aE-TN8?M5TR~*?8H{%3!Fj3rIQ9xuGn+#I1OnWID zHHcroAN^~DeelRX`1K*5H2Ah)iy0fZ7UOxg@Vg+E@B9Kv5H{qMUL{F^CP~U-K*k_> z#_K7wA>JW5ALC_d*u>Hw$bM7fC#am^S^PY{%;8cK#GC|_;-Mb;HW~vNQXx%sF(9OT z-aXo_o4p`N;UU|TxO%ND*Az?tVZUE90?lMy=rl~=>rr7f#E~6R$cD?q=I>I?rhN!e zCxDw2;<3i1Dv8BTs*lr=;2h1{;a|-RofR+Cr;NDiQ8vb#O}7zh}c?I`%E z;`L-BT}E5_SWt^0*=f_k0V0~cz+A>LUVmA2GL{l7qia3AMkGj`|;d}_{-M4VVr(BZqm z+eB1t5b2BI=qkD}*zLReti6=9LA_rovgP-4mE;>)vYUqVr=0gRMIk?bEr*sz{&9MhxD#Q%J)wZ!&^yB4rAvTF3C%h zA-Yal006~NNmg3--4cAIJNCot7onR%DwR`$u8fv6#DzYNMky&AIcRtZ%nZTnKAXU} z3k8YqFFHND1Q-?EPo($2t52po3OUJ`lsf}sFKR0 z6*Q1B#F1KWrT=}XqXO^&um3~fKgaYxKl=YbiP}XF3IHGjFaflH|0AHeTtIC9yybYr zFq`k^SKG^M2vlEgKAi!fT6O@K5YR-Y>`@+v8?c?xN`*PnKiKqFs8f3{n%DC_lQ%&Z zQal5cN2&Dm`(Ot8N1*vPf2qI_cJW&3yVfZXEJ6=a{prQddMq{aT!I96(0xX|zpK_`CoTZY|v&u57knhjz<@)cpCsy=#yeawj z_V!v9&A%02nwMW*`D6OlTbzmV0@dUf3$1Zmb>`%u1E1eZ8^vPzT5I=`_u$8rkR^tEx$`QuG2pFhUw1( z=>uO`H4-29S}rZlVfn;^J0(FPFhMFQA}u@Qrck_U*5Pd3dmJp$DasT2AtA1_?T6xmwFjQ%B%b>lmhdl_VV%AM zXLSBq&AE>sZh@-77AsIO>qPAhmZ4`KZp~p`mbH!PHwQQh-@N;EzUn(aW3ZQ||K%qI ziObC!u9);rUMMBUu+MS(N=|Cps@^|u6{1-oD!Mf_4PMJ7BE8)o*LUVkIzWRva$4pya2Hr$a5ds#I2nj6g< ro@{AY*S1Sf;R#nx(Ur44PZ$_h>{Fc^a;mKfXbFR-tDnm{r-UW|JBKul literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_tank_output_slot.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_tank_output_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..4d1311dce98bad572f1497cc4e04782d653ec7fb GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`ex5FlAr_~T6BY;(q-+SI+w^VPd$WuDE>qp4QtylNmf+{an^LB{Ts5!C)@9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_upgrade_slot.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/empty_upgrade_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..e3301dfa9a7a3e51c664c704eac8c8270e5a8c1a GIT binary patch literal 1260 zcmVdQ@0+Qek%> zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3yulH({0hX3mndjv}$1joUARP7D+`1^uM+MUj1 zGVz#-g=JaDdJs6&{`@)QG^?>=M-@oh0%JLJJqnqdD(2bD=on;r7BPWNR*EOZ}T=u8eS--t5ogU)x z+8dHl75>D~8K&=!_K zc*xPxvp&z=%+Le1+sNN;$iCTjK2Evoy~f_#@pjnmmLIHRVq^l8;43Ti898U88L+%p%pda+ zb117*PpTT!G-}cuT<}3d2o}Z~mCczqwP0q^lI7^4j~YX?7-Nb#Npe`iG=*f8VoE7z z44UCOVu@4040nmIOti0&1)SPUS%i1bt)C&UbcS zE)D}47KIO;ujgQIX5H%Sr-;SH>)4~8Ncz={cOM@LZ)*dTAwZgbqYxwaxi7t?D7 zR!YIFn3g^5uGRRMZ~7EeOGmGxT$=bsDbMRT^5@!$RHm2LOnC3D}{PSL{|#+ z%#^Ma>X|8BEZ93!x>BfTrgWuH&yubb>YeGa9_jVf_J^alm)oD4FMYB-KQo{|ckv|F zzxG-4$BsI_*zo_J{s#@!?5=YWj^+RW00v@9M??U000000^%4DW00009a7bBm000ie z000ie0hKEb8vpS23|^o(DN~%8C Date: Sun, 7 Jun 2026 13:09:22 +0800 Subject: [PATCH 02/10] port mob catcher upgrade --- .../capability/Capabilities.java | 4 + .../backpack/BackpackInventoryHelper.kt | 11 +- .../capability/BackpackWrapper.kt | 101 +++- .../upgrade/AdvancedDepositUpgradeWrapper.kt | 7 +- .../upgrade/AdvancedFeedingUpgradeWrapper.kt | 11 +- .../upgrade/AdvancedFilterUpgradeWrapper.kt | 5 +- .../upgrade/AdvancedPickupUpgradeWrapper.kt | 7 +- .../upgrade/AdvancedRestockUpgradeWrapper.kt | 7 +- .../upgrade/AdvancedUpgradeWrapper.kt | 3 +- .../capability/upgrade/BasicUpgradeWrapper.kt | 3 +- .../upgrade/BatteryUpgradeWrapper.kt | 12 +- .../upgrade/CompactingUpgradeWrapper.kt | 9 +- .../upgrade/DepositUpgradeWrapper.kt | 7 +- .../upgrade/FeedingUpgradeWrapper.kt | 7 +- .../upgrade/FilterUpgradeWrapper.kt | 7 +- .../capability/upgrade/IAdvancedFilterable.kt | 4 +- .../capability/upgrade/IBasicFilterable.kt | 5 +- .../upgrade/JukeboxUpgradeWrapper.kt | 3 +- .../upgrade/MagnetUpgradeWrapper.kt | 15 +- .../upgrade/PickupUpgradeWrapper.kt | 7 +- .../capability/upgrade/PumpUpgradeWrapper.kt | 9 +- .../upgrade/RefillUpgradeWrapper.kt | 11 +- .../upgrade/RestockUpgradeWrapper.kt | 7 +- .../capability/upgrade/TankUpgradeWrapper.kt | 15 +- .../upgrade/ToolSwapperUpgradeWrapper.kt | 4 +- .../capability/upgrade/VoidUpgradeWrapper.kt | 25 +- .../upgrade/mobcatcher/CapturedMob.kt | 30 + .../mobcatcher/CapturedMobFootprint.kt | 6 + .../upgrade/mobcatcher/MobCatcherHandler.kt | 288 ++++++++++ .../upgrade/mobcatcher/MobCatcherStorage.kt | 531 ++++++++++++++++++ .../mobcatcher/MobCatcherUpgradeWrapper.kt | 19 + .../client/gui/BackpackPanel.kt | 23 +- .../widgets/BackpackInventoryScrollWidget.kt | 1 + .../gui/widgets/BackpackMainSettingsWidget.kt | 5 +- .../MobCatcherInventoryControlWidget.kt | 330 +++++++++++ .../gui/widgets/UpgradeSlotGroupWidget.kt | 5 - .../client/gui/widgets/slot/BackpackSlot.kt | 14 +- .../gui/widgets/slot/NoBackgroundItemSlot.kt | 12 +- .../widgets/upgrade/AdvancedFilterWidget.kt | 2 +- .../gui/widgets/upgrade/BasicFilterWidget.kt | 2 +- .../widgets/upgrade/BatteryUpgradeWidget.kt | 32 +- .../widgets/upgrade/JukeboxUpgradeWidget.kt | 19 +- .../gui/widgets/upgrade/TankUpgradeWidget.kt | 38 +- .../common/gui/slot/ModularBackpackSlot.kt | 9 +- .../common/gui/slot/ModularUpgradeSlot.kt | 48 +- .../config/Config.kt | 304 +++++++++- .../handler/CapabilityHandler.kt | 10 + .../handler/EntityEventHandler.kt | 10 + .../handler/NetworkHandler.kt | 14 + .../inventory/BackpackItemStackHandler.kt | 13 +- .../inventory/UpgradeItemStackHandler.kt | 10 +- .../item/BackpackItem.kt | 3 +- .../retrosophisticatedbackpacks/item/Items.kt | 27 +- .../item/JukeboxUpgradeItem.kt | 2 +- .../item/MobCatcherUpgradeItem.kt | 18 + .../item/StackUpgradeItem.kt | 2 +- .../item/UpgradeItem.kt | 4 +- .../network/C2SMobCatcherReleasePacket.kt | 33 ++ .../network/S2CMobCatcherContentsPacket.kt | 32 ++ .../proxy/RSBProxy.kt | 14 + .../sync/BackpackSH.kt | 13 + .../tileentity/BackpackTileEntity.kt | 29 +- .../lang/en_us.lang | 23 + .../lang/zh_cn.lang | 23 + .../item/advanced_mob_catcher_upgrade.json | 6 + .../models/item/mob_catcher_upgrade.json | 6 + .../recipes/advanced_mob_catcher_upgrade.json | 34 ++ .../recipes/mob_catcher_upgrade.json | 26 + .../item/advanced_mob_catcher_upgrade.png | Bin 0 -> 319 bytes .../textures/item/mob_catcher_upgrade.png | Bin 0 -> 325 bytes 70 files changed, 2164 insertions(+), 212 deletions(-) create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/advanced_mob_catcher_upgrade.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/mob_catcher_upgrade.png diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java index 78c1643..1d78b26 100644 --- a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability; import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.*; +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityInject; import org.jetbrains.annotations.NotNull; @@ -98,6 +99,9 @@ public final class Capabilities { @CapabilityInject(AnvilUpgradeWrapper.class) public static final @NotNull Capability ANVIL_UPGRADE_CAPABILITY = null; + @CapabilityInject(MobCatcherUpgradeWrapper.class) + public static final @NotNull Capability MOB_CATCHER_UPGRADE_CAPABILITY = null; + // Abstract capabilities @CapabilityInject(UpgradeWrapper.class) public static final @NotNull Capability> UPGRADE_CAPABILITY = null; diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt index 5be8ba2..68984be 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.backpack import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import net.minecraft.entity.Entity import net.minecraft.inventory.IInventory @@ -40,7 +41,7 @@ object BackpackInventoryHelper { val isMemorizedSlot = wrapper.isSlotMemorized(i) val baseStack = wrapper.getStackInSlot(i) - val maxSize = baseStack.maxStackSize * wrapper.getTotalStackMultiplier() + val maxSize = wrapper.getStackLimit(baseStack) for (j in i + 1 until wrapper.backpackInventorySize()) { if (isMemorizedSlot != wrapper.isSlotMemorized(j) || wrapper.isSlotLocked(j)) @@ -167,6 +168,9 @@ object BackpackInventoryHelper { } fun attemptDepositOnTileEntity(wrapper: BackpackWrapper, destination: TileEntity, facing: EnumFacing): Boolean { + if (Config.isInteractionBlockDisallowed(destination.blockType)) { + return false + } val destination = getHandler(destination, facing) ?: return false return attemptDepositOnItemHandler(wrapper, destination) } @@ -204,6 +208,9 @@ object BackpackInventoryHelper { } fun attemptRestockFromTileEntity(wrapper: BackpackWrapper, source: TileEntity, facing: EnumFacing): Boolean { + if (Config.isInteractionBlockDisallowed(source.blockType)) { + return false + } val source = getHandler(source, facing) ?: return false return attemptRestockFromItemHandler(wrapper, source) } @@ -262,4 +269,4 @@ object BackpackInventoryHelper { return true } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt index 6e4822f..524ef6f 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt @@ -8,6 +8,9 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedCo import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedVoidUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CompactingUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.CapturedMob +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.BackpackItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.inventory.UpgradeItemStackHandler @@ -74,7 +77,6 @@ class BackpackWrapper( private const val ITEM_DISPLAY_ROTATIONS_TAG = "Rotations" private const val ITEM_DISPLAY_COLOR_TAG = "Color" private const val ITEM_DISPLAY_SIDE_TAG = "DisplaySide" - private const val UUID_TAG = "UUID" const val DEFAULT_MAIN_COLOR: Int = -0x339ec6 @@ -83,7 +85,7 @@ class BackpackWrapper( var isCached: Boolean = false var backpackItemStackHandler = BackpackItemStackHandler(backpackInventorySize(), this) - var upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize()) + var upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize(), this) var sortType: SortType = SortType.BY_NAME var mainColor = DEFAULT_MAIN_COLOR @@ -94,13 +96,16 @@ class BackpackWrapper( var shiftClickIntoOpenTab = false var keepTabOpen = true var keepSearchPhrase = false - var anotherPlayerCanOpen = false + var anotherPlayerCanOpen = Config.allowOpeningOtherPlayerBackpacks var itemDisplayColor: EnumDyeColor = EnumDyeColor.RED var itemDisplaySide: DisplaySide = DisplaySide.FRONT private val itemDisplaySlots = linkedSetOf() private val itemDisplayRotations = mutableMapOf() private val slotsToCompact = mutableSetOf() private val slotsToVoid = mutableSetOf() + val capturedMobs: MutableList = mutableListOf() + var capturedMobsColumns = 0 + private var updatingCapturedMobLayout = false enum class SettingsContext { PLAYER, @@ -133,6 +138,12 @@ class BackpackWrapper( return stackUpgradeItems.fold(base) { acc, item -> func(acc, item.multiplier()) } } + fun getTotalStackMultiplier(stack: ItemStack): Int = + if (Config.canStackWithStackUpgrade(stack)) getTotalStackMultiplier() else 1 + + fun getStackLimit(stack: ItemStack): Int = + stack.maxStackSize * getTotalStackMultiplier(stack) + fun canAddStackUpgrade(newMultiplier: Int): Boolean { // Ensures no overflow for vanilla itemstack, no guarantee for modded itemstack val currentMultiplier = getTotalStackMultiplier() * 64 @@ -153,7 +164,7 @@ class BackpackWrapper( val newStackMultiplier = getTotalStackMultiplier() / oldMultiplier * newMultiplier for (stack in backpackItemStackHandler.inventory) { - if (stack.isEmpty) + if (stack.isEmpty || !Config.canStackWithStackUpgrade(stack)) continue if (stack.count > stack.maxStackSize * newStackMultiplier) @@ -178,7 +189,7 @@ class BackpackWrapper( val byAddMultiplier = getTotalStackMultiplier(false) for (stack in backpackItemStackHandler.inventory) { - if (stack.isEmpty) + if (stack.isEmpty || !Config.canStackWithStackUpgrade(stack)) continue if (stack.count > stack.maxStackSize * byAddMultiplier) @@ -227,6 +238,23 @@ class BackpackWrapper( else filterUpgrades.any { it.canInsert(stack) } } + fun ensureCapturedMobLayoutCurrent() { + if (updatingCapturedMobLayout) + return + + updatingCapturedMobLayout = true + try { + MobCatcherStorage.ensureLayoutCurrent(this) + } finally { + updatingCapturedMobLayout = false + } + } + + fun isSlotBlockedByMobCatcher(slotIndex: Int): Boolean { + ensureCapturedMobLayoutCurrent() + return MobCatcherStorage.isSlotBlocked(this, slotIndex) + } + fun onBeforeInsert(stack: ItemStack): ItemStack = if (shouldVoid(stack, false, false)) ItemStack.EMPTY else stack @@ -447,9 +475,12 @@ class BackpackWrapper( private fun insertIntoSimulation(simulation: ExposedItemStackHandler, stack: ItemStack): ItemStack { var remaining = stack for (slot in 0 until simulation.slots) { + if (isSlotBlockedByMobCatcher(slot)) { + continue + } val existing = simulation.getStackInSlot(slot) if (existing.isEmpty) { - val moved = minOf(remaining.count, remaining.maxStackSize * getTotalStackMultiplier()) + val moved = minOf(remaining.count, getStackLimit(remaining)) simulation.setStackInSlot(slot, ItemHandlerHelper.copyStackWithSize(remaining, moved)) remaining = ItemHandlerHelper.copyStackWithSize(remaining, remaining.count - moved) if (remaining.isEmpty) { @@ -460,7 +491,7 @@ class BackpackWrapper( if (!ItemHandlerHelper.canItemStacksStack(existing, remaining)) { continue } - val moved = minOf(remaining.count, existing.maxStackSize * getTotalStackMultiplier() - existing.count) + val moved = minOf(remaining.count, getStackLimit(existing) - existing.count) if (moved > 0) { existing.grow(moved) remaining = ItemHandlerHelper.copyStackWithSize(remaining, remaining.count - moved) @@ -593,14 +624,18 @@ class BackpackWrapper( } fun toggleAnotherPlayerCanOpen() { + if (!Config.allowOpeningOtherPlayerBackpacks) { + anotherPlayerCanOpen = false + return + } anotherPlayerCanOpen = !anotherPlayerCanOpen } fun isItemDisplaySlotSelected(slotIndex: Int): Boolean = - slotIndex in itemDisplaySlots + !Config.itemDisplayDisabled && slotIndex in itemDisplaySlots fun selectItemDisplaySlot(slotIndex: Int) { - if (slotIndex !in 0 until backpackInventorySize() || slotIndex in itemDisplaySlots) { + if (Config.itemDisplayDisabled || slotIndex !in 0 until backpackInventorySize() || slotIndex in itemDisplaySlots) { return } if (itemDisplaySlots.size + 1 > 1) { @@ -615,22 +650,25 @@ class BackpackWrapper( } fun getFirstItemDisplaySlot(): Int = - itemDisplaySlots.firstOrNull() ?: -1 + if (Config.itemDisplayDisabled) -1 else itemDisplaySlots.firstOrNull() ?: -1 fun getItemDisplaySlots(): Set = - itemDisplaySlots + if (Config.itemDisplayDisabled) emptySet() else itemDisplaySlots fun getItemDisplayRotation(slotIndex: Int): Int = itemDisplayRotations[slotIndex] ?: 0 fun rotateItemDisplaySlot(slotIndex: Int, clockwise: Boolean) { - if (slotIndex !in itemDisplaySlots) { + if (Config.itemDisplayDisabled || slotIndex !in itemDisplaySlots) { return } itemDisplayRotations[slotIndex] = (getItemDisplayRotation(slotIndex) + if (clockwise) 45 else -45 + 360) % 360 } fun getDisplayItem(): DisplayItem? { + if (Config.itemDisplayDisabled) { + return null + } val slotIndex = getFirstItemDisplaySlot() if (slotIndex !in 0 until backpackInventorySize()) { return null @@ -645,7 +683,11 @@ class BackpackWrapper( // This is only meant to used for bogosorter as RSB already implemented a sorting mechanism fun getSortableSlotIndexes(): List = - (0.., facing: EnumFacing?): Boolean = capability == Capabilities.BACKPACK_CAPABILITY || capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || - capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && hasTankUpgrade() || + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && Config.itemFluidHandlerEnabled && hasTankUpgrade() || capability == CapabilityEnergy.ENERGY && hasBatteryUpgrade() @Suppress("UNCHECKED_CAST") @@ -714,7 +762,7 @@ class BackpackWrapper( capability == Capabilities.BACKPACK_CAPABILITY -> this as T capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY -> this as T capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && - hasTankUpgrade() -> BackpackFluidHandler(this) as T + Config.itemFluidHandlerEnabled && hasTankUpgrade() -> BackpackFluidHandler(this) as T capability == CapabilityEnergy.ENERGY && hasBatteryUpgrade() -> BackpackEnergyStorage(this) as T else -> null } @@ -766,6 +814,9 @@ class BackpackWrapper( itemDisplayNbt.setByte(ITEM_DISPLAY_COLOR_TAG, itemDisplayColor.ordinal.toByte()) itemDisplayNbt.setString(ITEM_DISPLAY_SIDE_TAG, itemDisplaySide.serializedName) nbt.setTag(ITEM_DISPLAY_SETTINGS_TAG, itemDisplayNbt) + ensureCapturedMobLayoutCurrent() + nbt.setTag(MobCatcherStorage.CAPTURED_MOBS_TAG, MobCatcherStorage.serialize(capturedMobs)) + nbt.setInteger(MobCatcherStorage.CAPTURED_MOBS_COLUMNS_TAG, capturedMobsColumns) nbt.setUniqueId(UUID_TAG, uuid) return nbt @@ -780,7 +831,7 @@ class BackpackWrapper( uuid = nbt.getUniqueId(UUID_TAG)!! backpackItemStackHandler = BackpackItemStackHandler(backpackInventorySize(), this) - upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize()) + upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize(), this) mainColor = nbt.getInteger(MAIN_COLOR_TAG) accentColor = nbt.getInteger(ACCENT_COLOR_TAG) @@ -824,7 +875,9 @@ class BackpackWrapper( mainSettingsNbt.getBoolean(MAIN_SETTINGS_KEEP_TAB_OPEN_TAG) else true keepSearchPhrase = mainSettingsNbt.getBoolean(MAIN_SETTINGS_KEEP_SEARCH_PHRASE_TAG) - anotherPlayerCanOpen = mainSettingsNbt.getBoolean(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG) + anotherPlayerCanOpen = Config.allowOpeningOtherPlayerBackpacks && + (!mainSettingsNbt.hasKey(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG) || + mainSettingsNbt.getBoolean(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG)) } itemDisplaySlots.clear() @@ -846,6 +899,14 @@ class BackpackWrapper( itemDisplaySide = DisplaySide.fromName(itemDisplayNbt.getString(ITEM_DISPLAY_SIDE_TAG)) } + capturedMobs.clear() + capturedMobs.addAll(MobCatcherStorage.deserialize(nbt.getTagList(MobCatcherStorage.CAPTURED_MOBS_TAG, 10))) + capturedMobsColumns = if (nbt.hasKey(MobCatcherStorage.CAPTURED_MOBS_COLUMNS_TAG)) { + nbt.getInteger(MobCatcherStorage.CAPTURED_MOBS_COLUMNS_TAG) + } else { + MobCatcherStorage.getColumns(this) + } + sortType = SortType.entries[nbt.getByte(SORT_TYPE_TAG).toInt()] } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt index 7424b65..45b696c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.DepositUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedDepositUpgradeWrapper : AdvancedUpgradeWrapper(), IDepositUpgrade { +class AdvancedDepositUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedDepositUpgrade.filterSlots, Config.advancedDepositUpgrade.slotsInRow), + IDepositUpgrade { override val settingsLangKey: String = "gui.advanced_deposit_settings".asTranslationKey() override fun canDeposit(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class AdvancedDepositUpgradeWrapper : AdvancedUpgradeWrapper capability == Capabilities.ADVANCED_DEPOSIT_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt index 800a51e..2353a53 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt @@ -1,22 +1,21 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade -import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackDataFixer import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.FeedingUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.BackpackItemStackHelper import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey -import net.minecraft.item.ItemFood import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -import net.minecraftforge.fml.common.Loader import net.minecraftforge.items.IItemHandler -import squeek.applecore.api.AppleCoreAPI -class AdvancedFeedingUpgradeWrapper : AdvancedUpgradeWrapper(), IFeedingUpgrade { +class AdvancedFeedingUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedFeedingUpgrade.filterSlots, Config.advancedFeedingUpgrade.slotsInRow), + IFeedingUpgrade { companion object { private const val HUNGER_FEEDING_STRATEGY_TAG = "HungerFeedingStrategy" private const val HURT_FEEDING_STRATEGY_TAG = "HurtFeedingStrategy" @@ -24,7 +23,7 @@ class AdvancedFeedingUpgradeWrapper : AdvancedUpgradeWrapper override val settingsLangKey: String = "gui.advanced_feeding_settings".asTranslationKey() - override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(16) { + override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(Config.advancedFeedingUpgrade.filterSlots) { override fun isItemValid(slot: Int, stack: ItemStack): Boolean = IFeedingUpgrade.isValidFood(stack) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt index 3f9fe59..7f61aca 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.FilterUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -8,7 +9,9 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedFilterUpgradeWrapper : AdvancedUpgradeWrapper(), IFilterUpgrade { +class AdvancedFilterUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedFilterUpgrade.filterSlots, Config.advancedFilterUpgrade.slotsInRow), + IFilterUpgrade { override val settingsLangKey: String = "gui.advanced_filter_settings".asTranslationKey() override var filterWay: IFilterUpgrade.FilterWayType = IFilterUpgrade.FilterWayType.IN_OUT diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt index 20ebc0e..04db38d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.PickupUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedPickupUpgradeWrapper : AdvancedUpgradeWrapper(), IPickupUpgrade { +class AdvancedPickupUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedPickupUpgrade.filterSlots, Config.advancedPickupUpgrade.slotsInRow), + IPickupUpgrade { override val settingsLangKey: String = "gui.advanced_pickup_settings".asTranslationKey() override fun canPickup(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class AdvancedPickupUpgradeWrapper : AdvancedUpgradeWrapper() capability == Capabilities.ADVANCED_PICKUP_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt index a0fa35a..d2cfbd1 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.RestockUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedRestockUpgradeWrapper : AdvancedUpgradeWrapper(), IRestockUpgrade { +class AdvancedRestockUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedRestockUpgrade.filterSlots, Config.advancedRestockUpgrade.slotsInRow), + IRestockUpgrade { override val settingsLangKey: String = "gui.advanced_restock_settings".asTranslationKey() override fun canRestock(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class AdvancedRestockUpgradeWrapper : AdvancedUpgradeWrapper capability == Capabilities.ADVANCED_RESTOCK_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt index 64ff348..67fdaa0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt @@ -10,7 +10,8 @@ import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.Constants -abstract class AdvancedUpgradeWrapper(filterSlots: Int = 16) : UpgradeWrapper(), IToggleable, IAdvancedFilterable where T : UpgradeItem { +abstract class AdvancedUpgradeWrapper(filterSlots: Int = 16, override val slotsInRow: Int = 4) : + UpgradeWrapper(), IToggleable, IAdvancedFilterable where T : UpgradeItem { override var enabled = true override var filterType = IBasicFilterable.FilterType.WHITELIST override val filterItems: ExposedItemStackHandler = ExposedItemStackHandler(filterSlots) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt index 1bbd550..d70882c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt @@ -7,7 +7,8 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -abstract class BasicUpgradeWrapper(filterSlots: Int = 9) : UpgradeWrapper(), IToggleable, IBasicFilterable where T : UpgradeItem { +abstract class BasicUpgradeWrapper(filterSlots: Int = 9, override val slotsInRow: Int = 3) : + UpgradeWrapper(), IToggleable, IBasicFilterable where T : UpgradeItem { override var enabled = true override var filterType = IBasicFilterable.FilterType.WHITELIST override val filterItems = ExposedItemStackHandler(filterSlots) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt index 924f2cd..b273dc2 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.BatteryUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -19,8 +20,6 @@ class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgr private const val INVENTORY_TAG = "Inventory" private const val INPUT_SLOT = 0 private const val OUTPUT_SLOT = 1 - private const val ENERGY_PER_ROW = 10000 - private const val MAX_INPUT_OUTPUT_PER_ROW = 20 } override val settingsLangKey = "gui.battery_settings".asTranslationKey() @@ -41,10 +40,10 @@ class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgr } override fun getMaxEnergyStored(wrapper: BackpackWrapper): Int = - getMaxEnergyStored(wrapper, maxOf(1, wrapper.getTotalStackMultiplier())) + getMaxEnergyStored(wrapper, wrapper.getTotalStackMultiplier()) override fun getMaxEnergyStored(wrapper: BackpackWrapper, stackMultiplier: Int): Int = - getSlotRows(wrapper) * ENERGY_PER_ROW * maxOf(1, stackMultiplier) + (getSlotRows(wrapper) * Config.batteryUpgrade.energyPerSlotRow * getAdjustedStackMultiplier(stackMultiplier)).toInt() override fun receiveEnergy(wrapper: BackpackWrapper, maxReceive: Int, simulate: Boolean): Int { val accepted = minOf(maxReceive, getMaxInOut(wrapper), getMaxEnergyStored(wrapper) - energyStored) @@ -109,11 +108,14 @@ class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgr } private fun getMaxInOut(wrapper: BackpackWrapper): Int = - maxOf(1, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * maxOf(1, wrapper.getTotalStackMultiplier())) + maxOf(1, (getSlotRows(wrapper) * Config.batteryUpgrade.maxInputOutput * getAdjustedStackMultiplier(wrapper.getTotalStackMultiplier())).toInt()) private fun getSlotRows(wrapper: BackpackWrapper): Int = maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) + private fun getAdjustedStackMultiplier(stackMultiplier: Int): Double = + 1.0 + Config.batteryUpgrade.stackMultiplierRatio * (stackMultiplier - 1) + override fun serializeNBT(): NBTTagCompound { val nbt = super.serializeNBT() nbt.setInteger(ENERGY_TAG, energyStored) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt index b5eb365..562e338 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.CompactingUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -11,7 +12,9 @@ import net.minecraft.util.EnumFacing import net.minecraft.world.World import net.minecraftforge.common.capabilities.Capability -open class CompactingUpgradeWrapper : BasicUpgradeWrapper(), ICompactingUpgrade { +open class CompactingUpgradeWrapper : + BasicUpgradeWrapper(Config.compactingUpgrade.filterSlots, Config.compactingUpgrade.slotsInRow), + ICompactingUpgrade { companion object { private const val COMPACT_NON_UNCRAFTABLE_TAG = "CompactNonUncraftable" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" @@ -54,7 +57,9 @@ open class CompactingUpgradeWrapper : BasicUpgradeWrapper super.hasCapability(capability, facing) } -class AdvancedCompactingUpgradeWrapper : AdvancedUpgradeWrapper(), ICompactingUpgrade { +class AdvancedCompactingUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedCompactingUpgrade.filterSlots, Config.advancedCompactingUpgrade.slotsInRow), + ICompactingUpgrade { companion object { private const val COMPACT_NON_UNCRAFTABLE_TAG = "CompactNonUncraftable" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt index c793039..042b349 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.DepositUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class DepositUpgradeWrapper : BasicUpgradeWrapper(), IDepositUpgrade { +class DepositUpgradeWrapper : + BasicUpgradeWrapper(Config.depositUpgrade.filterSlots, Config.depositUpgrade.slotsInRow), + IDepositUpgrade { override val settingsLangKey: String = "gui.deposit_settings".asTranslationKey() override fun canDeposit(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class DepositUpgradeWrapper : BasicUpgradeWrapper(), IDeposi capability == Capabilities.DEPOSIT_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt index 262ff4c..1b921cc 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackDataFixer import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.FeedingUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.BackpackItemStackHelper @@ -12,10 +13,12 @@ import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.items.IItemHandler -class FeedingUpgradeWrapper : BasicUpgradeWrapper(), IFeedingUpgrade { +class FeedingUpgradeWrapper : + BasicUpgradeWrapper(Config.feedingUpgrade.filterSlots, Config.feedingUpgrade.slotsInRow), + IFeedingUpgrade { override val settingsLangKey: String = "gui.feeding_settings".asTranslationKey() - override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(9) { + override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(Config.feedingUpgrade.filterSlots) { override fun isItemValid(slot: Int, stack: ItemStack): Boolean = IFeedingUpgrade.isValidFood(stack) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt index a921ef4..fa653a8 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.FilterUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -8,7 +9,9 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class FilterUpgradeWrapper : BasicUpgradeWrapper(), IFilterUpgrade { +class FilterUpgradeWrapper : + BasicUpgradeWrapper(Config.filterUpgrade.filterSlots, Config.filterUpgrade.slotsInRow), + IFilterUpgrade { override val settingsLangKey: String = "gui.filter_settings".asTranslationKey() override var filterWay: IFilterUpgrade.FilterWayType = IFilterUpgrade.FilterWayType.IN_OUT @@ -41,4 +44,4 @@ class FilterUpgradeWrapper : BasicUpgradeWrapper(), IFilterUp super.deserializeNBT(nbt) filterWay = IFilterUpgrade.FilterWayType.entries[nbt.getByte(IFilterUpgrade.FILTER_WAY_TAG).toInt()] } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt index 56a2206..fbc30da 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt @@ -106,6 +106,8 @@ interface IAdvancedFilterable : IBasicFilterable { object Impl : IAdvancedFilterable { override val filterItems: ExposedItemStackHandler get() = ExposedItemStackHandler(0) + override val slotsInRow: Int + get() = 1 override var filterType: IBasicFilterable.FilterType get() = IBasicFilterable.Impl.filterType set(_) {} @@ -126,4 +128,4 @@ interface IAdvancedFilterable : IBasicFilterable { get() = false set(_) {} } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt index 0bb0003..7fd472d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt @@ -14,6 +14,7 @@ interface IBasicFilterable : ISidelessCapabilityProvider { } val filterItems: ExposedItemStackHandler + val slotsInRow: Int var filterType: FilterType fun checkFilter(stack: ItemStack): Boolean = when (filterType) { @@ -32,6 +33,8 @@ interface IBasicFilterable : ISidelessCapabilityProvider { object Impl : IBasicFilterable { override val filterItems: ExposedItemStackHandler get() = ExposedItemStackHandler(0) + override val slotsInRow: Int + get() = 1 override var filterType: FilterType get() = FilterType.WHITELIST set(_) {} @@ -39,4 +42,4 @@ interface IBasicFilterable : ISidelessCapabilityProvider { override fun checkFilter(itemStack: ItemStack): Boolean = false } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt index 713e0e3..20c239d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.JukeboxUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -240,7 +241,7 @@ open class JukeboxUpgradeWrapper(private val slots: Int = 1) : UpgradeWrapper.hasCapability(capability, facing) } -class AdvancedJukeboxUpgradeWrapper : JukeboxUpgradeWrapper(12) { +class AdvancedJukeboxUpgradeWrapper : JukeboxUpgradeWrapper(Config.advancedJukeboxUpgrade.numberOfSlots) { override val settingsLangKey = "gui.advanced_jukebox_settings".asTranslationKey() override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt index 1cee70d..4dd3b34 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt @@ -2,14 +2,19 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.MagnetUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -open class MagnetUpgradeWrapper(filterSlots: Int = 9, override val range: Double = 3.0) : - BasicUpgradeWrapper(filterSlots), IMagnetUpgrade { +open class MagnetUpgradeWrapper( + filterSlots: Int = Config.magnetUpgrade.filterSlots, + slotsInRow: Int = Config.magnetUpgrade.slotsInRow, + override val range: Double = Config.magnetUpgrade.magnetRange.toDouble() +) : + BasicUpgradeWrapper(filterSlots, slotsInRow), IMagnetUpgrade { override val settingsLangKey = "gui.magnet_settings".asTranslationKey() init { @@ -25,9 +30,11 @@ open class MagnetUpgradeWrapper(filterSlots: Int = 9, override val range: Double super.hasCapability(capability, facing) } -class AdvancedMagnetUpgradeWrapper : AdvancedUpgradeWrapper(), IMagnetUpgrade { +class AdvancedMagnetUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedMagnetUpgrade.filterSlots, Config.advancedMagnetUpgrade.slotsInRow), + IMagnetUpgrade { override val settingsLangKey = "gui.advanced_magnet_settings".asTranslationKey() - override val range = 5.0 + override val range = Config.advancedMagnetUpgrade.magnetRange.toDouble() init { filterType = IBasicFilterable.FilterType.BLACKLIST diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt index e1950e6..63be82a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.PickupUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class PickupUpgradeWrapper : BasicUpgradeWrapper(), IPickupUpgrade { +class PickupUpgradeWrapper : + BasicUpgradeWrapper(Config.pickupUpgrade.filterSlots, Config.pickupUpgrade.slotsInRow), + IPickupUpgrade { override val settingsLangKey: String = "gui.pickup_settings".asTranslationKey() override fun canPickup(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class PickupUpgradeWrapper : BasicUpgradeWrapper(), IPickupUp capability == Capabilities.PICKUP_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt index afaa507..dbd0661 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackFluidHandler import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.PumpUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.entity.player.EntityPlayer @@ -42,7 +43,6 @@ open class PumpUpgradeWrapper( private const val FLUID_HANDLER_COOLDOWN = 20L private const val PLAYER_SEARCH_RANGE = 3.0 private const val WORLD_RANGE = 4 - private const val MAX_INPUT_OUTPUT_PER_ROW = 20 } override val settingsLangKey = "gui.pump_settings".asTranslationKey() @@ -212,11 +212,14 @@ open class PumpUpgradeWrapper( } private fun getMaxInOut(wrapper: BackpackWrapper): Int = - maxOf(Fluid.BUCKET_VOLUME, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * maxOf(1, wrapper.getTotalStackMultiplier())) + maxOf(Fluid.BUCKET_VOLUME, (getSlotRows(wrapper) * Config.pumpUpgrade.maxInputOutput * getAdjustedStackMultiplier(wrapper)).toInt()) private fun getSlotRows(wrapper: BackpackWrapper): Int = maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) + private fun getAdjustedStackMultiplier(wrapper: BackpackWrapper): Double = + 1.0 + Config.pumpUpgrade.stackMultiplierRatio * (wrapper.getTotalStackMultiplier() - 1) + private fun distanceSq(first: BlockPos, second: BlockPos): Int { val dx = first.x - second.x val dy = first.y - second.y @@ -263,7 +266,7 @@ open class PumpUpgradeWrapper( } class AdvancedPumpUpgradeWrapper : PumpUpgradeWrapper( - filterSlots = 4, + filterSlots = Config.pumpUpgrade.filterSlots, interactWithHandDefault = true, interactWithWorldDefault = false, interactWithFluidHandlersDefault = true diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt index 20b25f3..0922cb6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.RefillUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.entity.player.EntityPlayer @@ -14,8 +15,11 @@ import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.Constants import net.minecraftforge.items.ItemHandlerHelper -open class RefillUpgradeWrapper(filterSlots: Int = 6) : - BasicUpgradeWrapper(filterSlots), IRefillUpgrade { +open class RefillUpgradeWrapper( + filterSlots: Int = Config.refillUpgrade.filterSlots, + slotsInRow: Int = Config.refillUpgrade.slotsInRow +) : + BasicUpgradeWrapper(filterSlots, slotsInRow), IRefillUpgrade { override val settingsLangKey = "gui.refill_settings".asTranslationKey() init { @@ -156,7 +160,8 @@ open class RefillUpgradeWrapper(filterSlots: Int = 6) : } } -class AdvancedRefillUpgradeWrapper : RefillUpgradeWrapper(12) { +class AdvancedRefillUpgradeWrapper : + RefillUpgradeWrapper(Config.advancedRefillUpgrade.filterSlots, Config.advancedRefillUpgrade.slotsInRow) { companion object { private const val TARGET_SLOTS_TAG = "TargetSlots" private const val SLOT_TAG = "Slot" diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt index 44884c2..029c052 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.RestockUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class RestockUpgradeWrapper : BasicUpgradeWrapper(), IRestockUpgrade { +class RestockUpgradeWrapper : + BasicUpgradeWrapper(Config.restockUpgrade.filterSlots, Config.restockUpgrade.slotsInRow), + IRestockUpgrade { override val settingsLangKey: String = "gui.restock_settings".asTranslationKey() override fun canRestock(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class RestockUpgradeWrapper : BasicUpgradeWrapper(), IRestoc capability == Capabilities.RESTOCK_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt index 4600a6d..a867129 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.TankUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -27,12 +28,10 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { private const val INPUT_RESULT_SLOT = 2 private const val OUTPUT_RESULT_SLOT = 3 private const val BUCKET = 1000 - private const val CAPACITY_PER_ROW = 4000 - private const val MAX_INPUT_OUTPUT_PER_ROW = 20 } override val settingsLangKey = "gui.tank_settings".asTranslationKey() - override val tankCapacity = CAPACITY_PER_ROW * 3 + override val tankCapacity = Config.tankUpgrade.capacityPerSlotRow * 3 private var fluid: FluidStack? = null private val inventory = object : ExposedItemStackHandler(4) { override fun isItemValid(slot: Int, stack: ItemStack): Boolean = @@ -47,16 +46,16 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { fluid?.copy() override fun getTankCapacity(wrapper: BackpackWrapper): Int = - maxOf(BUCKET, getSlotRows(wrapper) * CAPACITY_PER_ROW * getStackMultiplier(wrapper)) + maxOf(BUCKET, (getSlotRows(wrapper) * Config.tankUpgrade.capacityPerSlotRow * getAdjustedStackMultiplier(wrapper)).toInt()) private fun getMaxInOut(wrapper: BackpackWrapper): Int = - maxOf(BUCKET, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * getStackMultiplier(wrapper)) + maxOf(BUCKET, (getSlotRows(wrapper) * Config.tankUpgrade.maxInputOutput * getAdjustedStackMultiplier(wrapper)).toInt()) private fun getSlotRows(wrapper: BackpackWrapper): Int = maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) - private fun getStackMultiplier(wrapper: BackpackWrapper): Int = - maxOf(1, wrapper.getTotalStackMultiplier()) + private fun getAdjustedStackMultiplier(wrapper: BackpackWrapper): Double = + 1.0 + Config.tankUpgrade.stackMultiplierRatio * (wrapper.getTotalStackMultiplier() - 1) override fun fill(wrapper: BackpackWrapper, resource: FluidStack, doFill: Boolean, ignoreInOutLimit: Boolean): Int { val current = fluid @@ -98,7 +97,7 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { } override fun tick(wrapper: BackpackWrapper, world: World) { - if (world.totalWorldTime % 20L != 0L) { + if (world.totalWorldTime % Config.tankUpgrade.autoFillDrainContainerCooldown.coerceAtLeast(1).toLong() != 0L) { return } tryDrainInput(wrapper) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt index 70c47cd..8ff380e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import com.cleanroommc.retrosophisticatedbackpacks.item.ToolSwapperUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -28,7 +29,8 @@ import java.util.LinkedList open class ToolSwapperUpgradeWrapper( private val hasSettingsTab: Boolean = false, private val swapToolOnKeyPress: Boolean = false, -) : BasicUpgradeWrapper(8), IToolSwapperUpgrade { +) : BasicUpgradeWrapper(Config.toolSwapperUpgrade.filterSlots, Config.toolSwapperUpgrade.slotsInRow), + IToolSwapperUpgrade { companion object { private const val SHOULD_SWAP_WEAPON_TAG = "ShouldSwapWeapon" private const val TOOL_SWAP_MODE_TAG = "ToolSwapMode" diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt index 7b1ce1d..90a97db 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.VoidUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -9,14 +10,19 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class VoidUpgradeWrapper : BasicUpgradeWrapper(), IVoidUpgrade { +class VoidUpgradeWrapper : + BasicUpgradeWrapper(Config.voidUpgrade.filterSlots, Config.voidUpgrade.slotsInRow), + IVoidUpgrade { companion object { private const val VOID_TYPE_TAG = "VoidType" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" } override val settingsLangKey = "gui.void_settings".asTranslationKey() - var voidType = VoidType.ALWAYS + var voidType = normalizeVoidType(VoidType.ALWAYS) + set(value) { + field = normalizeVoidType(value) + } var shouldWorkInGui = false init { @@ -50,20 +56,28 @@ class VoidUpgradeWrapper : BasicUpgradeWrapper(), IVoidUpgrade shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } + private fun normalizeVoidType(type: VoidType): VoidType = + if (!Config.voidUpgrade.voidAlwaysEnabled && type == VoidType.ALWAYS) VoidType.SLOT_OVERFLOW else type + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.VOID_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) } -class AdvancedVoidUpgradeWrapper : AdvancedUpgradeWrapper(), IVoidUpgrade { +class AdvancedVoidUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedVoidUpgrade.filterSlots, Config.advancedVoidUpgrade.slotsInRow), + IVoidUpgrade { companion object { private const val VOID_TYPE_TAG = "VoidType" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" } override val settingsLangKey = "gui.advanced_void_settings".asTranslationKey() - var voidType = VoidType.ALWAYS + var voidType = normalizeVoidType(VoidType.ALWAYS) + set(value) { + field = normalizeVoidType(value) + } var shouldWorkInGui = false init { @@ -97,6 +111,9 @@ class AdvancedVoidUpgradeWrapper : AdvancedUpgradeWrapper(), IV shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } + private fun normalizeVoidType(type: VoidType): VoidType = + if (!Config.advancedVoidUpgrade.voidAlwaysEnabled && type == VoidType.ALWAYS) VoidType.SLOT_OVERFLOW else type + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.ADVANCED_VOID_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt new file mode 100644 index 0000000..3c6e966 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt @@ -0,0 +1,30 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.ResourceLocation +import java.util.UUID + +data class CapturedMob( + val id: UUID, + val entityType: ResourceLocation, + val entityNbt: NBTTagCompound, + val slot: Int, + val width: Int, + val height: Int, + val slotCost: Int, + val hostile: Boolean, + val displayName: String, + val currentHealth: Int, + val maxHealth: Int +) { + fun occupiesSlot(inventorySlot: Int, columns: Int): Boolean { + if (columns <= 0 || inventorySlot < 0) { + return false + } + val originX = slot % columns + val originY = slot / columns + val slotX = inventorySlot % columns + val slotY = inventorySlot / columns + return slotX >= originX && slotX < originX + width && slotY >= originY && slotY < originY + height + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt new file mode 100644 index 0000000..a47706c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt @@ -0,0 +1,6 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +data class CapturedMobFootprint(val width: Int, val height: Int) { + val area: Int + get() = width * height +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt new file mode 100644 index 0000000..44aa863 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt @@ -0,0 +1,288 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer +import com.cleanroommc.retrosophisticatedbackpacks.config.Config +import com.cleanroommc.retrosophisticatedbackpacks.handler.CapabilityHandler +import com.cleanroommc.retrosophisticatedbackpacks.handler.NetworkHandler +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem +import com.cleanroommc.retrosophisticatedbackpacks.network.S2CMobCatcherContentsPacket +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.block.Block +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityFlying +import net.minecraft.entity.EntityList +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.IEntityOwnable +import net.minecraft.entity.SharedMonsterAttributes +import net.minecraft.entity.boss.EntityDragon +import net.minecraft.entity.boss.EntityWither +import net.minecraft.entity.monster.IMob +import net.minecraft.entity.passive.EntityWaterMob +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.player.EntityPlayerMP +import net.minecraft.init.SoundEvents +import net.minecraft.inventory.IInventory +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumActionResult +import net.minecraft.util.EnumFacing +import net.minecraft.util.ResourceLocation +import net.minecraft.util.SoundCategory +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.RayTraceResult +import net.minecraft.util.math.Vec3d +import net.minecraft.util.text.TextComponentTranslation +import net.minecraft.world.World +import java.util.UUID +import kotlin.math.ceil + +object MobCatcherHandler { + private const val RELEASE_REACH = 5.0 + + fun tryCapture(player: EntityPlayer, entity: EntityLivingBase): EnumActionResult { + val stack = player.heldItemMainhand + if (stack.item !is BackpackItem) { + return EnumActionResult.PASS + } + val backpackWrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return EnumActionResult.PASS + val upgradeWrapper = getBestUpgrade(backpackWrapper) ?: return EnumActionResult.PASS + if (player.world.isRemote) { + return EnumActionResult.SUCCESS + } + + val result = capture(player as EntityPlayerMP, backpackWrapper, entity, upgradeWrapper.isAdvanced) + player.sendStatusMessage(TextComponentTranslation(result.messageKey.asTranslationKey(), *result.args), true) + return if (result.success) EnumActionResult.SUCCESS else EnumActionResult.FAIL + } + + private fun capture( + player: EntityPlayerMP, + backpackWrapper: BackpackWrapper, + entity: EntityLivingBase, + advanced: Boolean + ): CaptureResult { + getEligibilityError(player, entity, advanced)?.let { return fail(player, it) } + + val hostile = isHostile(entity) + val slotCost = getSlotCost(entity, hostile) + val maxSlotCost = if (advanced) Config.mobCatcherUpgrade.advancedMaxSlotCost else Config.mobCatcherUpgrade.basicMaxSlotCost + if (slotCost > maxSlotCost) { + return fail(player, "gui.status.mob_catcher_too_large", slotCost, maxSlotCost) + } + + val footprint = MobCatcherStorage.getFootprint(entity, slotCost) + val slot = MobCatcherStorage.findEmptyRectangle(backpackWrapper, footprint) + ?: return fail(player, "gui.status.mob_catcher_no_space", footprint.width, footprint.height) + val entityType = EntityList.getKey(entity) + ?: return fail(player, "gui.status.mob_catcher_invalid_entity") + val entityTag = NBTTagCompound() + entity.writeToNBT(entityTag) + entityTag.setString("id", entityType.toString()) + entityTag.removeTag("UUIDMost") + entityTag.removeTag("UUIDLeast") + + val capturedMob = CapturedMob( + UUID.randomUUID(), + entityType, + entityTag, + slot, + footprint.width, + footprint.height, + slotCost, + hostile, + getCapturedMobDisplayName(entity), + ceil(entity.health.toDouble()).toInt(), + ceil(getEffectiveMaxHealth(entity)).toInt() + ) + MobCatcherStorage.addCapturedMob(backpackWrapper, capturedMob) + entity.setDead() + syncBackpack(player, backpackWrapper) + playMobCatcherSound(player, true, 0.7f) + return CaptureResult(true, "gui.status.mob_catcher_captured", arrayOf(capturedMob.displayName)) + } + + private fun getEligibilityError(player: EntityPlayerMP, entity: EntityLivingBase, advanced: Boolean): String? { + if (entity is EntityPlayer) { + return "gui.status.mob_catcher_players_blocked" + } + if (entity is EntityDragon || entity is EntityWither) { + return "gui.status.mob_catcher_boss_blocked" + } + if (entity.isRiding || entity.isBeingRidden) { + return "gui.status.mob_catcher_passengers_blocked" + } + val entityType = EntityList.getKey(entity) + if (entityType == null || entityType in configuredEntityTypes(Config.mobCatcherUpgrade.entityBlockList)) { + return "gui.status.mob_catcher_blocklisted" + } + if (entity is IEntityOwnable && entity.ownerId != null && entity.ownerId != player.uniqueID) { + return "gui.status.mob_catcher_not_owner" + } + if (Config.mobCatcherUpgrade.disallowInventoryEntities && entity is IInventory) { + return "gui.status.mob_catcher_inventory_blocked" + } + if (!advanced && isHostile(entity)) { + return "gui.status.mob_catcher_hostile_needs_advanced" + } + return null + } + + fun release(player: EntityPlayerMP, capturedMobId: UUID) { + val container = player.openContainer as? BackpackContainer ?: return + val backpackWrapper = container.backpackWrapper + val capturedMob = MobCatcherStorage.getCapturedMob(backpackWrapper, capturedMobId) ?: return + val entity = createEntity(player.world, capturedMob) as? EntityLivingBase ?: run { + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_release_failed".asTranslationKey()), true) + return + } + val target = getReleasePosition(player, entity) ?: run { + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_no_release_space".asTranslationKey()), true) + playMobCatcherSound(player, false, 0.8f) + return + } + entity.setLocationAndAngles(target.x, target.y, target.z, player.rotationYaw, 0f) + entity.setUniqueId(UUID.randomUUID()) + if (!player.world.spawnEntity(entity)) { + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_release_failed".asTranslationKey()), true) + return + } + MobCatcherStorage.removeCapturedMob(backpackWrapper, capturedMobId) + syncBackpack(player, backpackWrapper) + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_released".asTranslationKey(), capturedMob.displayName), true) + playMobCatcherSound(player, true, 1.2f) + } + + private fun createEntity(world: World, capturedMob: CapturedMob): Entity? { + val entity = EntityList.createEntityByIDFromName(capturedMob.entityType, world) ?: return null + entity.readFromNBT(capturedMob.entityNbt) + return entity + } + + private fun getReleasePosition(player: EntityPlayerMP, entity: EntityLivingBase): Vec3d? { + val eye = player.getPositionEyes(1f) + val look = player.lookVec + val hit = player.world.rayTraceBlocks(eye, eye.add(look.scale(RELEASE_REACH)), false, true, false) + if (hit != null && hit.typeOfHit == RayTraceResult.Type.BLOCK) { + getValidReleasePosition(player, entity, hit.blockPos.offset(hit.sideHit))?.let { return it } + getValidReleasePosition(player, entity, hit.blockPos.up())?.let { return it } + } + + var horizontal = Vec3d(look.x, 0.0, look.z) + if (horizontal.lengthSquared() < 1.0E-4) { + horizontal = Vec3d.fromPitchYaw(0f, player.rotationYaw) + } + val direction = horizontal.normalize() + val maxFallbackDistance = maxOf( + 2, + minOf(RELEASE_REACH.toInt(), ceil(entity.width / 2.0 + player.width / 2.0 + 1.0).toInt()) + ) + for (distance in 1..maxFallbackDistance) { + val candidate = player.positionVector.add(direction.scale(distance.toDouble())) + getValidReleasePosition(player, entity, BlockPos(candidate.x, player.posY, candidate.z))?.let { return it } + } + return null + } + + private fun getValidReleasePosition(player: EntityPlayerMP, entity: EntityLivingBase, spawnPos: BlockPos): Vec3d? { + val pos = getReleasePositionOnGround(player, entity, spawnPos) ?: return null + val bounds = AxisAlignedBB( + pos.x - entity.width / 2.0, + pos.y, + pos.z - entity.width / 2.0, + pos.x + entity.width / 2.0, + pos.y + entity.height, + pos.z + entity.width / 2.0 + ) + return if (player.world.getCollisionBoxes(entity, bounds).isEmpty() && + player.world.checkNoEntityCollision(bounds, entity) + ) pos else null + } + + private fun getReleasePositionOnGround(player: EntityPlayerMP, entity: EntityLivingBase, spawnPos: BlockPos): Vec3d? { + if (canReleaseWithoutGround(entity)) { + return Vec3d(spawnPos.x + 0.5, spawnPos.y.toDouble(), spawnPos.z + 0.5) + } + val groundPos = spawnPos.down() + val bounds = player.world.getBlockState(groundPos).getCollisionBoundingBox(player.world, groundPos) + if (bounds == null || bounds == Block.NULL_AABB) { + return null + } + return Vec3d(spawnPos.x + 0.5, groundPos.y + bounds.maxY, spawnPos.z + 0.5) + } + + private fun canReleaseWithoutGround(entity: EntityLivingBase): Boolean = + entity is EntityFlying || entity is EntityWaterMob || entity is net.minecraft.entity.passive.EntityFlying || entity.hasNoGravity() + + fun getBestUpgrade(backpackWrapper: BackpackWrapper): MobCatcherUpgradeWrapper? { + val upgrades = backpackWrapper.gatherCapabilityUpgrades(Capabilities.MOB_CATCHER_UPGRADE_CAPABILITY) + return upgrades.firstOrNull { it.isAdvanced } ?: upgrades.firstOrNull() + } + + fun isHostile(entity: EntityLivingBase): Boolean { + val entityType = EntityList.getKey(entity) ?: return entity is IMob + if (entityType in configuredEntityTypes(Config.mobCatcherUpgrade.passiveOverrides)) { + return false + } + return entityType in configuredEntityTypes(Config.mobCatcherUpgrade.hostileOverrides) || entity is IMob + } + + fun getSlotCost(entity: EntityLivingBase, hostile: Boolean): Int { + val maxHealth = getEffectiveMaxHealth(entity) + val currentHealth = maxOf(0.0, entity.health.toDouble()) + val baseCost = maxHealth / 2.0 + minOf(currentHealth, maxHealth) / 2.0 + val multiplier = if (hostile) Config.mobCatcherUpgrade.hostileMultiplier else Config.mobCatcherUpgrade.animalMultiplier + return maxOf(1, ceil(baseCost * multiplier).toInt()) + } + + fun getEffectiveMaxHealth(entity: EntityLivingBase): Double = + maxOf( + 1.0, + entity.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).attributeValue, + entity.maxHealth.toDouble(), + entity.health.toDouble() + ) + + private fun getCapturedMobDisplayName(entity: EntityLivingBase): String = + if (entity.hasCustomName()) entity.customNameTag else entity.displayName.unformattedText + + private fun configuredEntityTypes(configuredEntityTypes: Array): Set = + configuredEntityTypes.mapNotNull { + try { + ResourceLocation(it) + } catch (_: RuntimeException) { + null + } + }.toSet() + + private fun fail(player: EntityPlayerMP, messageKey: String, vararg args: Any): CaptureResult { + playMobCatcherSound(player, false, 0.8f) + return CaptureResult(false, messageKey, args) + } + + private fun playMobCatcherSound(player: EntityPlayerMP, success: Boolean, basePitch: Float) { + val sound = if (success) SoundEvents.ENTITY_ITEM_PICKUP else SoundEvents.BLOCK_NOTE_BASS + val pitch = basePitch + (player.rng.nextFloat() - 0.5f) * 0.16f + player.world.playSound(null, player.position, sound, SoundCategory.PLAYERS, 0.7f, pitch) + } + + private fun syncBackpack(player: EntityPlayerMP, backpackWrapper: BackpackWrapper) { + player.openContainer.detectAndSendChanges() + player.inventoryContainer.detectAndSendChanges() + CapabilityHandler.updateBackpackInventory(backpackWrapper) + syncCapturedMobsToViewers(player, backpackWrapper) + } + + private fun syncCapturedMobsToViewers(player: EntityPlayerMP, backpackWrapper: BackpackWrapper) { + player.server.playerList.players + .filter { + it == player || (it.openContainer as? BackpackContainer)?.backpackWrapper?.uuid == backpackWrapper.uuid + } + .forEach { + NetworkHandler.INSTANCE.sendTo(S2CMobCatcherContentsPacket(backpackWrapper), it) + } + } + + private data class CaptureResult(val success: Boolean, val messageKey: String, val args: Array = emptyArray()) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt new file mode 100644 index 0000000..8347cbf --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt @@ -0,0 +1,531 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.EntityList +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.nbt.NBTTagList +import net.minecraft.util.ResourceLocation +import net.minecraftforge.items.ItemHandlerHelper +import kotlin.math.abs +import kotlin.math.ceil +import kotlin.math.ln + +object MobCatcherStorage { + const val CAPTURED_MOBS_TAG = "capturedMobs" + const val CAPTURED_MOBS_COLUMNS_TAG = "capturedMobsColumns" + + private const val ID_TAG = "id" + private const val ENTITY_TYPE_TAG = "entityType" + private const val ENTITY_NBT_TAG = "entityNbt" + private const val SLOT_TAG = "slot" + private const val WIDTH_TAG = "width" + private const val HEIGHT_TAG = "height" + private const val SLOT_COST_TAG = "slotCost" + private const val HOSTILE_TAG = "hostile" + private const val DISPLAY_NAME_TAG = "displayName" + private const val CURRENT_HEALTH_TAG = "currentHealth" + private const val MAX_HEALTH_TAG = "maxHealth" + private const val TAG_COMPOUND = 10 + private const val FOOTPRINT_ASPECT_WIDENING = 1.4 + private const val FOOTPRINT_ASPECT_WEIGHT = 10.0 + private const val FOOTPRINT_OVERFILL_WEIGHT = 0.75 + private const val MOB_PART_PREFIX = "mob:" + private const val STACK_PART_PREFIX = "stack:" + private const val FIXED_PART_PREFIX = "fixed:" + + fun getCapturedMobs(backpackWrapper: BackpackWrapper): List = + backpackWrapper.capturedMobs + + fun setCapturedMobs(backpackWrapper: BackpackWrapper, capturedMobs: List) { + backpackWrapper.capturedMobs.clear() + backpackWrapper.capturedMobs.addAll(capturedMobs) + backpackWrapper.capturedMobsColumns = getColumns(backpackWrapper) + } + + fun addCapturedMob(backpackWrapper: BackpackWrapper, capturedMob: CapturedMob) { + backpackWrapper.capturedMobs.add(capturedMob) + backpackWrapper.capturedMobsColumns = getColumns(backpackWrapper) + } + + fun removeCapturedMob(backpackWrapper: BackpackWrapper, capturedMobId: java.util.UUID): Boolean { + val removed = backpackWrapper.capturedMobs.removeIf { it.id == capturedMobId } + if (removed && backpackWrapper.capturedMobs.isEmpty()) { + backpackWrapper.capturedMobsColumns = getColumns(backpackWrapper) + } + return removed + } + + fun getCapturedMob(backpackWrapper: BackpackWrapper, capturedMobId: java.util.UUID): CapturedMob? = + backpackWrapper.capturedMobs.firstOrNull { it.id == capturedMobId } + + fun getCapturedMobsTag(backpackWrapper: BackpackWrapper): NBTTagCompound { + backpackWrapper.ensureCapturedMobLayoutCurrent() + return NBTTagCompound().also { + it.setTag(CAPTURED_MOBS_TAG, serialize(getCapturedMobs(backpackWrapper))) + it.setInteger(CAPTURED_MOBS_COLUMNS_TAG, backpackWrapper.capturedMobsColumns) + } + } + + fun applyCapturedMobsTag(backpackWrapper: BackpackWrapper, nbt: NBTTagCompound) { + backpackWrapper.capturedMobs.clear() + backpackWrapper.capturedMobs.addAll(deserializeCapturedMobsTag(nbt)) + backpackWrapper.capturedMobsColumns = if (nbt.hasKey(CAPTURED_MOBS_COLUMNS_TAG)) { + nbt.getInteger(CAPTURED_MOBS_COLUMNS_TAG) + } else { + getColumns(backpackWrapper) + } + backpackWrapper.ensureCapturedMobLayoutCurrent() + } + + fun isSlotBlocked(backpackWrapper: BackpackWrapper, slot: Int): Boolean { + val columns = getColumns(backpackWrapper) + return getCapturedMobs(backpackWrapper).any { it.occupiesSlot(slot, columns) } + } + + fun canFitBasicTier(backpackWrapper: BackpackWrapper, maxSlotCost: Int): Boolean = + getCapturedMobs(backpackWrapper).all { !it.hostile && it.slotCost <= maxSlotCost } + + fun canFitWithAdditionalInventoryControls(backpackWrapper: BackpackWrapper, additionalControls: Int): Boolean { + if (additionalControls <= 0) { + return true + } + backpackWrapper.ensureCapturedMobLayoutCurrent() + val currentColumns = getColumns(backpackWrapper) + return canFitLayout(backpackWrapper, (currentColumns - additionalControls * 2).coerceAtLeast(1), currentColumns) + } + + fun findEmptyRectangle(backpackWrapper: BackpackWrapper, footprint: CapturedMobFootprint): Int? { + backpackWrapper.ensureCapturedMobLayoutCurrent() + val columns = getColumns(backpackWrapper) + val rows = ceil(backpackWrapper.backpackInventorySize().toDouble() / columns).toInt() + val capturedMobs = getCapturedMobs(backpackWrapper) + return findEmptyRectangle(backpackWrapper, footprint, columns, rows, capturedMobs) + } + + fun ensureLayoutCurrent(backpackWrapper: BackpackWrapper) { + val currentColumns = getColumns(backpackWrapper) + val previousColumns = backpackWrapper.capturedMobsColumns.takeIf { it > 0 } ?: currentColumns + val capturedMobs = getCapturedMobs(backpackWrapper) + if (capturedMobs.isEmpty()) { + backpackWrapper.capturedMobsColumns = currentColumns + return + } + if (previousColumns == currentColumns) { + return + } + + val compact = currentColumns > previousColumns + val fitResult = fitInventoryLayout( + getInventoryLayoutParts(backpackWrapper, capturedMobs, previousColumns, currentColumns), + backpackWrapper.backpackInventorySize(), + currentColumns, + compact + ) + if (!fitResult.fits) { + return + } + + applyInventoryLayout(backpackWrapper, fitResult) + backpackWrapper.capturedMobsColumns = currentColumns + } + + private fun canFitLayout(backpackWrapper: BackpackWrapper, targetColumns: Int, previousColumns: Int): Boolean { + if (targetColumns == previousColumns) { + return true + } + val capturedMobs = getCapturedMobs(backpackWrapper) + if (capturedMobs.isEmpty()) { + return true + } + return fitInventoryLayout( + getInventoryLayoutParts(backpackWrapper, capturedMobs, previousColumns, targetColumns), + backpackWrapper.backpackInventorySize(), + targetColumns, + compact = targetColumns > previousColumns + ).fits + } + + private fun getInventoryLayoutParts( + backpackWrapper: BackpackWrapper, + capturedMobs: List, + previousColumns: Int, + currentColumns: Int + ): List { + val parts = mutableListOf() + for (slot in 0 until backpackWrapper.backpackInventorySize()) { + val mobAtOrigin = capturedMobs.firstOrNull { it.slot == slot } + if (mobAtOrigin != null) { + parts += LayoutPart( + MOB_PART_PREFIX + mobAtOrigin.id, + getTargetSlot(mobAtOrigin.slot, previousColumns, currentColumns), + mobAtOrigin.width, + mobAtOrigin.height, + getOccupiedSlots(mobAtOrigin, previousColumns, backpackWrapper.backpackInventorySize()) + ) + continue + } + if (capturedMobs.any { it.occupiesSlot(slot, previousColumns) }) { + continue + } + + val stack = backpackWrapper.backpackItemStackHandler.getStackInSlot(slot) + if (stack.isEmpty) { + continue + } + val fixed = backpackWrapper.isSlotLocked(slot) || backpackWrapper.isSlotMemorized(slot) + parts += LayoutPart( + (if (fixed) FIXED_PART_PREFIX else STACK_PART_PREFIX) + slot, + slot, + 1, + 1, + setOf(slot) + ) + } + return parts + } + + private fun applyInventoryLayout(backpackWrapper: BackpackWrapper, fitResult: LayoutFitResult) { + val stackMoves = fitResult.fittedSlots.mapNotNull { (partId, targetSlot) -> + if (!partId.startsWith(STACK_PART_PREFIX)) { + return@mapNotNull null + } + val sourceSlot = partId.removePrefix(STACK_PART_PREFIX).toIntOrNull() ?: return@mapNotNull null + if (sourceSlot == targetSlot || + sourceSlot !in 0 until backpackWrapper.backpackInventorySize() || + targetSlot !in 0 until backpackWrapper.backpackInventorySize() + ) { + return@mapNotNull null + } + val stack = backpackWrapper.backpackItemStackHandler.getStackInSlot(sourceSlot) + if (stack.isEmpty) null else StackMove(sourceSlot, targetSlot, stack.copy()) + } + + if (stackMoves.isNotEmpty()) { + val sourceSlots = stackMoves.mapTo(mutableSetOf()) { it.sourceSlot } + val targetSlots = stackMoves.mapTo(mutableSetOf()) { it.targetSlot } + if (targetSlots.any { !backpackWrapper.backpackItemStackHandler.getStackInSlot(it).isEmpty && it !in sourceSlots }) { + return + } + stackMoves.forEach { backpackWrapper.backpackItemStackHandler.setStackInSlot(it.sourceSlot, net.minecraft.item.ItemStack.EMPTY) } + stackMoves.forEach { + backpackWrapper.backpackItemStackHandler.setStackInSlot( + it.targetSlot, + ItemHandlerHelper.copyStackWithSize(it.stack, it.stack.count) + ) + } + } + + val fittedMobs = getCapturedMobs(backpackWrapper).map { capturedMob -> + fitResult.fittedSlots[MOB_PART_PREFIX + capturedMob.id]?.let { capturedMob.copy(slot = it) } ?: capturedMob + } + backpackWrapper.capturedMobs.clear() + backpackWrapper.capturedMobs.addAll(fittedMobs) + } + + private fun findEmptyRectangle( + backpackWrapper: BackpackWrapper, + footprint: CapturedMobFootprint, + columns: Int, + rows: Int, + capturedMobs: List + ): Int? { + for (y in 0..rows - footprint.height) { + for (x in 0..columns - footprint.width) { + val slot = y * columns + x + if (isRectangleEmpty(backpackWrapper, slot, footprint, columns, capturedMobs)) { + return slot + } + } + } + return null + } + + private fun isRectangleEmpty( + backpackWrapper: BackpackWrapper, + slot: Int, + footprint: CapturedMobFootprint, + columns: Int, + capturedMobs: List + ): Boolean { + for (y in 0 until footprint.height) { + for (x in 0 until footprint.width) { + val checkedSlot = slot + y * columns + x + if (checkedSlot !in 0 until backpackWrapper.backpackInventorySize()) { + return false + } + if (!backpackWrapper.getStackInSlot(checkedSlot).isEmpty) { + return false + } + if (capturedMobs.any { it.occupiesSlot(checkedSlot, columns) }) { + return false + } + } + } + return true + } + + fun getFootprint(entity: EntityLivingBase, slotCost: Int): CapturedMobFootprint { + val entityWidth = maxOf(entity.width.toDouble(), 0.25) + val entityHeight = maxOf(entity.height.toDouble(), 0.25) + val targetAspect = entityWidth / entityHeight * FOOTPRINT_ASPECT_WIDENING + var best = CapturedMobFootprint(1, maxOf(1, slotCost)) + var bestScore = Double.MAX_VALUE + var bestAspectError = Double.MAX_VALUE + var bestOverfill = Int.MAX_VALUE + + for (width in 1..slotCost) { + for (height in 1..slotCost) { + val area = width * height + if (area < slotCost) { + continue + } + val aspect = width.toDouble() / height + val aspectError = abs(ln(aspect / targetAspect)) + val overfill = area - slotCost + val score = aspectError * FOOTPRINT_ASPECT_WEIGHT + overfill * FOOTPRINT_OVERFILL_WEIGHT + val isBetter = score < bestScore || + score == bestScore && ( + aspectError < bestAspectError || + aspectError == bestAspectError && ( + width > best.width || + width == best.width && ( + height < best.height || + height == best.height && overfill < bestOverfill + ) + ) + ) + if (isBetter) { + best = CapturedMobFootprint(width, height) + bestScore = score + bestAspectError = aspectError + bestOverfill = overfill + } + } + } + return best + } + + fun getColumns(backpackWrapper: BackpackWrapper): Int { + val backgroundColumns = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 + val columnsTaken = (backpackWrapper.tankUpgradeSlots().take(2).size + backpackWrapper.batteryUpgradeSlots().take(1).size) * 2 + return (backgroundColumns - columnsTaken).coerceAtLeast(1) + } + + private fun getTargetSlot(slot: Int, columns: Int, targetColumns: Int): Int = + slot / columns * targetColumns + slot % columns + + private fun getOccupiedSlots(capturedMob: CapturedMob, columns: Int, inventorySlots: Int): Set { + val occupiedSlots = mutableSetOf() + for (y in 0 until capturedMob.height) { + for (x in 0 until capturedMob.width) { + val slot = capturedMob.slot + y * columns + x + if (slot < inventorySlots) { + occupiedSlots += slot + } + } + } + return occupiedSlots + } + + private fun fitInventoryLayout( + parts: List, + targetSlots: Int, + targetColumns: Int, + compact: Boolean + ): LayoutFitResult { + val result = fitInventoryLayoutInternal(parts, targetSlots, targetColumns, compact, compact) + if (compact || result.fits) { + return result + } + + val compactResult = fitInventoryLayoutInternal(parts, targetSlots, targetColumns, compact = true, preserveStacks = false) + if (compactResult.fits) { + return compactResult + } + + val reorderedCompactResult = fitInventoryLayoutInternal( + orderPartsForCompaction(parts), + targetSlots, + targetColumns, + compact = true, + preserveStacks = false, + fillGapsWithStacks = true + ) + return if (reorderedCompactResult.fits) reorderedCompactResult else compactResult + } + + private fun orderPartsForCompaction(parts: List): List = + parts.sortedWith( + compareBy { compactionPriority(it) } + .thenByDescending { it.width * it.height } + .thenBy { it.firstSlot } + ) + + private fun compactionPriority(part: LayoutPart): Int = + when { + part.id.startsWith(FIXED_PART_PREFIX) -> 0 + part.id.startsWith(STACK_PART_PREFIX) -> 2 + else -> 1 + } + + private fun fitInventoryLayoutInternal( + parts: List, + targetSlots: Int, + targetColumns: Int, + compact: Boolean, + preserveStacks: Boolean, + fillGapsWithStacks: Boolean = false + ): LayoutFitResult { + val occupiedSlots = mutableSetOf() + val fittedSlots = mutableMapOf() + var nextSlot = 0 + + for ((partIndex, part) in parts.withIndex()) { + val fittedSlot = findNextFit( + part, + if (fillGapsWithStacks && part.id.startsWith(STACK_PART_PREFIX)) 0 else nextSlot, + targetSlots, + targetColumns, + occupiedSlots, + compact, + preserveStacks + ) + if (fittedSlot < 0) { + return LayoutFitResult( + false, + fittedSlots, + parts.drop(partIndex).flatMapTo(mutableSetOf()) { it.sourceSlots } + ) + } + + occupy(part, fittedSlot, targetColumns, occupiedSlots) + fittedSlots[part.id] = fittedSlot + nextSlot = if (!compact && fittedSlot == part.firstSlot) { + maxOf(nextSlot, getSlotAfterPart(part, fittedSlot, targetColumns)) + } else { + fittedSlot + part.width + } + } + + return LayoutFitResult(true, fittedSlots) + } + + private fun findNextFit( + part: LayoutPart, + nextSlot: Int, + targetSlots: Int, + targetColumns: Int, + occupiedSlots: Set, + compact: Boolean, + preserveStacks: Boolean + ): Int { + if (part.id.startsWith(FIXED_PART_PREFIX)) { + return if (fits(part, part.firstSlot, targetSlots, targetColumns, occupiedSlots)) part.firstSlot else -1 + } + if (shouldPreserveFirstSlot(part, compact, preserveStacks) && + part.firstSlot < targetSlots && + fits(part, part.firstSlot, targetSlots, targetColumns, occupiedSlots) + ) { + return part.firstSlot + } + + val startSlot = if (compact || part.firstSlot >= targetSlots) nextSlot else maxOf(nextSlot, part.firstSlot) + for (slot in startSlot until targetSlots) { + if (fits(part, slot, targetSlots, targetColumns, occupiedSlots)) { + return slot + } + } + return -1 + } + + private fun shouldPreserveFirstSlot(part: LayoutPart, compact: Boolean, preserveStacks: Boolean): Boolean = + !compact || preserveStacks && part.id.startsWith(STACK_PART_PREFIX) + + private fun fits(part: LayoutPart, slot: Int, targetSlots: Int, targetColumns: Int, occupiedSlots: Set): Boolean { + val x = slot % targetColumns + if (x + part.width > targetColumns) { + return false + } + for (y in 0 until part.height) { + for (partX in 0 until part.width) { + val checkedSlot = slot + y * targetColumns + partX + if (checkedSlot >= targetSlots || checkedSlot in occupiedSlots) { + return false + } + } + } + return true + } + + private fun occupy(part: LayoutPart, slot: Int, targetColumns: Int, occupiedSlots: MutableSet) { + for (y in 0 until part.height) { + for (x in 0 until part.width) { + occupiedSlots += slot + y * targetColumns + x + } + } + } + + private fun getSlotAfterPart(part: LayoutPart, slot: Int, targetColumns: Int): Int = + slot + (part.height - 1) * targetColumns + part.width + + fun serialize(capturedMobs: List): NBTTagList = + NBTTagList().also { list -> capturedMobs.sortedBy { it.slot }.forEach { list.appendTag(serialize(it)) } } + + fun deserialize(list: NBTTagList): List = + (0 until list.tagCount()).mapNotNull { deserialize(list.getCompoundTagAt(it)) } + + private fun serialize(capturedMob: CapturedMob): NBTTagCompound = + NBTTagCompound().also { tag -> + tag.setUniqueId(ID_TAG, capturedMob.id) + tag.setString(ENTITY_TYPE_TAG, capturedMob.entityType.toString()) + tag.setTag(ENTITY_NBT_TAG, capturedMob.entityNbt.copy()) + tag.setInteger(SLOT_TAG, capturedMob.slot) + tag.setInteger(WIDTH_TAG, capturedMob.width) + tag.setInteger(HEIGHT_TAG, capturedMob.height) + tag.setInteger(SLOT_COST_TAG, capturedMob.slotCost) + tag.setBoolean(HOSTILE_TAG, capturedMob.hostile) + tag.setString(DISPLAY_NAME_TAG, capturedMob.displayName) + tag.setInteger(CURRENT_HEALTH_TAG, capturedMob.currentHealth) + tag.setInteger(MAX_HEALTH_TAG, capturedMob.maxHealth) + } + + private fun deserialize(tag: NBTTagCompound): CapturedMob? { + val entityType = ResourceLocation(tag.getString(ENTITY_TYPE_TAG)) + if (!EntityList.isRegistered(entityType)) { + return null + } + return CapturedMob( + tag.getUniqueId(ID_TAG) ?: return null, + entityType, + tag.getCompoundTag(ENTITY_NBT_TAG), + tag.getInteger(SLOT_TAG), + tag.getInteger(WIDTH_TAG).coerceAtLeast(1), + tag.getInteger(HEIGHT_TAG).coerceAtLeast(1), + tag.getInteger(SLOT_COST_TAG).coerceAtLeast(1), + tag.getBoolean(HOSTILE_TAG), + tag.getString(DISPLAY_NAME_TAG), + tag.getInteger(CURRENT_HEALTH_TAG), + tag.getInteger(MAX_HEALTH_TAG).coerceAtLeast(1) + ) + } + + fun deserializeCapturedMobsTag(nbt: NBTTagCompound): List = + deserialize(nbt.getTagList(CAPTURED_MOBS_TAG, TAG_COMPOUND)) + + private data class LayoutPart( + val id: String, + val firstSlot: Int, + val width: Int, + val height: Int, + val sourceSlots: Set + ) + + private data class LayoutFitResult( + val fits: Boolean, + val fittedSlots: Map, + val errorSlots: Set = emptySet() + ) + + private data class StackMove(val sourceSlot: Int, val targetSlot: Int, val stack: net.minecraft.item.ItemStack) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt new file mode 100644 index 0000000..c6d637c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt @@ -0,0 +1,19 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.item.MobCatcherUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability + +class MobCatcherUpgradeWrapper(private val advanced: Boolean = false) : UpgradeWrapper() { + override val settingsLangKey: String = "" + + val isAdvanced: Boolean + get() = advanced + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.MOB_CATCHER_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt index f3f20a6..a08a135 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt @@ -33,6 +33,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.LockedPlayerS import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlot import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularUpgradeSlot import com.cleanroommc.retrosophisticatedbackpacks.config.ClientConfig +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.UpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSH import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSlotSH @@ -538,7 +539,10 @@ class BackpackPanel( upgradeSlotGroupWidget.setEnabledIf { !isSettingMode } for (i in 0 until backpackWrapper.upgradeSlotsSize()) { - val itemSlot = NoBackgroundItemSlot().syncHandler("upgrades", i).pos(5, 5 + i * 16).name("slot_${i}") + val itemSlot = NoBackgroundItemSlot(RSBTextures.EMPTY_UPGRADE_SLOT) + .syncHandler("upgrades", i) + .pos(5, 5 + i * 16) + .name("slot_${i}") upgradeSlotWidgets.add(itemSlot) upgradeSlotGroupWidget.child(itemSlot) @@ -613,8 +617,10 @@ class BackpackPanel( } child(SettingTabWidget().setEnabledIf { !isSettingMode }) - .child(itemDisplaySettingTabWidget) - .child(memorySettingTabWidget) + if (!Config.itemDisplayDisabled) { + child(itemDisplaySettingTabWidget) + } + child(memorySettingTabWidget) .child(sortingSettingTabWidget) .child(backpackSettingTabWidget) .child(backToBackpackTab) @@ -687,7 +693,7 @@ class BackpackPanel( } fun openItemDisplaySettings(tabWidget: TabWidget, open: Boolean) { - if (!isSettingMode) + if (!isSettingMode || Config.itemDisplayDisabled) return itemDisplaySettingTabWidget.showExpanded = open @@ -715,7 +721,7 @@ class BackpackPanel( backpackSettingTabWidget.isEnabled = isSettingMode memorySettingTabWidget.isEnabled = isSettingMode sortingSettingTabWidget.isEnabled = isSettingMode - itemDisplaySettingTabWidget.isEnabled = isSettingMode + itemDisplaySettingTabWidget.isEnabled = isSettingMode && !Config.itemDisplayDisabled isBackpackSettingTabOpened = false isMemorySettingTabOpened = false shouldMemorizeRespectNBT = false @@ -748,6 +754,9 @@ class BackpackPanel( private fun updateSettingTabEnabledStates(openTab: TabWidget, open: Boolean) { listOf(backpackSettingTabWidget, sortingSettingTabWidget, memorySettingTabWidget, itemDisplaySettingTabWidget) .forEach { it.isEnabled = !open || it == openTab } + if (Config.itemDisplayDisabled) { + itemDisplaySettingTabWidget.isEnabled = false + } } private fun closeUpgradeTabs(syncToServer: Boolean) { @@ -988,7 +997,7 @@ class BackpackPanel( wrapper ) ) - tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, 12) + tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, wrapper.discInventory.slots) } is JukeboxUpgradeWrapper -> { @@ -998,7 +1007,7 @@ class BackpackPanel( wrapper ) ) - tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, 1) + tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, wrapper.discInventory.slots) } is AdvancedToolSwapperUpgradeWrapper -> { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt index a287e5c..ea2c148 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt @@ -38,6 +38,7 @@ class BackpackInventoryScrollWidget(panel: BackpackPanel) : .name("slot_$i") ) } + slots.child(MobCatcherInventoryControlWidget(panel).pos(0, 0).name("mob_catcher_inventory_control")) return slots } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt index e59e266..1fd4747 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt @@ -11,6 +11,7 @@ import com.cleanroommc.modularui.widgets.ButtonWidget import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault @@ -91,7 +92,9 @@ class BackpackMainSettingsWidget( .child(shiftClickButton) .child(keepTabOpenButton) .child(keepSearchPhraseButton) - .child(otherPlayerButton) + if (Config.allowOpeningOtherPlayerBackpacks) { + child(otherPlayerButton) + } } override fun updateTabState() { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt new file mode 100644 index 0000000..ffe8f43 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt @@ -0,0 +1,330 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.layout.IViewportStack +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.CapturedMob +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.handler.NetworkHandler +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SMobCatcherReleasePacket +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.OpenGlHelper +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.EntityList +import net.minecraft.util.text.TextFormatting +import kotlin.math.floor +import kotlin.math.max +import kotlin.math.min + +class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : + Widget(), Interactable { + companion object { + private const val SLOT_SIZE = 18 + private const val CAPTURED_MOB_BORDER_DARK = 0xFF171717.toInt() + private const val CAPTURED_MOB_BORDER_LIGHT = 0xFF5A5A5A.toInt() + private const val CAPTURED_MOB_BACKGROUND = 0xFF2B2B2B.toInt() + private const val CAPTURED_MOB_BACKGROUND_ALT = 0xFF353535.toInt() + private const val HEAD_STATIC_YAW_RANGE = 24f + private const val HEAD_IDLE_YAW_AMPLITUDE = 33f + private const val HEAD_STATIC_PITCH_RANGE = 6f + private const val HEAD_IDLE_PITCH_AMPLITUDE = 10f + private const val HEAD_IDLE_MIN_CYCLE_TICKS = 340f + private const val HEAD_IDLE_CYCLE_VARIATION_TICKS = 180f + private const val HEAD_IDLE_MOVE_TICKS = 30f + private const val HEAD_IDLE_HOLD_TICKS = 15f + } + + private val renderEntities = mutableMapOf() + + init { + size(panel.backpackSlotsWidth, panel.colSize * SLOT_SIZE) + tooltipAutoUpdate(true) + tooltipDynamic { tooltip -> + val hovered = hoveredCapturedMob(getContext().mouseX, getContext().mouseY) ?: return@tooltipDynamic + val entity = renderEntity(hovered) + tooltip.addLine(IKey.str(tooltipDisplayName(hovered, entity))) + tooltip.addLine( + IKey.lang("gui.mob_catcher.click_to_release".asTranslationKey()) + .style(TextFormatting.GRAY, TextFormatting.ITALIC) + ) + tooltip.addLine( + IKey.str( + "${TextFormatting.RED}\u2665 ${hovered.currentHealth}/${hovered.maxHealth}" + ) + ) + tooltip.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + } + + override fun isInside(stack: IViewportStack, mx: Int, my: Int, absolute: Boolean): Boolean { + val x = if (absolute) stack.unTransformX(mx.toFloat(), my.toFloat()) else mx + val y = if (absolute) stack.unTransformY(mx.toFloat(), my.toFloat()) else my + return hoveredCapturedMob(x, y) != null + } + + override fun canHoverThrough(): Boolean = true + + override fun canClickThrough(): Boolean = true + + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (mouseButton != 0) { + return Interactable.Result.STOP + } + val capturedMob = hoveredCapturedMob(context.mouseX, context.mouseY) ?: return Interactable.Result.IGNORE + NetworkHandler.INSTANCE.sendToServer(C2SMobCatcherReleasePacket(capturedMob.id)) + Interactable.playButtonClickSound() + return Interactable.Result.SUCCESS + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + panel.backpackWrapper.ensureCapturedMobLayoutCurrent() + val theme = widgetTheme.theme + val hoveredMob = hoveredCapturedMob(context.mouseX, context.mouseY) + for (capturedMob in MobCatcherStorage.getCapturedMobs(panel.backpackWrapper)) { + val slotX = capturedMob.slot % panel.rowSize * SLOT_SIZE + val slotY = capturedMob.slot / panel.rowSize * SLOT_SIZE + val width = capturedMob.width * SLOT_SIZE + val height = capturedMob.height * SLOT_SIZE + renderCapturedMobArea(slotX, slotY, capturedMob.width, capturedMob.height) + renderEntity(capturedMob)?.let { entity -> + val state = EntityRenderState.capture(entity) + try { + prepareEntityForRender(entity, capturedMob, context) + val scale = getRenderScale(entity, width, height) + renderEntityInInventory( + slotX + width / 2, + getRenderBottomY(entity, slotY, height, scale), + scale, + entity, + context.partialTicks + ) + } finally { + state.restore(entity) + } + } + if (hoveredMob?.id == capturedMob.id) { + RSBTextures.SOLID_DOWN_ARROW_ICON.draw(context, slotX + width - 14, slotY + height - 14, 12, 12, theme) + } + } + } + + private fun renderCapturedMobArea(x: Int, y: Int, widthSlots: Int, heightSlots: Int) { + val backgroundX = x + val backgroundY = y + val width = widthSlots * SLOT_SIZE + val height = heightSlots * SLOT_SIZE + GlStateManager.disableLighting() + GlStateManager.disableDepth() + GlStateManager.color(1f, 1f, 1f, 1f) + Gui.drawRect(backgroundX, backgroundY, backgroundX + width, backgroundY + height, CAPTURED_MOB_BORDER_DARK) + Gui.drawRect(backgroundX + 1, backgroundY + 1, backgroundX + width - 1, backgroundY + height - 1, CAPTURED_MOB_BACKGROUND) + Gui.drawRect(backgroundX + 2, backgroundY + 2, backgroundX + width - 2, backgroundY + height - 2, CAPTURED_MOB_BACKGROUND_ALT) + Gui.drawRect(backgroundX + 1, backgroundY + 1, backgroundX + width - 1, backgroundY + 2, CAPTURED_MOB_BORDER_LIGHT) + Gui.drawRect(backgroundX + 1, backgroundY + 1, backgroundX + 2, backgroundY + height - 1, CAPTURED_MOB_BORDER_LIGHT) + Gui.drawRect(backgroundX + 1, backgroundY + height - 2, backgroundX + width - 1, backgroundY + height - 1, CAPTURED_MOB_BORDER_DARK) + Gui.drawRect(backgroundX + width - 2, backgroundY + 1, backgroundX + width - 1, backgroundY + height - 1, CAPTURED_MOB_BORDER_DARK) + GlStateManager.color(1f, 1f, 1f, 1f) + } + + private fun renderEntityInInventory(posX: Int, posY: Float, scale: Int, entity: EntityLivingBase, partialTicks: Float) { + val renderManager = Minecraft.getMinecraft().renderManager + val previousViewY = renderManager.playerViewY + val previousShadow = renderManager.isRenderShadow + GlStateManager.color(1f, 1f, 1f, 1f) + GlStateManager.enableColorMaterial() + GlStateManager.enableDepth() + GlStateManager.pushMatrix() + try { + GlStateManager.translate(posX.toFloat(), posY, 50f) + GlStateManager.scale((-scale).toFloat(), scale.toFloat(), scale.toFloat()) + GlStateManager.rotate(180f, 0f, 0f, 1f) + GlStateManager.rotate(135f, 0f, 1f, 0f) + RenderHelper.enableStandardItemLighting() + GlStateManager.rotate(-135f, 0f, 1f, 0f) + GlStateManager.disableCull() + renderManager.setPlayerViewY(180f) + renderManager.setRenderShadow(false) + renderManager.renderEntity(entity, 0.0, 0.0, 0.0, 0f, partialTicks, false) + } finally { + renderManager.setRenderShadow(previousShadow) + renderManager.setPlayerViewY(previousViewY) + GlStateManager.popMatrix() + GlStateManager.enableCull() + RenderHelper.disableStandardItemLighting() + GlStateManager.disableRescaleNormal() + GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit) + GlStateManager.disableTexture2D() + GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit) + GlStateManager.disableDepth() + GlStateManager.color(1f, 1f, 1f, 1f) + } + } + + private fun hoveredCapturedMob(mouseX: Int, mouseY: Int): CapturedMob? { + panel.backpackWrapper.ensureCapturedMobLayoutCurrent() + return MobCatcherStorage.getCapturedMobs(panel.backpackWrapper).firstOrNull { capturedMob -> + val x = capturedMob.slot % panel.rowSize * SLOT_SIZE + val y = capturedMob.slot / panel.rowSize * SLOT_SIZE + mouseX >= x && mouseX < x + capturedMob.width * SLOT_SIZE && + mouseY >= y && mouseY < y + capturedMob.height * SLOT_SIZE + } + } + + private fun renderEntity(capturedMob: CapturedMob): EntityLivingBase? { + renderEntities[capturedMob.id]?.let { return it } + val world = Minecraft.getMinecraft().world ?: return null + val entity = EntityList.createEntityByIDFromName(capturedMob.entityType, world) as? EntityLivingBase ?: return null + entity.readFromNBT(capturedMob.entityNbt.copy() as net.minecraft.nbt.NBTTagCompound) + renderEntities[capturedMob.id] = entity + return entity + } + + private fun tooltipDisplayName(capturedMob: CapturedMob, entity: EntityLivingBase?): String = + when { + entity == null -> capturedMob.displayName + entity.hasCustomName() -> entity.customNameTag + else -> entity.displayName.unformattedText + } + + private fun prepareEntityForRender(entity: EntityLivingBase, capturedMob: CapturedMob, context: ModularGuiContext) { + val renderTime = renderTime(capturedMob, context) + resetCapturedEntityVisualState(entity) + entity.setLocationAndAngles(0.0, 0.0, 0.0, 0f, 0f) + val bodyRot = 0f + val headOffset = -HEAD_STATIC_YAW_RANGE / 2f + uuidFloat(capturedMob.id, 1) * HEAD_STATIC_YAW_RANGE + + idlePoseOffset(capturedMob.id, renderTime, 0, HEAD_IDLE_YAW_AMPLITUDE) + val pitch = -HEAD_STATIC_PITCH_RANGE / 2f + uuidFloat(capturedMob.id, 2) * HEAD_STATIC_PITCH_RANGE + + idlePoseOffset(capturedMob.id, renderTime, 1, HEAD_IDLE_PITCH_AMPLITUDE) + entity.ticksExisted = renderTime.toInt() + entity.renderYawOffset = bodyRot + entity.prevRenderYawOffset = bodyRot + entity.rotationYaw = bodyRot + entity.prevRotationYaw = bodyRot + entity.rotationYawHead = bodyRot + headOffset + entity.prevRotationYawHead = entity.rotationYawHead + entity.rotationPitch = pitch + entity.prevRotationPitch = pitch + } + + private fun resetCapturedEntityVisualState(entity: EntityLivingBase) { + entity.hurtResistantTime = 0 + entity.hurtTime = 0 + entity.maxHurtTime = 0 + entity.deathTime = 0 + entity.attackedAtYaw = 0f + entity.limbSwing = 0f + entity.limbSwingAmount = 0f + entity.prevLimbSwingAmount = 0f + } + + private fun renderTime(capturedMob: CapturedMob, context: ModularGuiContext): Float { + val player = Minecraft.getMinecraft().player + val baseTime = player?.ticksExisted?.toFloat() ?: context.tick.toFloat() + return baseTime + context.partialTicks + uuidFloat(capturedMob.id, 3) * 200f + } + + private fun idlePoseOffset(uuid: java.util.UUID, renderTime: Float, salt: Int, amplitude: Float): Float { + val cycleLength = HEAD_IDLE_MIN_CYCLE_TICKS + uuidFloat(uuid, salt + 4) * HEAD_IDLE_CYCLE_VARIATION_TICKS + val cycle = floor(renderTime / cycleLength).toInt() + val phase = renderTime - cycle * cycleLength + val target = (cycleFloat(uuid, cycle, salt) - 0.5f) * 2f * amplitude + return when { + phase < HEAD_IDLE_MOVE_TICKS -> smoothStep(phase / HEAD_IDLE_MOVE_TICKS) * target + phase < HEAD_IDLE_MOVE_TICKS + HEAD_IDLE_HOLD_TICKS -> target + phase < HEAD_IDLE_MOVE_TICKS * 2f + HEAD_IDLE_HOLD_TICKS -> + (1f - smoothStep((phase - HEAD_IDLE_MOVE_TICKS - HEAD_IDLE_HOLD_TICKS) / HEAD_IDLE_MOVE_TICKS)) * target + else -> 0f + } + } + + private fun smoothStep(value: Float): Float = + value * value * (3f - 2f * value) + + private fun cycleFloat(uuid: java.util.UUID, cycle: Int, salt: Int): Float = + Math.floorMod(uuid.hashCode() * 31 + cycle * 131 + salt * 17, 1000) / 999f + + private fun uuidFloat(uuid: java.util.UUID, salt: Int): Float = + Math.floorMod(uuid.hashCode() + salt * 31, 1000) / 999f + + private fun getRenderScale(entity: EntityLivingBase, width: Int, height: Int): Int { + val entityWidth = max(entity.width, 0.25f) + val entityHeight = max(entity.height, 0.25f) + return max(8, (min((width - 6) / entityWidth, (height - 6) / entityHeight) * 0.5625f).toInt()) + } + + private fun getRenderBottomY(entity: EntityLivingBase, y: Int, height: Int, scale: Int): Float = + y + height / 2f + entity.height * scale / 2f + + private data class EntityRenderState( + val renderYawOffset: Float, + val prevRenderYawOffset: Float, + val rotationYaw: Float, + val prevRotationYaw: Float, + val rotationYawHead: Float, + val prevRotationYawHead: Float, + val rotationPitch: Float, + val prevRotationPitch: Float, + val ticksExisted: Int, + val hurtResistantTime: Int, + val hurtTime: Int, + val maxHurtTime: Int, + val deathTime: Int, + val attackedAtYaw: Float, + val limbSwing: Float, + val limbSwingAmount: Float, + val prevLimbSwingAmount: Float + ) { + fun restore(entity: EntityLivingBase) { + entity.renderYawOffset = renderYawOffset + entity.prevRenderYawOffset = prevRenderYawOffset + entity.rotationYaw = rotationYaw + entity.prevRotationYaw = prevRotationYaw + entity.rotationYawHead = rotationYawHead + entity.prevRotationYawHead = prevRotationYawHead + entity.rotationPitch = rotationPitch + entity.prevRotationPitch = prevRotationPitch + entity.ticksExisted = ticksExisted + entity.hurtResistantTime = hurtResistantTime + entity.hurtTime = hurtTime + entity.maxHurtTime = maxHurtTime + entity.deathTime = deathTime + entity.attackedAtYaw = attackedAtYaw + entity.limbSwing = limbSwing + entity.limbSwingAmount = limbSwingAmount + entity.prevLimbSwingAmount = prevLimbSwingAmount + } + + companion object { + fun capture(entity: EntityLivingBase): EntityRenderState = + EntityRenderState( + entity.renderYawOffset, + entity.prevRenderYawOffset, + entity.rotationYaw, + entity.prevRotationYaw, + entity.rotationYawHead, + entity.prevRotationYawHead, + entity.rotationPitch, + entity.prevRotationPitch, + entity.ticksExisted, + entity.hurtResistantTime, + entity.hurtTime, + entity.maxHurtTime, + entity.deathTime, + entity.attackedAtYaw, + entity.limbSwing, + entity.limbSwingAmount, + entity.prevLimbSwingAmount + ) + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt index 0a8ec31..77f59ba 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt @@ -72,11 +72,6 @@ class UpgradeSlotGroupWidget(private val panel: BackpackPanel, private val slotS ) LOWER_TAB_TEXTURE.draw(context, 0, heightWithoutBottom, 25, 6, widgetTheme.getThemeOrDefault()) - for (slot in 0 until slotSize) { - if (panel.backpackWrapper.upgradeItemStackHandler.getStackInSlot(slot).isEmpty) { - RSBTextures.EMPTY_UPGRADE_SLOT.draw(context, 6, 6 + slot * 16, 16, 16, widgetTheme.getThemeOrDefault()) - } - } } class UpgradeToggleWidget(private val panel: BackpackPanel, private val slotIndex: Int) : diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt index 7627eaf..4b00fd8 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt @@ -52,8 +52,13 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa get() = panel.isSortingSettingTabOpened private val isInItemDisplaySettingMode: Boolean get() = panel.isItemDisplaySettingTabOpened + private val isBlockedByCapturedMob: Boolean + get() = wrapper.isSlotBlockedByMobCatcher(slot.slotIndex) override fun buildTooltip(stack: ItemStack, tooltip: RichTooltip) { + if (isBlockedByCapturedMob) + return + val memorizedStack = wrapper.getMemorizedStack(slot.slotIndex) if (stack.isEmpty && memorizedStack.isEmpty) @@ -105,6 +110,7 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa override fun onMousePressed(mouseButton: Int): Interactable.Result = when { + isBlockedByCapturedMob -> Interactable.Result.STOP isInItemDisplaySettingMode -> handleItemDisplaySlotClick(mouseButton) isInMemorySettingMode -> handleMemorySlotClick(mouseButton) isInSortSettingMode -> handleSortSlotClick(mouseButton) @@ -114,10 +120,13 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa } override fun onMouseRelease(mouseButton: Int): Boolean = - if (isInSettingMode) true + if (isBlockedByCapturedMob || isInSettingMode) true else super.onMouseRelease(mouseButton) override fun onMouseDrag(mouseButton: Int, timeSinceClick: Long) { + if (isBlockedByCapturedMob) { + return + } if (isInMemorySettingMode) { handleMemorySlotClick(mouseButton) return @@ -203,6 +212,9 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa @SideOnly(Side.CLIENT) override fun draw(context: ModularGuiContext?, widgetThemeEntry: WidgetThemeEntry<*>?) { context?.let { + if (isBlockedByCapturedMob) + return + val widgetTheme = widgetThemeEntry?.theme ?: WidgetTheme.getDefault().theme if (isInSettingMode) { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt index b2234e6..fd670c3 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt @@ -1,10 +1,20 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widgets.slot.ItemSlot +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault -open class NoBackgroundItemSlot : ItemSlot() { +open class NoBackgroundItemSlot(private val emptyOverlay: IDrawable? = null) : ItemSlot() { init { background(IDrawable.EMPTY) } + + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawOverlay(context, widgetTheme) + if (emptyOverlay != null && isSynced && slot.stack.isEmpty) { + emptyOverlay.draw(context, 1, 1, 16, 16, widgetTheme.getThemeOrDefault()) + } + } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt index f236917..f160ff7 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt @@ -215,7 +215,7 @@ class AdvancedFilterWidget( filterSlots = mutableListOf() val filterSlotCount = filterableWrapper.filterItems.slots - val slotsInRow = minOf(4, filterSlotCount) + val slotsInRow = if (filterSlotCount > 0) filterableWrapper.slotsInRow.coerceIn(1, filterSlotCount) else 1 for (i in 0 until filterSlotCount) { val slot = PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt index 68594b4..13f473b 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt @@ -49,7 +49,7 @@ class BasicFilterWidget( filterSlots = mutableListOf() val filterSlotCount = filterableWrapper.filterItems.slots - val slotsInRow = minOf(3, filterSlotCount) + val slotsInRow = if (filterSlotCount > 0) filterableWrapper.slotsInRow.coerceIn(1, filterSlotCount) else 1 for (i in 0 until filterSlotCount) { val slot = PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt index 866fafe..b5c04b9 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt @@ -10,7 +10,6 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.BatteryUpg import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot import net.minecraft.item.ItemStack -import net.minecraftforge.items.IItemHandler class BatteryUpgradeWidget( slotIndex: Int, @@ -22,8 +21,8 @@ class BatteryUpgradeWidget( size(48, 66) val slots = SlotGroupWidget().name("battery_$slotIndex").disableSortButtons() slots.size(42, 18).pos(3, 42) - slots.child(NoBackgroundItemSlot().syncHandler("battery_$slotIndex", 0).pos(0, 0)) - slots.child(NoBackgroundItemSlot().syncHandler("battery_$slotIndex", 1).pos(21, 0)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_BATTERY_INPUT_SLOT).syncHandler("battery_$slotIndex", 0).pos(0, 0)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_BATTERY_OUTPUT_SLOT).syncHandler("battery_$slotIndex", 1).pos(21, 0)) child(slots) } @@ -38,33 +37,6 @@ class BatteryUpgradeWidget( super.draw(context, widgetTheme) } - override fun drawOverlay(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - super.drawOverlay(context, widgetTheme) - drawEmptySlotIcons(context, widgetTheme) - } - - private fun drawEmptySlotIcons(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - val inventory = wrapper.getInventory() - drawEmptySlotIcon(context, widgetTheme, inventory, 0, 4, 43, true) - drawEmptySlotIcon(context, widgetTheme, inventory, 1, 25, 43, false) - } - - private fun drawEmptySlotIcon( - context: ModularGuiContext, - widgetTheme: WidgetThemeEntry<*>, - inventory: IItemHandler, - slot: Int, - x: Int, - y: Int, - input: Boolean - ) { - if (!inventory.getStackInSlot(slot).isEmpty) { - return - } - (if (input) RSBTextures.EMPTY_BATTERY_INPUT_SLOT else RSBTextures.EMPTY_BATTERY_OUTPUT_SLOT) - .draw(context, x, y, 16, 16, widgetTheme.theme) - } - private fun energyText(wrapper: BatteryUpgradeWrapper): String = "${wrapper.energyStored}/${wrapper.getMaxEnergyStored(backpackWrapper)} FE" } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt index ee5b620..80bcbbd 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt @@ -9,12 +9,25 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpg import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RepeatMode import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack -class JukeboxUpgradeWidget(slotIndex: Int, wrapper: JukeboxUpgradeWrapper, stack: ItemStack, private val slots: Int) : - ExpandedUpgradeTabWidget(slotIndex, wrapper, if (slots > 4) 5 else 4, stack, wrapper.settingsLangKey, width = if (slots > 4) 112 else 80) { +class JukeboxUpgradeWidget( + slotIndex: Int, + wrapper: JukeboxUpgradeWrapper, + stack: ItemStack, + private val slots: Int, + private val slotsInRow: Int = if (slots > 1) Config.advancedJukeboxUpgrade.slotsInRow.coerceIn(1, slots) else 1 +) : ExpandedUpgradeTabWidget( + slotIndex, + wrapper, + if (slots > 4) 5 else 4, + stack, + wrapper.settingsLangKey, + width = if (slots > 4) 112 else 80 +) { companion object { private const val SLOT_SIZE = 18 } @@ -32,7 +45,7 @@ class JukeboxUpgradeWidget(slotIndex: Int, wrapper: JukeboxUpgradeWrapper, stack val discs = SlotGroupWidget().name("jukebox_discs_$slotIndex").disableSortButtons() discs.flex().coverChildren().leftRel(0.5F).top(if (slots > 4) 74 else 72) repeat(slots) { - discs.child(ItemSlot().syncHandler("jukebox_discs_$slotIndex", it).pos(it % 4 * SLOT_SIZE, it / 4 * SLOT_SIZE)) + discs.child(ItemSlot().syncHandler("jukebox_discs_$slotIndex", it).pos(it % slotsInRow * SLOT_SIZE, it / slotsInRow * SLOT_SIZE)) } child(discs) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt index 05c97d0..c901cf4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt @@ -7,7 +7,6 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.TankUpgrad import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot import net.minecraft.item.ItemStack -import net.minecraftforge.items.IItemHandler class TankUpgradeWidget(slotIndex: Int, wrapper: TankUpgradeWrapper, stack: ItemStack) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 3, stack, wrapper.settingsLangKey, width = 48) { @@ -16,10 +15,10 @@ class TankUpgradeWidget(slotIndex: Int, wrapper: TankUpgradeWrapper, stack: Item val slots = SlotGroupWidget().name("tank_$slotIndex").disableSortButtons() slots.size(42, 50).pos(3, 24) - slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 0).pos(0, 0)) - slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 1).pos(21, 0)) - slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 2).pos(0, 32)) - slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 3).pos(21, 32)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_TANK_INPUT_SLOT).syncHandler("tank_$slotIndex", 0).pos(0, 0)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_TANK_OUTPUT_SLOT).syncHandler("tank_$slotIndex", 1).pos(21, 0)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_TANK_INPUT_SLOT).syncHandler("tank_$slotIndex", 2).pos(0, 32)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_TANK_OUTPUT_SLOT).syncHandler("tank_$slotIndex", 3).pos(21, 32)) child(slots) } @@ -32,33 +31,4 @@ class TankUpgradeWidget(slotIndex: Int, wrapper: TankUpgradeWrapper, stack: Item RSBTextures.TANK_ARROW.draw(context, 4, 45, 15, 8, widgetTheme.theme) RSBTextures.TANK_ARROW.draw(context, 25, 45, 15, 8, widgetTheme.theme) } - - override fun drawOverlay(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - super.drawOverlay(context, widgetTheme) - drawEmptySlotIcons(context, widgetTheme) - } - - private fun drawEmptySlotIcons(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - val inventory = wrapper.getInventory() - drawEmptySlotIcon(context, widgetTheme, inventory, 0, 4, 25, true) - drawEmptySlotIcon(context, widgetTheme, inventory, 1, 25, 25, false) - drawEmptySlotIcon(context, widgetTheme, inventory, 2, 4, 57, true) - drawEmptySlotIcon(context, widgetTheme, inventory, 3, 25, 57, false) - } - - private fun drawEmptySlotIcon( - context: ModularGuiContext, - widgetTheme: WidgetThemeEntry<*>, - inventory: IItemHandler, - slot: Int, - x: Int, - y: Int, - input: Boolean - ) { - if (!inventory.getStackInSlot(slot).isEmpty) { - return - } - (if (input) RSBTextures.EMPTY_TANK_INPUT_SLOT else RSBTextures.EMPTY_TANK_OUTPUT_SLOT) - .draw(context, x, y, 16, 16, widgetTheme.theme) - } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt index 39cb5bd..2ab38d4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt @@ -12,8 +12,11 @@ class ModularBackpackSlot( wrapper.getMemorizedStack(slotIndex) override fun getSlotStackLimit(): Int = - Int.MAX_VALUE + if (wrapper.isSlotBlockedByMobCatcher(slotIndex)) 0 else Int.MAX_VALUE override fun getItemStackLimit(stack: ItemStack): Int = - stack.maxStackSize * wrapper.getTotalStackMultiplier() -} \ No newline at end of file + if (wrapper.isSlotBlockedByMobCatcher(slotIndex)) 0 else wrapper.getStackLimit(stack) + + override fun isItemValid(stack: ItemStack): Boolean = + !wrapper.isSlotBlockedByMobCatcher(slotIndex) && super.isItemValid(stack) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt index 485e0c1..2ebf60a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt @@ -8,6 +8,10 @@ import com.cleanroommc.retrosophisticatedbackpacks.item.InceptionUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.StackUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.UpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.BatteryUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.item.MobCatcherUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.item.TankUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack @@ -43,16 +47,50 @@ class ModularUpgradeSlot( else true } + if (originalUpgradeItem is MobCatcherUpgradeItem) { + if (wrapper.capturedMobs.isEmpty()) { + return true + } + return newUpgradeItem is MobCatcherUpgradeItem && + (newUpgradeItem.advanced || MobCatcherStorage.canFitBasicTier(wrapper, Config.mobCatcherUpgrade.basicMaxSlotCost)) + } + return true } override fun getItemStackLimit(stack: ItemStack): Int = 1 - override fun isItemValid(stack: ItemStack): Boolean = when (val item = stack.item) { - is StackUpgradeItem -> wrapper.canAddStackUpgrade(item.multiplier()) - is ExponentialStackUpgradeItem -> wrapper.canAddExponentialStackUpgrade() - is BatteryUpgradeItem -> wrapper.canAddBatteryUpgrade() - else -> item is UpgradeItem + override fun isItemValid(stack: ItemStack): Boolean { + val item = stack.item as? UpgradeItem ?: return false + if (!canFitConfiguredUpgradeLimit(item)) { + return false + } + return when (item) { + is StackUpgradeItem -> wrapper.canAddStackUpgrade(item.multiplier()) + is ExponentialStackUpgradeItem -> wrapper.canAddExponentialStackUpgrade() + is TankUpgradeItem -> MobCatcherStorage.canFitWithAdditionalInventoryControls( + wrapper, + if (this.stack.item is TankUpgradeItem || wrapper.tankUpgradeSlots().size >= 2) 0 else 1 + ) + is BatteryUpgradeItem -> (this.stack.item is BatteryUpgradeItem || wrapper.canAddBatteryUpgrade()) && + MobCatcherStorage.canFitWithAdditionalInventoryControls( + wrapper, + if (this.stack.item is BatteryUpgradeItem || wrapper.hasBatteryUpgrade()) 0 else 1 + ) + is MobCatcherUpgradeItem -> this.stack.item is MobCatcherUpgradeItem || wrapper.canAddMobCatcherUpgrade() + else -> true + } + } + + private fun canFitConfiguredUpgradeLimit(item: UpgradeItem): Boolean { + val (limitKey, max) = Config.getUpgradeLimit(item) ?: return true + val currentItem = stack.item as? UpgradeItem + val currentCount = wrapper.upgradeItemStackHandler.inventory.count { + val upgrade = it.item as? UpgradeItem ?: return@count false + Config.matchesUpgradeLimit(upgrade, limitKey) + } + val replacingSameLimit = currentItem != null && Config.matchesUpgradeLimit(currentItem, limitKey) + return currentCount - (if (replacingSameLimit) 1 else 0) < max } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt index 8061f23..2182bd4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt @@ -1,14 +1,51 @@ package com.cleanroommc.retrosophisticatedbackpacks.config import com.cleanroommc.retrosophisticatedbackpacks.Tags +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem +import com.cleanroommc.retrosophisticatedbackpacks.item.UpgradeItem +import net.minecraft.block.Block +import net.minecraft.item.ItemStack import net.minecraftforge.common.config.Config +import net.minecraftforge.items.CapabilityItemHandler @Config(modid = Tags.MOD_ID, name = "${Tags.MOD_ID}_general") object Config { @JvmField - @Config.Comment("Items that cannot be stored in backpack") + @Config.Comment("List of items that are not allowed to be put in backpacks - e.g. \"minecraft:shulker_box\"") + var disallowedItems = arrayOf("minecraft:shulker_box") + + @JvmField + @Config.Comment("Determines if container items are able to fit in backpacks") + var containerItemsDisallowed = false + + @JvmField + @Config.Comment("List of blocks that inventory interaction upgrades can't interact with - e.g. \"minecraft:shulker_box\"") + var noInteractionBlocks = arrayOf("minecraft:shulker_box") + + @JvmField + @Config.Comment("List of blocks that are not allowed to connect to backpacks - e.g. \"refinedstorage:external_storage\"") + var noConnectionBlocks = arrayOf() + + @JvmField + @Config.Comment("If true, disallows all blocks from connecting to backpacks") + var allBlockConnectionsDisallowed = false + + @JvmField + @Config.Comment("Turns on/off item fluid handler of backpack in its item form") + var itemFluidHandlerEnabled = true + + @JvmField + @Config.Comment("Determines whether player can right click on backpack that another player is wearing to open it") + var allowOpeningOtherPlayerBackpacks = true + + @JvmField + @Config.Comment("Allows disabling item display settings") @Config.RequiresMcRestart - var blacklistedItems = arrayOf() + var itemDisplayDisabled = false + + @JvmField + @Config.Comment("Allows disabling logic that dedupes backpacks with the same UUID in players' inventory") + var tickDedupeLogicDisabled = false @JvmField val leatherBackpack = LeatherBackpackConfig() @@ -28,54 +65,167 @@ object Config { @JvmField val stackUpgrade = StackUpgradeConfig() + @JvmField + val compactingUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedCompactingUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val depositUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedDepositUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val feedingUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedFeedingUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val filterUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedFilterUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val magnetUpgrade = MagnetUpgradeConfig(9, 3, 3) + + @JvmField + val advancedMagnetUpgrade = MagnetUpgradeConfig(16, 4, 5) + + @JvmField + val pickupUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedPickupUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val refillUpgrade = FilteredUpgradeConfig(6, 3) + + @JvmField + val advancedRefillUpgrade = FilteredUpgradeConfig(12, 4) + + @JvmField + val restockUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedRestockUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val voidUpgrade = VoidUpgradeConfig(9, 3) + + @JvmField + val advancedVoidUpgrade = VoidUpgradeConfig(16, 4) + + @JvmField + val toolSwapperUpgrade = FilteredUpgradeConfig(8, 4) + + @JvmField + val tankUpgrade = TankUpgradeConfig() + + @JvmField + val batteryUpgrade = BatteryUpgradeConfig() + + @JvmField + val pumpUpgrade = PumpUpgradeConfig() + + @JvmField + val advancedJukeboxUpgrade = JukeboxUpgradeConfig(12) + + @JvmField + val mobCatcherUpgrade = MobCatcherUpgradeConfig() + + @JvmField + val maxUpgradesPerStorage = MaxUpgradesPerStorageConfig() + + fun isItemDisallowed(stack: ItemStack): Boolean { + val registryName = stack.item.registryName?.toString() ?: return false + if (registryName in disallowedItems) { + return true + } + return containerItemsDisallowed && + stack.item !is BackpackItem && + stack.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null) + } + + fun canStackWithStackUpgrade(stack: ItemStack): Boolean { + val registryName = stack.item.registryName?.toString() ?: return true + return registryName !in stackUpgrade.nonStackableItems + } + + fun isInteractionBlockDisallowed(block: Block): Boolean = + block.registryName?.toString() in noInteractionBlocks + + fun isConnectionBlockDisallowed(block: Block): Boolean = + allBlockConnectionsDisallowed || block.registryName?.toString() in noConnectionBlocks + + fun getUpgradeLimit(upgradeItem: UpgradeItem): Pair? { + val limits = maxUpgradesPerStorage.maxUpgradesPerStorage.mapNotNull { + val parts = it.split("|", limit = 2) + val max = parts.getOrNull(1)?.toIntOrNull() ?: return@mapNotNull null + parts[0] to max + }.toMap() + val registryPath = upgradeItem.registryName?.path + if (registryPath != null && registryPath in limits) { + return registryPath to limits.getValue(registryPath) + } + val group = upgradeItem.upgradeGroup + return if (group != null && group in limits) group to limits.getValue(group) else null + } + + fun matchesUpgradeLimit(upgradeItem: UpgradeItem, limitKey: String): Boolean = + upgradeItem.registryName?.path == limitKey || upgradeItem.upgradeGroup == limitKey + class LeatherBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 27 + var inventorySlotCount = 27 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 1 + var upgradeSlotCount = 1 } class IronBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 54 + var inventorySlotCount = 54 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 2 + var upgradeSlotCount = 2 } class GoldBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 81 + var inventorySlotCount = 81 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 3 + var upgradeSlotCount = 3 } class DiamondBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 108 + var inventorySlotCount = 108 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 5 + var upgradeSlotCount = 5 } class ObsidianBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 120 + var inventorySlotCount = 120 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 7 + var upgradeSlotCount = 7 } class StackUpgradeConfig { @@ -98,5 +248,135 @@ object Config { @JvmField @Config.RequiresMcRestart var obsidianMultiplier = 32 + + @JvmField + var nonStackableItems = arrayOf( + "minecraft:shulker_box", + "minecraft:white_shulker_box", + "minecraft:orange_shulker_box", + "minecraft:magenta_shulker_box", + "minecraft:light_blue_shulker_box", + "minecraft:yellow_shulker_box", + "minecraft:lime_shulker_box", + "minecraft:pink_shulker_box", + "minecraft:gray_shulker_box", + "minecraft:silver_shulker_box", + "minecraft:cyan_shulker_box", + "minecraft:purple_shulker_box", + "minecraft:blue_shulker_box", + "minecraft:brown_shulker_box", + "minecraft:green_shulker_box", + "minecraft:red_shulker_box", + "minecraft:black_shulker_box" + ) + } + + open class FilteredUpgradeConfig(defaultFilterSlots: Int, defaultSlotsInRow: Int) { + @JvmField + var filterSlots = defaultFilterSlots + + @JvmField + var slotsInRow = defaultSlotsInRow + } + + class MagnetUpgradeConfig(defaultFilterSlots: Int, defaultSlotsInRow: Int, defaultMagnetRange: Int) { + @JvmField + var filterSlots = defaultFilterSlots + + @JvmField + var slotsInRow = defaultSlotsInRow + + @JvmField + var magnetRange = defaultMagnetRange + } + + class VoidUpgradeConfig(defaultFilterSlots: Int, defaultSlotsInRow: Int) { + @JvmField + var filterSlots = defaultFilterSlots + + @JvmField + var slotsInRow = defaultSlotsInRow + + @JvmField + var voidAlwaysEnabled = true + } + + class TankUpgradeConfig { + @JvmField + var capacityPerSlotRow = 4000 + + @JvmField + var stackMultiplierRatio = 1.0 + + @JvmField + var autoFillDrainContainerCooldown = 20 + + @JvmField + var maxInputOutput = 20 + } + + class BatteryUpgradeConfig { + @JvmField + var energyPerSlotRow = 10000 + + @JvmField + var stackMultiplierRatio = 1.0 + + @JvmField + var maxInputOutput = 20 + } + + class PumpUpgradeConfig { + @JvmField + var filterSlots = 4 + + @JvmField + var maxInputOutput = 20 + + @JvmField + var stackMultiplierRatio = 1.0 + } + + class JukeboxUpgradeConfig(defaultNumberOfSlots: Int) { + @JvmField + var numberOfSlots = defaultNumberOfSlots + + @JvmField + var slotsInRow = 4 + } + + class MobCatcherUpgradeConfig { + @JvmField + var basicMaxSlotCost = 18 + + @JvmField + var advancedMaxSlotCost = 72 + + @JvmField + var animalMultiplier = 1.0 + + @JvmField + var hostileMultiplier = 2.0 + + @JvmField + var disallowInventoryEntities = false + + @JvmField + var entityBlockList = arrayOf("minecraft:wither") + + @JvmField + var hostileOverrides = arrayOf("minecraft:enderman") + + @JvmField + var passiveOverrides = arrayOf("minecraft:villager") + } + + class MaxUpgradesPerStorageConfig { + @JvmField + var maxUpgradesPerStorage = arrayOf( + "stack|3", + "cooking|1", + "jukebox|1" + ) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt index 16149ad..82e5d7c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt @@ -3,6 +3,8 @@ package com.cleanroommc.retrosophisticatedbackpacks.handler import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.* +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import it.unimi.dsi.fastutil.objects.Object2ObjectMap import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap import net.minecraft.nbt.NBTBase @@ -210,6 +212,11 @@ object CapabilityHandler { ::AnvilUpgradeWrapper ) + instance.register( + MobCatcherUpgradeWrapper::class.java, + CapabilityStorageProvider() + ) { MobCatcherUpgradeWrapper() } + // Interfaces instance.register( UpgradeWrapper::class.java, @@ -324,6 +331,9 @@ object CapabilityHandler { } fun cacheBackpackInventory(backpackWrapper: BackpackWrapper) { + if (Config.tickDedupeLogicDisabled) { + return + } if (BACKPACK_INVENTORY_CACHE.containsKey(backpackWrapper.uuid)) { backpackWrapper.isCached = true return diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt index 5b76181..b736763 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt @@ -8,10 +8,12 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.EverlastingUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IToolSwapperUpgrade +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherHandler import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import com.cleanroommc.retrosophisticatedbackpacks.mixin.EntityItemAccessor import net.minecraft.block.material.Material import net.minecraft.entity.item.EntityItem +import net.minecraft.entity.EntityLivingBase import net.minecraft.init.SoundEvents import net.minecraft.item.ItemStack import net.minecraft.util.EnumActionResult @@ -185,6 +187,14 @@ object EntityEventHandler { if (stack.item is BackpackItem) { if (player.isSneaking) { + if (entity is EntityLivingBase) { + val captureResult = MobCatcherHandler.tryCapture(player, entity) + if (captureResult != EnumActionResult.PASS) { + event.isCanceled = true + event.cancellationResult = captureResult + return + } + } val wrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return var transferred = BackpackInventoryHelper.attemptDepositOnEntity(wrapper, entity) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt index 3251a0f..29af868 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt @@ -1,8 +1,10 @@ package com.cleanroommc.retrosophisticatedbackpacks.handler import com.cleanroommc.retrosophisticatedbackpacks.network.C2SOpenBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SMobCatcherReleasePacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SRefillBlockPickPacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SStashToBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.S2CMobCatcherContentsPacket import net.minecraftforge.fml.common.network.NetworkRegistry import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper import net.minecraftforge.fml.relauncher.Side @@ -37,5 +39,17 @@ object NetworkHandler { idGenerator.next(), Side.SERVER ) + INSTANCE.registerMessage( + C2SMobCatcherReleasePacket.Handler::class.java, + C2SMobCatcherReleasePacket::class.java, + idGenerator.next(), + Side.SERVER + ) + INSTANCE.registerMessage( + S2CMobCatcherContentsPacket.Handler::class.java, + S2CMobCatcherContentsPacket::class.java, + idGenerator.next(), + Side.CLIENT + ) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt index de14df0..8553034 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt @@ -14,13 +14,14 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) val sortLockedSlots: MutableList = MutableList(size) { false } override fun isItemValid(slot: Int, stack: ItemStack): Boolean = - if (Config.blacklistedItems.contains(stack.item.registryName?.toString())) false + if (wrapper.isSlotBlockedByMobCatcher(slot)) false + else if (Config.isItemDisallowed(stack)) false else if (memorizedSlotStack[slot].isEmpty) stack.item !is BackpackItem || wrapper.canNestBackpack() else if (memorizedSlotRespectNbtList[slot]) ItemStack.areItemStacksEqual(stack, memorizedSlotStack[slot]) else stack.isItemEqualIgnoreDurability(memorizedSlotStack[slot]) override fun getStackLimit(slotIndex: Int, stack: ItemStack): Int = - stacks[slotIndex].maxStackSize * wrapper.getTotalStackMultiplier() + wrapper.getStackLimit(stack) /** * Prioritize insertion by tries inserting on memorized slot first. @@ -55,6 +56,9 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) validateSlotIndex(slot) + if (wrapper.isSlotBlockedByMobCatcher(slot)) + return stack + if (!isItemValid(slot, stack)) return stack @@ -95,12 +99,15 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) validateSlotIndex(slotIndex) + if (wrapper.isSlotBlockedByMobCatcher(slotIndex)) + return ItemStack.EMPTY + val stack = stacks[slotIndex] if (stack.isEmpty) return ItemStack.EMPTY - val slotMaxStackSize = stack.maxStackSize * wrapper.getTotalStackMultiplier() + val slotMaxStackSize = wrapper.getStackLimit(stack) val toExtract = min(amount, slotMaxStackSize) if (stack.count <= toExtract) { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt index 2e9ef5d..8ef5321 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt @@ -1,11 +1,12 @@ package com.cleanroommc.retrosophisticatedbackpacks.inventory import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import net.minecraft.item.ItemStack import net.minecraft.util.NonNullList import net.minecraftforge.items.ItemStackHandler -class UpgradeItemStackHandler(size: Int) : ItemStackHandler(size) { +class UpgradeItemStackHandler(size: Int, private val wrapper: BackpackWrapper? = null) : ItemStackHandler(size) { val inventory: NonNullList = stacks @@ -15,6 +16,7 @@ class UpgradeItemStackHandler(size: Int) : ItemStackHandler(size) { original.getCapability(Capabilities.UPGRADE_CAPABILITY, null)?.onBeforeRemoved() } super.setStackInSlot(slot, stack) + wrapper?.ensureCapturedMobLayoutCurrent() } override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack { @@ -24,6 +26,10 @@ class UpgradeItemStackHandler(size: Int) : ItemStackHandler(size) { original.getCapability(Capabilities.UPGRADE_CAPABILITY, null)?.onBeforeRemoved() } } - return super.extractItem(slot, amount, simulate) + return super.extractItem(slot, amount, simulate).also { + if (!simulate && !it.isEmpty) { + wrapper?.ensureCapturedMobLayoutCurrent() + } + } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt index 563827e..5bf503e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt @@ -20,6 +20,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackGuiHolder import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData.InventoryType import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiFactory +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.handler.CapabilityHandler import com.cleanroommc.retrosophisticatedbackpacks.handler.RegistryHandler import com.cleanroommc.retrosophisticatedbackpacks.mixin.EntityItemAccessor @@ -188,7 +189,7 @@ class BackpackItem( if (entityIn.ticksExisted % 5 == 0) wrapper.tickUpgrades(entityIn, worldIn, entityIn.posX, entityIn.posY, entityIn.posZ) - if (!wrapper.isCached) + if (!Config.tickDedupeLogicDisabled && !wrapper.isCached) CapabilityHandler.cacheBackpackInventory(wrapper) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt index 7e29c1a..327b924 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.item import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackTier import com.cleanroommc.retrosophisticatedbackpacks.block.Blocks import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.* +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.config.Config import net.minecraft.item.Item @@ -19,8 +20,8 @@ object Items { val backpackLeather = BackpackItem( "backpack_leather", Blocks.leatherBackpack, - Config.leatherBackpack::slots, - Config.leatherBackpack::upgradeSlots, + Config.leatherBackpack::inventorySlotCount, + Config.leatherBackpack::upgradeSlotCount, BackpackTier.LEATHER ) @@ -28,8 +29,8 @@ object Items { val backpackIron = BackpackItem( "backpack_iron", Blocks.ironBackpack, - Config.ironBackpack::slots, - Config.ironBackpack::upgradeSlots, + Config.ironBackpack::inventorySlotCount, + Config.ironBackpack::upgradeSlotCount, BackpackTier.IRON ) @@ -37,8 +38,8 @@ object Items { val backpackGold = BackpackItem( "backpack_gold", Blocks.goldBackpack, - Config.goldBackpack::slots, - Config.goldBackpack::upgradeSlots, + Config.goldBackpack::inventorySlotCount, + Config.goldBackpack::upgradeSlotCount, BackpackTier.GOLD ) @@ -46,8 +47,8 @@ object Items { val backpackDiamond = BackpackItem( "backpack_diamond", Blocks.diamondBackpack, - Config.diamondBackpack::slots, - Config.diamondBackpack::upgradeSlots, + Config.diamondBackpack::inventorySlotCount, + Config.diamondBackpack::upgradeSlotCount, BackpackTier.DIAMOND ) @@ -55,8 +56,8 @@ object Items { val backpackObsidian = BackpackItem( "backpack_obsidian", Blocks.obsidianBackpack, - Config.obsidianBackpack::slots, - Config.obsidianBackpack::upgradeSlots, + Config.obsidianBackpack::inventorySlotCount, + Config.obsidianBackpack::upgradeSlotCount, BackpackTier.OBSIDIAN ) @@ -171,4 +172,10 @@ object Items { @JvmField val anvilUpgrade = AnvilUpgradeItem("anvil_upgrade", ::AnvilUpgradeWrapper) + + @JvmField + val mobCatcherUpgrade = MobCatcherUpgradeItem("mob_catcher_upgrade", false, ::MobCatcherUpgradeWrapper) + + @JvmField + val advancedMobCatcherUpgrade = MobCatcherUpgradeItem("advanced_mob_catcher_upgrade", true, ::MobCatcherUpgradeWrapper) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt index 130b9fb..acdad3f 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt @@ -7,7 +7,7 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider class JukeboxUpgradeItem( registryName: String, private val wrapperFactory: () -> IJukeboxUpgrade, -) : UpgradeItem(registryName, true) { +) : UpgradeItem(registryName, true, "jukebox") { override fun initCapabilities(stack: net.minecraft.item.ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { val capability = wrapperFactory.invoke() nbt?.let(capability::deserializeNBT) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt new file mode 100644 index 0000000..d4e8442 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt @@ -0,0 +1,18 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider + +class MobCatcherUpgradeItem( + registryName: String, + val advanced: Boolean, + private val wrapperFactory: (Boolean) -> MobCatcherUpgradeWrapper +) : UpgradeItem(registryName, false) { + override fun initCapabilities(stack: ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory(advanced) + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt index 7120b7b..542ec5a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt @@ -6,7 +6,7 @@ import net.minecraft.item.ItemStack import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World -class StackUpgradeItem(registryName: String, val multiplier: () -> Int) : UpgradeItem(registryName) { +class StackUpgradeItem(registryName: String, val multiplier: () -> Int) : UpgradeItem(registryName, upgradeGroup = "stack") { override fun addInformation( stack: ItemStack, worldIn: World?, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt index cfb736c..46568c9 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt @@ -10,7 +10,7 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World -abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false) : ItemBase() { +abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false, val upgradeGroup: String? = null) : ItemBase() { init { setCreativeTab(RetroSophisticatedBackpacks.CREATIVE_TAB) setRegistryName(registryName) @@ -43,4 +43,4 @@ abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false) : if (nbt.hasKey("Capability")) wrapper.deserializeNBT(nbt.getCompoundTag("Capability")) else wrapper.deserializeNBT(nbt) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt new file mode 100644 index 0000000..5365182 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt @@ -0,0 +1,33 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherHandler +import io.netty.buffer.ByteBuf +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext +import java.util.UUID + +class C2SMobCatcherReleasePacket() : IRefinedMessage { + private var capturedMobId: UUID = UUID(0L, 0L) + + constructor(capturedMobId: UUID) : this() { + this.capturedMobId = capturedMobId + } + + override fun toBytes(buf: ByteBuf) { + buf.writeLong(capturedMobId.mostSignificantBits) + buf.writeLong(capturedMobId.leastSignificantBits) + } + + override fun fromBytes(buf: ByteBuf) { + capturedMobId = UUID(buf.readLong(), buf.readLong()) + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: C2SMobCatcherReleasePacket, ctx: MessageContext): IRefinedMessage? { + val player = ctx.serverHandler.player + player.serverWorld.addScheduledTask { + MobCatcherHandler.release(player, message.capturedMobId) + } + return null + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt new file mode 100644 index 0000000..a3303f3 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt @@ -0,0 +1,32 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import io.netty.buffer.ByteBuf +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.fml.common.network.ByteBufUtils +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext + +class S2CMobCatcherContentsPacket() : IRefinedMessage { + private var capturedMobsTag = NBTTagCompound() + + constructor(backpackWrapper: BackpackWrapper) : this() { + capturedMobsTag = MobCatcherStorage.getCapturedMobsTag(backpackWrapper) + } + + override fun toBytes(buf: ByteBuf) { + ByteBufUtils.writeTag(buf, capturedMobsTag) + } + + override fun fromBytes(buf: ByteBuf) { + capturedMobsTag = ByteBufUtils.readTag(buf) ?: NBTTagCompound() + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: S2CMobCatcherContentsPacket, ctx: MessageContext): IRefinedMessage? { + RetroSophisticatedBackpacks.proxy.applyMobCatcherContentsSync(message.capturedMobsTag) + return null + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt index ad7e73a..b306298 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt @@ -6,15 +6,19 @@ import com.cleanroommc.retrosophisticatedbackpacks.block.Blocks import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackBlockEntityRenderer import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackDynamicModel import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackItemStackRenderer +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiFactory import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlot import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlotWrapper import com.cleanroommc.retrosophisticatedbackpacks.item.Items import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.Minecraft import net.minecraft.client.renderer.block.model.ModelResourceLocation import net.minecraft.client.settings.KeyBinding import net.minecraft.item.Item +import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.client.model.ModelLoader import net.minecraftforge.client.model.ModelLoaderRegistry import net.minecraftforge.fml.client.registry.ClientRegistry @@ -50,6 +54,8 @@ abstract class RSBProxy { open fun registerItemRenderer(item: Item, meta: Int, id: String) {} + open fun applyMobCatcherContentsSync(nbt: NBTTagCompound) {} + class ServerProxy : RSBProxy() class ClientProxy : RSBProxy() { @@ -95,5 +101,13 @@ abstract class RSBProxy { ModelLoaderRegistry.registerLoader(BackpackDynamicModel.Loader()) } + + override fun applyMobCatcherContentsSync(nbt: NBTTagCompound) { + val mc = Minecraft.getMinecraft() + mc.addScheduledTask { + val container = mc.player?.openContainer as? BackpackContainer ?: return@addScheduledTask + MobCatcherStorage.applyCapturedMobsTag(container.backpackWrapper, nbt) + } + } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt index a1d9828..5063b7a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt @@ -5,6 +5,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.backpack.DisplaySide import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHelper import com.cleanroommc.retrosophisticatedbackpacks.backpack.SortType import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import net.minecraft.item.EnumDyeColor import net.minecraft.network.PacketBuffer @@ -47,10 +48,16 @@ class BackpackSH( UPDATE_ITEM_DISPLAY_SLOT -> updateItemDisplaySlot(buf) UPDATE_ITEM_DISPLAY_ROTATION -> updateItemDisplayRotation(buf) UPDATE_ITEM_DISPLAY_COLOR -> { + if (Config.itemDisplayDisabled) { + return + } wrapper.itemDisplayColor = buf.readEnumValue(EnumDyeColor::class.java) syncRenderState() } UPDATE_ITEM_DISPLAY_SIDE -> { + if (Config.itemDisplayDisabled) { + return + } wrapper.itemDisplaySide = buf.readEnumValue(DisplaySide::class.java) syncRenderState() } @@ -98,6 +105,9 @@ class BackpackSH( } private fun updateItemDisplaySlot(buf: PacketBuffer) { + if (Config.itemDisplayDisabled) { + return + } val slotIndex = buf.readInt() val selected = buf.readBoolean() if (selected) { @@ -109,6 +119,9 @@ class BackpackSH( } private fun updateItemDisplayRotation(buf: PacketBuffer) { + if (Config.itemDisplayDisabled) { + return + } wrapper.rotateItemDisplaySlot(buf.readInt(), buf.readBoolean()) syncRenderState() } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt index 04c552a..129ada8 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt @@ -14,6 +14,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackEnergyStor import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackGuiHolder +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.block.state.IBlockState import net.minecraft.entity.player.EntityPlayer @@ -67,16 +68,28 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : @Suppress("UNCHECKED_CAST") override fun getCapability(capability: Capability, facing: EnumFacing?): T? = - if (capability == Capabilities.BACKPACK_CAPABILITY) wrapper as T - else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) this as T - else if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade()) BackpackFluidHandler(wrapper) as T - else if (capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade()) BackpackEnergyStorage(wrapper) as T - else null + when { + capability == Capabilities.BACKPACK_CAPABILITY -> wrapper as T + isExternalConnectionBlocked(facing) -> null + capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY -> this as T + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade() -> BackpackFluidHandler(wrapper) as T + capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade() -> BackpackEnergyStorage(wrapper) as T + else -> null + } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = - wrapper.hasCapability(capability, facing) || - capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade() || - capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade() + capability == Capabilities.BACKPACK_CAPABILITY || + !isExternalConnectionBlocked(facing) && + (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade() || + capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade()) + + private fun isExternalConnectionBlocked(facing: EnumFacing?): Boolean { + if (facing == null || !hasWorld()) { + return false + } + return Config.isConnectionBlockDisallowed(world.getBlockState(pos.offset(facing)).block) + } override fun writeToNBT(compound: NBTTagCompound): NBTTagCompound { compound.setTag(BACKPACK_INVENTORY_TAG, wrapper.serializeNBT()) diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang index 71808c3..df14b1e 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang @@ -239,6 +239,8 @@ item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack @@ -249,6 +251,8 @@ retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the back retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.tooltip.mob_catcher_upgrade=Captures passive mobs into backpack storage slots with sneak right-click +retro_sophisticated_backpacks.tooltip.advanced_mob_catcher_upgrade=Captures passive and hostile mobs into backpack storage slots with sneak right-click retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox @@ -279,3 +283,22 @@ retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=Only one Mob Catcher Upgrade is allowed per backpack +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=Captured %s +retro_sophisticated_backpacks.gui.status.mob_catcher_released=Released %s +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=Backpack has no Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=That mob cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=Players cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=Bosses cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=Mobs with passengers or vehicles cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=That mob is blocked from capture +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=Only the owner can capture that mob +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=Mobs with inventories cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=Hostile mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slots, more than this upgrade allows (%s) +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang index 81cea3c..ac39d89 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang @@ -278,3 +278,26 @@ retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=切换武器 retro_sophisticated_backpacks.gui.tool_swapper_any=切换任意物品 retro_sophisticated_backpacks.gui.tool_swapper_only_tools=仅切换工具 retro_sophisticated_backpacks.gui.tool_swapper_no_swap=不自动切换工具 +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=生物捕捉升级 +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=高级生物捕捉升级 +retro_sophisticated_backpacks.tooltip.mob_catcher_upgrade=潜行右击将被动生物捕捉进背包存储槽 +retro_sophisticated_backpacks.tooltip.advanced_mob_catcher_upgrade=潜行右击将被动和敌对生物捕捉进背包存储槽 +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=点击释放 +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=先释放已捕获生物再移除生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=已捕获生物需要高级生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=每个背包只能安装一个生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=已捕获 %s +retro_sophisticated_backpacks.gui.status.mob_catcher_released=已释放 %s +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=背包没有生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=该生物无法捕捉 +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=无法捕捉玩家 +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=无法捕捉Boss +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=无法捕捉有乘客或载具的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=该生物被禁止捕捉 +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=只有主人能捕捉该生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=无法捕捉带物品栏的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=敌对生物需要高级生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=该生物需要 %s 个槽,超过此升级允许的 %s 个 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=没有可用的 %sx%s 空槽区域 +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=无法在这里释放生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=这里没有有效释放空间 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json new file mode 100644 index 0000000..c94212e --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json new file mode 100644 index 0000000..80c407e --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json new file mode 100644 index 0000000..b8428e8 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json @@ -0,0 +1,34 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "H": { + "item": "minecraft:skull", + "data": 1 + }, + "D": { + "type": "forge:ore_dict", + "ore": "gemDiamond" + }, + "E": { + "item": "minecraft:ender_eye" + }, + "G": { + "type": "forge:ore_dict", + "ore": "ingotGold" + }, + "B": { + "item": "retro_sophisticated_backpacks:mob_catcher_upgrade" + }, + "S": { + "item": "minecraft:soul_sand" + } + }, + "pattern": [ + "HDE", + "GBG", + "SSS" + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json new file mode 100644 index 0000000..ee85522 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json @@ -0,0 +1,26 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "E": { + "item": "minecraft:ender_pearl" + }, + "I": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + }, + "L": { + "item": "minecraft:lead" + } + }, + "pattern": [ + " E ", + "IBI", + "L L" + ], + "result": { + "item": "retro_sophisticated_backpacks:mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/advanced_mob_catcher_upgrade.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/advanced_mob_catcher_upgrade.png new file mode 100644 index 0000000000000000000000000000000000000000..b0abe62b10e54c3c532f754b11bb3d780886923e GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKU}W=jaSX9Iot&^hz`)4Bz~ImR z#P9NI0~z43d}O)Gd#pQBmPI5%534^t`ZVJ{w4+PERJH~ zr9Y3|USD9wedcDImr{hNxyn#c9J69vucCdW!sx-i2+P zVjeq8_W$_N>)15E`{B{!`5K=LY<+lmcs>ZYv7eZw`eUbr#Z3W6w#&`exlhbGf2Zb1 z!XiEQIpWXm{62Hw_}P;MKR(&E-R_S&V5(fryc{h2;pOM>w(0NfjZ3Un7_B(vxuAvB zQC}fDEg>PnBk)mc_BX+_V{@lG7vHC-shH^7c|x-%Z)WGEJ7*Xew!1gE)h}X>1_lg+ Mr>mdKI;Vst04INixc~qF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/mob_catcher_upgrade.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/mob_catcher_upgrade.png new file mode 100644 index 0000000000000000000000000000000000000000..e123b1b526ab13057dbd7bf98e45dc4901ccd9a1 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVC3<1aSX9Iot&_MjU!O}xBMc# zZ~q@0Z2s?=Xlwukhj=~&2`Qeul>7aj!J3^vyCzO-Y;1f8Qt-Yk#VCWLSa|8rW4G7y zoD#h(`R46g$-tO~vkh&@-vx8DU3V}Vh#NfIyz=3VS~lTQOEyVPK@i>ciFv!>6$3+{ z=}*o@^#*_L?!Pag@?)n&T+N?0CH~8Yj~qB~z`#;hWHt8$Q|}MO3r`&U^584ere}wz zzc;+`N=xv0tL1k);}3mdKI;Vst01>~Bh5!Hn literal 0 HcmV?d00001 From bf85f5f7947baa02e48483e2fd806911d80ddb5b Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Sun, 7 Jun 2026 15:46:24 +0800 Subject: [PATCH 03/10] Polish mob catcher inventory rendering - Align captured mob footprint selection with upstream scoring - Rework captured mob slot rendering, ordering, lighting, and orientation - Keep captured mob hitboxes and release hints aligned with the rendered slot --- .../upgrade/mobcatcher/MobCatcherStorage.kt | 52 +++- .../MobCatcherInventoryControlWidget.kt | 273 +++++++++++++++--- 2 files changed, 272 insertions(+), 53 deletions(-) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt index 8347cbf..dd31813 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt @@ -30,6 +30,7 @@ object MobCatcherStorage { private const val FOOTPRINT_ASPECT_WIDENING = 1.4 private const val FOOTPRINT_ASPECT_WEIGHT = 10.0 private const val FOOTPRINT_OVERFILL_WEIGHT = 0.75 + private const val FOOTPRINT_SCORE_EPSILON = 0.001 private const val MOB_PART_PREFIX = "mob:" private const val STACK_PART_PREFIX = "stack:" private const val FIXED_PART_PREFIX = "fixed:" @@ -269,13 +270,14 @@ object MobCatcherStorage { val entityWidth = maxOf(entity.width.toDouble(), 0.25) val entityHeight = maxOf(entity.height.toDouble(), 0.25) val targetAspect = entityWidth / entityHeight * FOOTPRINT_ASPECT_WIDENING - var best = CapturedMobFootprint(1, maxOf(1, slotCost)) + val maxSlotCost = maxOf(1, slotCost) + var best = CapturedMobFootprint(1, maxSlotCost) var bestScore = Double.MAX_VALUE var bestAspectError = Double.MAX_VALUE var bestOverfill = Int.MAX_VALUE - for (width in 1..slotCost) { - for (height in 1..slotCost) { + for (width in 1..maxSlotCost) { + for (height in 1..maxSlotCost) { val area = width * height if (area < slotCost) { continue @@ -284,18 +286,18 @@ object MobCatcherStorage { val aspectError = abs(ln(aspect / targetAspect)) val overfill = area - slotCost val score = aspectError * FOOTPRINT_ASPECT_WEIGHT + overfill * FOOTPRINT_OVERFILL_WEIGHT - val isBetter = score < bestScore || - score == bestScore && ( - aspectError < bestAspectError || - aspectError == bestAspectError && ( - width > best.width || - width == best.width && ( - height < best.height || - height == best.height && overfill < bestOverfill - ) - ) - ) - if (isBetter) { + if (isBetterFootprint( + score, + aspectError, + overfill, + width, + height, + bestScore, + bestAspectError, + bestOverfill, + best + ) + ) { best = CapturedMobFootprint(width, height) bestScore = score bestAspectError = aspectError @@ -306,6 +308,26 @@ object MobCatcherStorage { return best } + private fun isBetterFootprint( + score: Double, + aspectError: Double, + overfill: Int, + width: Int, + height: Int, + bestScore: Double, + bestAspectError: Double, + bestOverfill: Int, + best: CapturedMobFootprint + ): Boolean { + if (score < bestScore - FOOTPRINT_SCORE_EPSILON) return true + if (score > bestScore + FOOTPRINT_SCORE_EPSILON) return false + if (aspectError < bestAspectError - FOOTPRINT_SCORE_EPSILON) return true + if (aspectError > bestAspectError + FOOTPRINT_SCORE_EPSILON) return false + if (width != best.width) return width > best.width + if (height != best.height) return height < best.height + return overfill < bestOverfill + } + fun getColumns(backpackWrapper: BackpackWrapper): Int { val backgroundColumns = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 val columnsTaken = (backpackWrapper.tankUpgradeSlots().take(2).size + backpackWrapper.batteryUpgradeSlots().take(1).size) * 2 diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt index ffe8f43..07bb582 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt @@ -3,10 +3,12 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets import com.cleanroommc.modularui.api.drawable.IKey import com.cleanroommc.modularui.api.layout.IViewportStack import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.drawable.GuiDraw import com.cleanroommc.modularui.screen.RichTooltip import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.retrosophisticatedbackpacks.Tags import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.CapturedMob import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel @@ -15,25 +17,34 @@ import com.cleanroommc.retrosophisticatedbackpacks.handler.NetworkHandler import com.cleanroommc.retrosophisticatedbackpacks.network.C2SMobCatcherReleasePacket import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.client.Minecraft -import net.minecraft.client.gui.Gui import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.renderer.OpenGlHelper import net.minecraft.client.renderer.RenderHelper import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.EntityList +import net.minecraft.util.ResourceLocation import net.minecraft.util.text.TextFormatting +import org.lwjgl.opengl.GL11 import kotlin.math.floor import kotlin.math.max import kotlin.math.min +import kotlin.math.sqrt class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : Widget(), Interactable { companion object { private const val SLOT_SIZE = 18 - private const val CAPTURED_MOB_BORDER_DARK = 0xFF171717.toInt() - private const val CAPTURED_MOB_BORDER_LIGHT = 0xFF5A5A5A.toInt() - private const val CAPTURED_MOB_BACKGROUND = 0xFF2B2B2B.toInt() - private const val CAPTURED_MOB_BACKGROUND_ALT = 0xFF353535.toInt() + private const val CAPTURED_MOB_SLOT_OFFSET = 1 + private val GUI_CONTROLS = ResourceLocation(Tags.MOD_ID, "textures/gui/gui_controls.png") + private const val GUI_CONTROLS_TEXTURE_WIDTH = 256 + private const val GUI_CONTROLS_TEXTURE_HEIGHT = 256 + private const val CAPTURED_MOB_BACKGROUND_U = 29 + private const val CAPTURED_MOB_BACKGROUND_V = 30 + private const val CAPTURED_MOB_BACKGROUND_WIDTH = 18 + private const val CAPTURED_MOB_BACKGROUND_HEIGHT = 54 + private const val CAPTURED_MOB_BACKGROUND_COLOR = 0xFF2B2B2B.toInt() + private const val CAPTURED_MOB_BACKGROUND_LAYER_COLOR = 0x184A4A4A + private const val BODY_YAW_RANGE = 50f private const val HEAD_STATIC_YAW_RANGE = 24f private const val HEAD_IDLE_YAW_AMPLITUDE = 33f private const val HEAD_STATIC_PITCH_RANGE = 6f @@ -90,20 +101,30 @@ class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : panel.backpackWrapper.ensureCapturedMobLayoutCurrent() val theme = widgetTheme.theme val hoveredMob = hoveredCapturedMob(context.mouseX, context.mouseY) - for (capturedMob in MobCatcherStorage.getCapturedMobs(panel.backpackWrapper)) { - val slotX = capturedMob.slot % panel.rowSize * SLOT_SIZE - val slotY = capturedMob.slot / panel.rowSize * SLOT_SIZE - val width = capturedMob.width * SLOT_SIZE - val height = capturedMob.height * SLOT_SIZE - renderCapturedMobArea(slotX, slotY, capturedMob.width, capturedMob.height) - renderEntity(capturedMob)?.let { entity -> + val capturedMobs = MobCatcherStorage.getCapturedMobs(panel.backpackWrapper) + .filter { isValidBackpackSlot(it.slot) } + .map { capturedMob -> + CapturedMobRenderInfo( + capturedMob, + slotX(capturedMob.slot), + slotY(capturedMob.slot), + capturedMob.width * SLOT_SIZE, + capturedMob.height * SLOT_SIZE + ) + } + + for (renderInfo in capturedMobs) { + renderCapturedMobArea(renderInfo.x, renderInfo.y, renderInfo.capturedMob.width, renderInfo.capturedMob.height) + } + for (renderInfo in capturedMobs) { + renderEntity(renderInfo.capturedMob)?.let { entity -> val state = EntityRenderState.capture(entity) try { - prepareEntityForRender(entity, capturedMob, context) - val scale = getRenderScale(entity, width, height) + prepareEntityForRender(entity, renderInfo.capturedMob, context) + val scale = getRenderScale(entity, renderInfo.width, renderInfo.height) renderEntityInInventory( - slotX + width / 2, - getRenderBottomY(entity, slotY, height, scale), + renderInfo.x + renderInfo.width / 2, + getRenderBottomY(entity, renderInfo.y, renderInfo.height, scale), scale, entity, context.partialTicks @@ -112,35 +133,173 @@ class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : state.restore(entity) } } - if (hoveredMob?.id == capturedMob.id) { - RSBTextures.SOLID_DOWN_ARROW_ICON.draw(context, slotX + width - 14, slotY + height - 14, 12, 12, theme) - } + } + capturedMobs.firstOrNull { hoveredMob?.id == it.capturedMob.id }?.let { + RSBTextures.SOLID_DOWN_ARROW_ICON.draw(context, it.x + it.width - 14, it.y + it.height - 14, 12, 12, theme) } } private fun renderCapturedMobArea(x: Int, y: Int, widthSlots: Int, heightSlots: Int) { - val backgroundX = x - val backgroundY = y + val backgroundX = x - 1 + val backgroundY = y - 1 val width = widthSlots * SLOT_SIZE val height = heightSlots * SLOT_SIZE - GlStateManager.disableLighting() - GlStateManager.disableDepth() + renderTiledControlBackground( + backgroundX, + backgroundY, + width, + height, + CAPTURED_MOB_BACKGROUND_U, + CAPTURED_MOB_BACKGROUND_V, + CAPTURED_MOB_BACKGROUND_WIDTH, + CAPTURED_MOB_BACKGROUND_HEIGHT + ) + renderCapturedMobBackgroundLayers(backgroundX + 1, backgroundY + 1, width - 2, height - 2) + } + + private fun renderCapturedMobBackgroundLayers(x: Int, y: Int, width: Int, height: Int) { + GuiDraw.drawRect(x.toFloat(), y.toFloat(), width.toFloat(), height.toFloat(), CAPTURED_MOB_BACKGROUND_COLOR) + val layers = max(1, min(5, min(width, height) / 5)) + for (layer in 0 until layers) { + val insetX = 1 + layer * width / (layers * 3) + val insetY = 1 + layer * height / (layers * 3) + val alpha = 24 + layer * 12 + val color = (alpha shl 24) or (CAPTURED_MOB_BACKGROUND_LAYER_COLOR and 0x00FFFFFF) + GuiDraw.drawRect( + (x + insetX).toFloat(), + (y + insetY).toFloat(), + (width - insetX * 2).toFloat(), + (height - insetY * 2).toFloat(), + color + ) + } + restoreTexturedGuiState() + } + + private fun restoreTexturedGuiState() { + GlStateManager.enableTexture2D() + GlStateManager.enableAlpha() + GlStateManager.disableBlend() GlStateManager.color(1f, 1f, 1f, 1f) - Gui.drawRect(backgroundX, backgroundY, backgroundX + width, backgroundY + height, CAPTURED_MOB_BORDER_DARK) - Gui.drawRect(backgroundX + 1, backgroundY + 1, backgroundX + width - 1, backgroundY + height - 1, CAPTURED_MOB_BACKGROUND) - Gui.drawRect(backgroundX + 2, backgroundY + 2, backgroundX + width - 2, backgroundY + height - 2, CAPTURED_MOB_BACKGROUND_ALT) - Gui.drawRect(backgroundX + 1, backgroundY + 1, backgroundX + width - 1, backgroundY + 2, CAPTURED_MOB_BORDER_LIGHT) - Gui.drawRect(backgroundX + 1, backgroundY + 1, backgroundX + 2, backgroundY + height - 1, CAPTURED_MOB_BORDER_LIGHT) - Gui.drawRect(backgroundX + 1, backgroundY + height - 2, backgroundX + width - 1, backgroundY + height - 1, CAPTURED_MOB_BORDER_DARK) - Gui.drawRect(backgroundX + width - 2, backgroundY + 1, backgroundX + width - 1, backgroundY + height - 1, CAPTURED_MOB_BORDER_DARK) + } + + private fun renderTiledControlBackground( + x: Int, + y: Int, + width: Int, + height: Int, + u: Int, + v: Int, + textureWidth: Int, + textureHeight: Int + ) { + val leftWidth = 1 + val topHeight = 1 + val rightWidth = min(1, width - leftWidth) + val bottomHeight = min(1, height - topHeight) + val sourceRightU = u + textureWidth - rightWidth + val sourceBottomV = v + textureHeight - bottomHeight + val centerWidth = width - leftWidth - rightWidth + val centerHeight = height - topHeight - bottomHeight + val sourceCenterWidth = textureWidth - leftWidth - rightWidth + val sourceCenterHeight = textureHeight - topHeight - bottomHeight + GlStateManager.color(1f, 1f, 1f, 1f) + drawGuiControlsTexture(x, y, leftWidth, topHeight, u, v) + drawGuiControlsTexture(x + leftWidth + centerWidth, y, rightWidth, topHeight, sourceRightU, v) + drawGuiControlsTexture(x, y + topHeight + centerHeight, leftWidth, bottomHeight, u, sourceBottomV) + drawGuiControlsTexture( + x + leftWidth + centerWidth, + y + topHeight + centerHeight, + rightWidth, + bottomHeight, + sourceRightU, + sourceBottomV + ) + renderTiledTexture(x + leftWidth, y, centerWidth, topHeight, u + leftWidth, v, sourceCenterWidth, topHeight) + renderTiledTexture( + x + leftWidth, + y + topHeight + centerHeight, + centerWidth, + bottomHeight, + u + leftWidth, + sourceBottomV, + sourceCenterWidth, + bottomHeight + ) + renderTiledTexture(x, y + topHeight, leftWidth, centerHeight, u, v + topHeight, leftWidth, sourceCenterHeight) + renderTiledTexture( + x + leftWidth + centerWidth, + y + topHeight, + rightWidth, + centerHeight, + sourceRightU, + v + topHeight, + rightWidth, + sourceCenterHeight + ) + renderTiledTexture( + x + leftWidth, + y + topHeight, + centerWidth, + centerHeight, + u + leftWidth, + v + topHeight, + sourceCenterWidth, + sourceCenterHeight + ) + } + + private fun renderTiledTexture( + x: Int, + y: Int, + width: Int, + height: Int, + u: Int, + v: Int, + textureWidth: Int, + textureHeight: Int + ) { + if (width <= 0 || height <= 0 || textureWidth <= 0 || textureHeight <= 0) { + return + } + var renderedY = 0 + while (renderedY < height) { + val chunkHeight = min(textureHeight, height - renderedY) + var renderedX = 0 + while (renderedX < width) { + val chunkWidth = min(textureWidth, width - renderedX) + drawGuiControlsTexture(x + renderedX, y + renderedY, chunkWidth, chunkHeight, u, v) + renderedX += chunkWidth + } + renderedY += chunkHeight + } + } + + private fun drawGuiControlsTexture(x: Int, y: Int, width: Int, height: Int, u: Int, v: Int) { + if (width <= 0 || height <= 0) { + return + } + GuiDraw.drawTexture( + GUI_CONTROLS, + x.toFloat(), + y.toFloat(), + width.toFloat(), + height.toFloat(), + u, + v, + GUI_CONTROLS_TEXTURE_WIDTH, + GUI_CONTROLS_TEXTURE_HEIGHT + ) } private fun renderEntityInInventory(posX: Int, posY: Float, scale: Int, entity: EntityLivingBase, partialTicks: Float) { val renderManager = Minecraft.getMinecraft().renderManager val previousViewY = renderManager.playerViewY val previousShadow = renderManager.isRenderShadow - GlStateManager.color(1f, 1f, 1f, 1f) + val previousBrightnessX = OpenGlHelper.lastBrightnessX + val previousBrightnessY = OpenGlHelper.lastBrightnessY + restoreTexturedGuiState() GlStateManager.enableColorMaterial() GlStateManager.enableDepth() GlStateManager.pushMatrix() @@ -148,9 +307,8 @@ class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : GlStateManager.translate(posX.toFloat(), posY, 50f) GlStateManager.scale((-scale).toFloat(), scale.toFloat(), scale.toFloat()) GlStateManager.rotate(180f, 0f, 0f, 1f) - GlStateManager.rotate(135f, 0f, 1f, 0f) - RenderHelper.enableStandardItemLighting() - GlStateManager.rotate(-135f, 0f, 1f, 0f) + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 220f, 220f) + enableFrontEntityLighting() GlStateManager.disableCull() renderManager.setPlayerViewY(180f) renderManager.setRenderShadow(false) @@ -161,25 +319,56 @@ class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : GlStateManager.popMatrix() GlStateManager.enableCull() RenderHelper.disableStandardItemLighting() + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, previousBrightnessX, previousBrightnessY) GlStateManager.disableRescaleNormal() GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit) GlStateManager.disableTexture2D() GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit) GlStateManager.disableDepth() - GlStateManager.color(1f, 1f, 1f, 1f) + restoreTexturedGuiState() } } + private fun enableFrontEntityLighting() { + GlStateManager.enableLighting() + GlStateManager.enableLight(0) + GlStateManager.enableLight(1) + GlStateManager.enableColorMaterial() + GlStateManager.colorMaterial(GL11.GL_FRONT_AND_BACK, GL11.GL_AMBIENT_AND_DIFFUSE) + setFrontEntityLight(GL11.GL_LIGHT0, 0f, 0.65f, 1f, 0.55f) + setFrontEntityLight(GL11.GL_LIGHT1, 0f, -0.25f, 1f, 0.35f) + GlStateManager.shadeModel(GL11.GL_FLAT) + GlStateManager.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, RenderHelper.setColorBuffer(0.32f, 0.32f, 0.32f, 1f)) + } + + private fun setFrontEntityLight(light: Int, x: Float, y: Float, z: Float, diffuse: Float) { + val length = sqrt((x * x + y * y + z * z).toDouble()).toFloat().takeIf { it > 0f } ?: 1f + GlStateManager.glLight(light, GL11.GL_POSITION, RenderHelper.setColorBuffer(x / length, y / length, z / length, 0f)) + GlStateManager.glLight(light, GL11.GL_DIFFUSE, RenderHelper.setColorBuffer(diffuse, diffuse, diffuse, 1f)) + GlStateManager.glLight(light, GL11.GL_AMBIENT, RenderHelper.setColorBuffer(0f, 0f, 0f, 1f)) + GlStateManager.glLight(light, GL11.GL_SPECULAR, RenderHelper.setColorBuffer(0f, 0f, 0f, 1f)) + } + private fun hoveredCapturedMob(mouseX: Int, mouseY: Int): CapturedMob? { panel.backpackWrapper.ensureCapturedMobLayoutCurrent() return MobCatcherStorage.getCapturedMobs(panel.backpackWrapper).firstOrNull { capturedMob -> - val x = capturedMob.slot % panel.rowSize * SLOT_SIZE - val y = capturedMob.slot / panel.rowSize * SLOT_SIZE + if (!isValidBackpackSlot(capturedMob.slot)) { + return@firstOrNull false + } + val x = slotX(capturedMob.slot) - 1 + val y = slotY(capturedMob.slot) - 1 mouseX >= x && mouseX < x + capturedMob.width * SLOT_SIZE && mouseY >= y && mouseY < y + capturedMob.height * SLOT_SIZE } } + private fun isValidBackpackSlot(slot: Int): Boolean = + slot in 0 until panel.backpackWrapper.backpackInventorySize() + + private fun slotX(slot: Int): Int = slot % panel.rowSize * SLOT_SIZE + CAPTURED_MOB_SLOT_OFFSET + + private fun slotY(slot: Int): Int = slot / panel.rowSize * SLOT_SIZE + CAPTURED_MOB_SLOT_OFFSET + private fun renderEntity(capturedMob: CapturedMob): EntityLivingBase? { renderEntities[capturedMob.id]?.let { return it } val world = Minecraft.getMinecraft().world ?: return null @@ -200,7 +389,7 @@ class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : val renderTime = renderTime(capturedMob, context) resetCapturedEntityVisualState(entity) entity.setLocationAndAngles(0.0, 0.0, 0.0, 0f, 0f) - val bodyRot = 0f + val bodyRot = (uuidFloat(capturedMob.id, 0) - 0.5f) * BODY_YAW_RANGE val headOffset = -HEAD_STATIC_YAW_RANGE / 2f + uuidFloat(capturedMob.id, 1) * HEAD_STATIC_YAW_RANGE + idlePoseOffset(capturedMob.id, renderTime, 0, HEAD_IDLE_YAW_AMPLITUDE) val pitch = -HEAD_STATIC_PITCH_RANGE / 2f + uuidFloat(capturedMob.id, 2) * HEAD_STATIC_PITCH_RANGE + @@ -327,4 +516,12 @@ class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : ) } } + + private data class CapturedMobRenderInfo( + val capturedMob: CapturedMob, + val x: Int, + val y: Int, + val width: Int, + val height: Int + ) } From 9a051694f41794c8a88ad26c39c390eb54d21824 Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Sun, 7 Jun 2026 15:56:28 +0800 Subject: [PATCH 04/10] gitignore --- .gitignore | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 101fc45..322e5e1 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,4 @@ build # other eclipse -run - -source/ -docs/ -AGENTS.md \ No newline at end of file +run \ No newline at end of file From b7c09779271c0f2b35d04c4f5111ebc8b6a62174 Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Mon, 8 Jun 2026 11:47:58 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=A1=B9=E3=80=81=E8=83=8C=E5=8C=85=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 - build.gradle.kts | 8 +- gradle.properties | 2 +- .../capability/Capabilities.java | 4 + .../mixin/LayerArmorBaseMixin.java | 2 +- .../RetroSophisticatedBackpacks.kt | 9 +- .../backpack/BackpackDataFixer.kt | 6 +- .../backpack/BackpackInventoryHelper.kt | 53 +- .../block/BackpackBlock.kt | 10 + .../capability/BackpackFluidItemHandler.kt | 27 + .../capability/BackpackWrapper.kt | 138 ++++- .../upgrade/AdvancedDepositUpgradeWrapper.kt | 7 +- .../upgrade/AdvancedFeedingUpgradeWrapper.kt | 35 +- .../upgrade/AdvancedFilterUpgradeWrapper.kt | 5 +- .../upgrade/AdvancedPickupUpgradeWrapper.kt | 7 +- .../upgrade/AdvancedRestockUpgradeWrapper.kt | 7 +- .../upgrade/AdvancedUpgradeWrapper.kt | 3 +- .../capability/upgrade/BasicUpgradeWrapper.kt | 3 +- .../upgrade/BatteryUpgradeWrapper.kt | 12 +- .../upgrade/CompactingUpgradeWrapper.kt | 9 +- .../upgrade/DepositUpgradeWrapper.kt | 7 +- .../upgrade/FeedingUpgradeWrapper.kt | 25 +- .../upgrade/FilterUpgradeWrapper.kt | 7 +- .../capability/upgrade/IAdvancedFilterable.kt | 4 +- .../capability/upgrade/IBasicFilterable.kt | 5 +- .../capability/upgrade/IFeedingUpgrade.kt | 10 + .../upgrade/JukeboxUpgradeWrapper.kt | 3 +- .../upgrade/MagnetUpgradeWrapper.kt | 15 +- .../upgrade/PickupUpgradeWrapper.kt | 7 +- .../capability/upgrade/PumpUpgradeWrapper.kt | 16 +- .../upgrade/RefillUpgradeWrapper.kt | 11 +- .../upgrade/RestockUpgradeWrapper.kt | 7 +- .../capability/upgrade/TankUpgradeWrapper.kt | 15 +- .../upgrade/ToolSwapperUpgradeWrapper.kt | 4 +- .../capability/upgrade/VoidUpgradeWrapper.kt | 25 +- .../upgrade/mobcatcher/CapturedMob.kt | 30 + .../mobcatcher/CapturedMobFootprint.kt | 6 + .../upgrade/mobcatcher/MobCatcherHandler.kt | 288 +++++++++ .../upgrade/mobcatcher/MobCatcherStorage.kt | 553 ++++++++++++++++++ .../mobcatcher/MobCatcherUpgradeWrapper.kt | 19 + .../client/gui/BackpackPanel.kt | 351 ++++++++++- .../client/gui/RSBTextures.kt | 48 +- .../client/gui/UpgradeSlotUpdateGroup.kt | 19 +- .../gui/widgets/BackToBackpackTabWidget.kt | 4 +- .../widgets/BackpackInventoryScrollWidget.kt | 24 +- .../gui/widgets/BackpackMainSettingsWidget.kt | 23 +- .../gui/widgets/CyclicVariantButtonWidget.kt | 20 +- .../gui/widgets/DynamicIconButtonWidget.kt | 11 +- .../gui/widgets/ItemDisplaySettingsWidget.kt | 5 +- .../MobCatcherInventoryControlWidget.kt | 536 +++++++++++++++++ .../client/gui/widgets/SettingTabWidget.kt | 4 +- .../client/gui/widgets/TabWidget.kt | 9 +- .../gui/widgets/TransferButtonWidget.kt | 21 +- .../gui/widgets/UpgradeSlotGroupWidget.kt | 5 - .../gui/widgets/VanillaTextFieldWidget.kt | 146 +++++ .../client/gui/widgets/slot/BackpackSlot.kt | 40 +- .../gui/widgets/slot/NoBackgroundItemSlot.kt | 12 +- .../upgrade/AdvancedFeedingUpgradeWidget.kt | 4 +- .../widgets/upgrade/AdvancedFilterWidget.kt | 2 +- .../gui/widgets/upgrade/AnvilUpgradeWidget.kt | 159 +++-- .../gui/widgets/upgrade/BasicFilterWidget.kt | 2 +- .../widgets/upgrade/BatteryUpgradeWidget.kt | 54 +- .../widgets/upgrade/JukeboxUpgradeWidget.kt | 19 +- .../gui/widgets/upgrade/PumpUpgradeWidget.kt | 32 +- .../gui/widgets/upgrade/TankUpgradeWidget.kt | 34 +- .../common/gui/slot/ModularBackpackSlot.kt | 9 +- .../common/gui/slot/ModularUpgradeSlot.kt | 48 +- .../compat/jei/BackpackSubtypeInterpreter.kt | 12 + .../RetroSophisticatedBackpacksJEIPlugin.kt | 27 + .../compat/theoneprobe/OneProbePlugin.kt | 53 ++ .../config/Config.kt | 304 +++++++++- .../crafting/DyeingRecipeRegistry.kt | 27 +- .../RetroSophisticatedBackpacksJEIPlugin.kt | 25 - .../handler/CapabilityHandler.kt | 10 + .../handler/ClientImeInputHandler.kt | 29 + .../handler/EntityEventHandler.kt | 10 + .../handler/NetworkHandler.kt | 14 + .../inventory/BackpackItemStackHandler.kt | 13 +- .../inventory/UpgradeItemStackHandler.kt | 10 +- .../item/BackpackItem.kt | 112 +++- .../retrosophisticatedbackpacks/item/Items.kt | 27 +- .../item/JukeboxUpgradeItem.kt | 2 +- .../item/MobCatcherUpgradeItem.kt | 18 + .../item/StackUpgradeItem.kt | 2 +- .../item/UpgradeItem.kt | 4 +- .../network/C2SMobCatcherReleasePacket.kt | 33 ++ .../network/S2CMobCatcherContentsPacket.kt | 32 + .../proxy/RSBProxy.kt | 14 + .../sync/BackpackSH.kt | 18 + .../sync/FoodFilterSlotSH.kt | 6 +- .../sync/UpgradeSlotSH.kt | 29 +- .../tileentity/BackpackTileEntity.kt | 69 ++- .../util/BackpackItemStackHelper.kt | 28 +- .../lang/en_us.lang | 62 +- .../lang/zh_cn.lang | 71 ++- .../item/advanced_mob_catcher_upgrade.json | 6 + .../models/item/mob_catcher_upgrade.json | 6 + .../recipes/advanced_deposit_upgrade.json | 11 +- .../recipes/advanced_feeding_upgrade.json | 11 +- .../recipes/advanced_filter_upgrade.json | 11 +- .../recipes/advanced_mob_catcher_upgrade.json | 34 ++ .../recipes/advanced_pickup_upgrade.json | 11 +- .../recipes/advanced_restock_upgrade.json | 11 +- .../recipes/backpack_diamond.json | 5 +- .../recipes/backpack_gold.json | 5 +- .../recipes/backpack_iron.json | 5 +- .../recipes/backpack_leather.json | 11 +- .../recipes/backpack_obsidian.json | 8 +- .../recipes/crafting_upgrade.json | 4 +- .../recipes/deposit_upgrade.json | 11 +- .../recipes/exponential_stack_upgrade.json | 8 +- .../recipes/feeding_upgrade.json | 5 +- .../recipes/filter_upgrade.json | 8 +- .../recipes/inception_upgrade.json | 8 +- .../recipes/mob_catcher_upgrade.json | 26 + .../recipes/pickup_upgrade.json | 8 +- .../recipes/restock_upgrade.json | 11 +- .../recipes/stack_upgrade_starter_tier.json | 5 +- .../recipes/stack_upgrade_tier_1.json | 5 +- .../recipes/stack_upgrade_tier_2.json | 5 +- .../recipes/stack_upgrade_tier_3.json | 5 +- .../recipes/stack_upgrade_tier_4.json | 5 +- .../recipes/upgrade_base.json | 11 +- .../item/advanced_mob_catcher_upgrade.png | Bin 0 -> 319 bytes .../textures/item/mob_catcher_upgrade.png | Bin 0 -> 325 bytes 125 files changed, 3826 insertions(+), 544 deletions(-) create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidItemHandler.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/VanillaTextFieldWidget.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/BackpackSubtypeInterpreter.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/RetroSophisticatedBackpacksJEIPlugin.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/theoneprobe/OneProbePlugin.kt delete mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/RetroSophisticatedBackpacksJEIPlugin.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientImeInputHandler.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/advanced_mob_catcher_upgrade.png create mode 100644 src/main/resources/assets/retro_sophisticated_backpacks/textures/item/mob_catcher_upgrade.png diff --git a/.gitignore b/.gitignore index 101fc45..2c770e0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,3 @@ build # other eclipse run - -source/ -docs/ -AGENTS.md \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index c231bfd..a0bc313 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ - import org.jetbrains.gradle.ext.Gradle import org.jetbrains.gradle.ext.compiler import org.jetbrains.gradle.ext.runConfigurations @@ -138,6 +137,10 @@ repositories { name = "BlameJared Maven" url = uri("https://maven.blamejared.com") } + maven { + name = "RyanLiptak Maven" + url = uri("https://www.ryanliptak.com/maven/") + } mavenLocal() // Must be last for caching to work } @@ -146,10 +149,11 @@ dependencies { exclude("net.minecraftforge") } - implementation("com.cleanroommc:modularui:3.1.2") + implementation("com.cleanroommc:modularui:3.1.6") compileOnlyApi(rfg.deobf("curse.maven:neverenoughanimation-1062347:6533650-sources-6533651")) runtimeOnly(rfg.deobf("curse.maven:inventory-bogosorter-632327:7412409-sources-7412411")) implementation(rfg.deobf("curse.maven:baubles-227083:2518667")) + compileOnlyApi(rfg.deobf("applecore:AppleCore:1.12.2-3.4.0+356.64453:api")) compileOnly(rfg.deobf("curse.maven:fluidlogged-api-485654:3697254")) // Oldest supported version (v1.7) if (use_assetmover.toBoolean()) { diff --git a/gradle.properties b/gradle.properties index cca61f7..8bfae4c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs = -Xmx3G # Mod Information -mod_version = 1.1.1 +mod_version = 1.1.2 maven_group = com.cleanroommc.retrosophisticatedbackpacks mod_id = retro_sophisticated_backpacks archives_base_name = RetroSophisticatedBackpacks diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java index 78c1643..1d78b26 100644 --- a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/capability/Capabilities.java @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability; import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.*; +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityInject; import org.jetbrains.annotations.NotNull; @@ -98,6 +99,9 @@ public final class Capabilities { @CapabilityInject(AnvilUpgradeWrapper.class) public static final @NotNull Capability ANVIL_UPGRADE_CAPABILITY = null; + @CapabilityInject(MobCatcherUpgradeWrapper.class) + public static final @NotNull Capability MOB_CATCHER_UPGRADE_CAPABILITY = null; + // Abstract capabilities @CapabilityInject(UpgradeWrapper.class) public static final @NotNull Capability> UPGRADE_CAPABILITY = null; diff --git a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/LayerArmorBaseMixin.java b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/LayerArmorBaseMixin.java index 0b3171a..c355aeb 100644 --- a/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/LayerArmorBaseMixin.java +++ b/src/main/java/com/cleanroommc/retrosophisticatedbackpacks/mixin/LayerArmorBaseMixin.java @@ -38,6 +38,7 @@ public abstract class LayerArmorBaseMixin implements LayerR protected abstract void setModelSlotVisible(T p_188359_1_, EntityEquipmentSlot slotIn); @Inject(method = "renderArmorLayer", at = @At(value = "TAIL")) + @SuppressWarnings("unchecked") private void injectRenderArmorLayer(EntityLivingBase entityLivingBaseIn, float limbSwing, float limbSwingAmount, @@ -59,7 +60,6 @@ private void injectRenderArmorLayer(EntityLivingBase entityLivingBaseIn, T t = thisObject.getModelFromSlot(slotIn); t = getArmorModelHook(entityLivingBaseIn, itemStack, slotIn, t); - System.out.println("KEK"); t.setModelAttributes(renderer.getMainModel()); t.setLivingAnimations(entityLivingBaseIn, limbSwing, limbSwingAmount, partialTicks); setModelSlotVisible(t, slotIn); diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/RetroSophisticatedBackpacks.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/RetroSophisticatedBackpacks.kt index c417c0e..21d8423 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/RetroSophisticatedBackpacks.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/RetroSophisticatedBackpacks.kt @@ -1,5 +1,6 @@ package com.cleanroommc.retrosophisticatedbackpacks +import com.cleanroommc.retrosophisticatedbackpacks.compat.theoneprobe.OneProbePlugin import com.cleanroommc.retrosophisticatedbackpacks.handler.CapabilityHandler import com.cleanroommc.retrosophisticatedbackpacks.handler.NetworkHandler import com.cleanroommc.retrosophisticatedbackpacks.item.Items @@ -11,6 +12,7 @@ import net.minecraftforge.fml.common.Loader import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.SidedProxy import net.minecraftforge.fml.common.event.FMLInitializationEvent +import net.minecraftforge.fml.common.event.FMLInterModComms import net.minecraftforge.fml.common.event.FMLPostInitializationEvent import net.minecraftforge.fml.common.event.FMLPreInitializationEvent import net.minecraftforge.fml.common.event.FMLServerStoppedEvent @@ -41,6 +43,8 @@ object RetroSophisticatedBackpacks { var baublesLoaded = false private set + var appleCoreLoaded = false + private set val CREATIVE_TAB = object : CreativeTabs("creative_tab".asTranslationKey()) { override fun createIcon(): ItemStack = @@ -52,8 +56,11 @@ object RetroSophisticatedBackpacks { CapabilityHandler.register() baublesLoaded = Loader.isModLoaded("baubles") + appleCoreLoaded = Loader.isModLoaded("applecore") proxy.preInit(event) + + FMLInterModComms.sendFunctionMessage("theoneprobe", "getTheOneProbe", OneProbePlugin::class.java.name) } @Mod.EventHandler @@ -73,4 +80,4 @@ object RetroSophisticatedBackpacks { CapabilityHandler.BACKPACK_INVENTORY_CACHE.clear() LOGGER.info("Backpack UUID cache has been cleared") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackDataFixer.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackDataFixer.kt index 5f6be12..a78f759 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackDataFixer.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackDataFixer.kt @@ -1,7 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.backpack +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IFeedingUpgrade import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler -import net.minecraft.item.ItemFood import net.minecraft.item.ItemStack object BackpackDataFixer { @@ -9,9 +9,9 @@ object BackpackDataFixer { for (slotIndex in 0 until filterStacks.slots) { val stack = filterStacks.getStackInSlot(slotIndex) - if (stack.item !is ItemFood) { + if (!IFeedingUpgrade.isValidFood(stack)) { filterStacks.setStackInSlot(slotIndex, ItemStack.EMPTY) } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt index 5be8ba2..d6d53ab 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.backpack import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import net.minecraft.entity.Entity import net.minecraft.inventory.IInventory @@ -40,7 +41,7 @@ object BackpackInventoryHelper { val isMemorizedSlot = wrapper.isSlotMemorized(i) val baseStack = wrapper.getStackInSlot(i) - val maxSize = baseStack.maxStackSize * wrapper.getTotalStackMultiplier() + val maxSize = wrapper.getStackLimit(baseStack) for (j in i + 1 until wrapper.backpackInventorySize()) { if (isMemorizedSlot != wrapper.isSlotMemorized(j) || wrapper.isSlotLocked(j)) @@ -123,6 +124,11 @@ object BackpackInventoryHelper { ) { for (i in 9 until playerInventory.slots) { var stack = playerInventory.getStackInSlot(i) + if (stack.isEmpty) + continue + + if (transferMatched && !backpackContainsOrMemory(wrapper, stack)) + continue if (stack.item is BackpackItem) { val currentBackpackWrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) @@ -134,13 +140,11 @@ object BackpackInventoryHelper { continue } + stack = wrapper.backpackItemStackHandler.insertItemToMemorySlots(stack, false) for (j in 0 until wrapper.backpackInventorySize()) { - stack = wrapper.backpackItemStackHandler.insertItemToMemorySlots(stack, false) - - if (transferMatched && wrapper.getStackInSlot(j).isEmpty) - continue - stack = wrapper.insertItem(j, stack, false) + if (stack.isEmpty) + break } playerInventory.setStackInSlot(i, stack) @@ -154,19 +158,45 @@ object BackpackInventoryHelper { ) { for (i in 0 until wrapper.backpackInventorySize()) { var stack = wrapper.getStackInSlot(i) + if (stack.isEmpty) + continue - for (j in 9 until playerInventory.slots) { - if (transferMatched && playerInventory.getStackInSlot(j).isEmpty) - continue + if (transferMatched && !handlerContains(playerInventory, stack, 0)) + continue + val firstSlot = if (transferMatched) 0 else 9 + for (j in firstSlot until playerInventory.slots) { stack = playerInventory.insertItem(j, stack, false) + if (stack.isEmpty) + break } wrapper.backpackItemStackHandler.setStackInSlot(i, stack) } } + private fun backpackContainsOrMemory(wrapper: BackpackWrapper, stack: ItemStack): Boolean = + handlerContains(wrapper.backpackItemStackHandler, stack, 0) || + wrapper.backpackItemStackHandler.memorizedSlotStack.any { matchesStackKey(it, stack) } + + private fun handlerContains(handler: IItemHandler, stack: ItemStack, firstSlot: Int): Boolean { + for (slot in firstSlot until handler.slots) { + if (matchesStackKey(handler.getStackInSlot(slot), stack)) { + return true + } + } + return false + } + + private fun matchesStackKey(first: ItemStack, second: ItemStack): Boolean = + !first.isEmpty && !second.isEmpty && + ItemStack.areItemsEqual(first, second) && + ItemStack.areItemStackTagsEqual(first, second) + fun attemptDepositOnTileEntity(wrapper: BackpackWrapper, destination: TileEntity, facing: EnumFacing): Boolean { + if (Config.isInteractionBlockDisallowed(destination.blockType)) { + return false + } val destination = getHandler(destination, facing) ?: return false return attemptDepositOnItemHandler(wrapper, destination) } @@ -204,6 +234,9 @@ object BackpackInventoryHelper { } fun attemptRestockFromTileEntity(wrapper: BackpackWrapper, source: TileEntity, facing: EnumFacing): Boolean { + if (Config.isInteractionBlockDisallowed(source.blockType)) { + return false + } val source = getHandler(source, facing) ?: return false return attemptRestockFromItemHandler(wrapper, source) } @@ -262,4 +295,4 @@ object BackpackInventoryHelper { return true } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt index 5c8cdc0..4ac07f0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/block/BackpackBlock.kt @@ -181,6 +181,9 @@ class BackpackBlock( val tileEntity = worldIn.getTileEntity(pos) as? BackpackTileEntity ?: return tileEntity.wrapper.deserializeNBT(backpackInventory.serializeNBT()) + if (stack.hasDisplayName()) + tileEntity.wrapper.customName = stack.displayName + val (leftTank, rightTank) = tileEntity.wrapper.tankRenderSides() worldIn.setBlockState( pos, @@ -258,10 +261,17 @@ class BackpackBlock( val tileEntityBackpackInventory = tileEntity.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return val stackBackpackInventory = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return stackBackpackInventory.deserializeNBT(tileEntityBackpackInventory.serializeNBT()) + if (tileEntity.hasCustomName()) + stack.setStackDisplayName(tileEntity.name) drops.add(stack) } + override fun breakBlock(worldIn: World, pos: BlockPos, state: IBlockState) { + worldIn.updateComparatorOutputLevel(pos, state.block) + super.breakBlock(worldIn, pos, state) + } + override fun removedByPlayer( state: IBlockState, world: World, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidItemHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidItemHandler.kt new file mode 100644 index 0000000..9cd734c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackFluidItemHandler.kt @@ -0,0 +1,27 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability + +import net.minecraft.item.ItemStack +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.capability.IFluidHandlerItem +import net.minecraftforge.fluids.capability.IFluidTankProperties + +class BackpackFluidItemHandler( + private val container: ItemStack, + wrapper: BackpackWrapper +) : IFluidHandlerItem { + private val delegate = BackpackFluidHandler(wrapper) + + override fun getContainer(): ItemStack = container + + override fun getTankProperties(): Array = + delegate.tankProperties + + override fun fill(resource: FluidStack?, doFill: Boolean): Int = + delegate.fill(resource, doFill) + + override fun drain(resource: FluidStack?, doDrain: Boolean): FluidStack? = + delegate.drain(resource, doDrain) + + override fun drain(maxDrain: Int, doDrain: Boolean): FluidStack? = + delegate.drain(maxDrain, doDrain) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt index 201bf99..4fe37d0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt @@ -8,6 +8,9 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedCo import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedVoidUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CompactingUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.CapturedMob +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.BackpackItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.inventory.UpgradeItemStackHandler @@ -32,6 +35,7 @@ import net.minecraft.util.SoundCategory import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos import net.minecraft.util.text.ITextComponent +import net.minecraft.util.text.TextComponentString import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World import net.minecraftforge.common.capabilities.Capability @@ -47,6 +51,7 @@ class BackpackWrapper( var backpackInventorySize: () -> Int = { 27 }, var upgradeSlotsSize: () -> Int = { 1 }, var uuid: UUID = UUID.randomUUID(), + private val containerStack: ItemStack = ItemStack.EMPTY, ) : IItemHandler, ISidelessCapabilityProvider, INBTSerializable { companion object { private const val BACKPACK_INVENTORY_TAG = "BackpackInventory" @@ -56,7 +61,8 @@ class BackpackWrapper( private const val MAIN_COLOR_TAG = "MainColor" private const val ACCENT_COLOR_TAG = "AccentColor" - + private const val CUSTOM_NAME_TAG = "CustomName" + private const val MEMORY_STACK_ITEMS_TAG = "MemoryItems" private const val MEMORY_STACK_RESPECT_NBT_TAG = "MemoryRespectNBT" private const val SORT_TYPE_TAG = "SortType" @@ -66,13 +72,13 @@ class BackpackWrapper( private const val MAIN_SETTINGS_SHIFT_CLICK_INTO_OPEN_TAB_TAG = "ShiftClickIntoOpenTab" private const val MAIN_SETTINGS_KEEP_TAB_OPEN_TAG = "KeepTabOpen" private const val MAIN_SETTINGS_KEEP_SEARCH_PHRASE_TAG = "KeepSearchPhrase" + private const val MAIN_SETTINGS_SEARCH_PHRASE_TAG = "SearchPhrase" private const val MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG = "AnotherPlayerCanOpen" private const val ITEM_DISPLAY_SETTINGS_TAG = "ItemDisplay" private const val ITEM_DISPLAY_SLOTS_TAG = "Slots" private const val ITEM_DISPLAY_ROTATIONS_TAG = "Rotations" private const val ITEM_DISPLAY_COLOR_TAG = "Color" private const val ITEM_DISPLAY_SIDE_TAG = "DisplaySide" - private const val UUID_TAG = "UUID" const val DEFAULT_MAIN_COLOR: Int = -0x339ec6 @@ -81,23 +87,28 @@ class BackpackWrapper( var isCached: Boolean = false var backpackItemStackHandler = BackpackItemStackHandler(backpackInventorySize(), this) - var upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize()) + var upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize(), this) var sortType: SortType = SortType.BY_NAME var mainColor = DEFAULT_MAIN_COLOR var accentColor = DEFAULT_ACCENT_COLOR + var customName: String? = null var isGuiInteractionInProgress = false var settingsContext: SettingsContext = SettingsContext.PLAYER var shiftClickIntoOpenTab = false var keepTabOpen = true var keepSearchPhrase = false - var anotherPlayerCanOpen = false + var searchPhrase = "" + var anotherPlayerCanOpen = Config.allowOpeningOtherPlayerBackpacks var itemDisplayColor: EnumDyeColor = EnumDyeColor.RED var itemDisplaySide: DisplaySide = DisplaySide.FRONT private val itemDisplaySlots = linkedSetOf() private val itemDisplayRotations = mutableMapOf() private val slotsToCompact = mutableSetOf() private val slotsToVoid = mutableSetOf() + val capturedMobs: MutableList = mutableListOf() + var capturedMobsColumns = 0 + private var updatingCapturedMobLayout = false enum class SettingsContext { PLAYER, @@ -130,6 +141,12 @@ class BackpackWrapper( return stackUpgradeItems.fold(base) { acc, item -> func(acc, item.multiplier()) } } + fun getTotalStackMultiplier(stack: ItemStack): Int = + if (Config.canStackWithStackUpgrade(stack)) getTotalStackMultiplier() else 1 + + fun getStackLimit(stack: ItemStack): Int = + stack.maxStackSize * getTotalStackMultiplier(stack) + fun canAddStackUpgrade(newMultiplier: Int): Boolean { // Ensures no overflow for vanilla itemstack, no guarantee for modded itemstack val currentMultiplier = getTotalStackMultiplier() * 64 @@ -150,7 +167,7 @@ class BackpackWrapper( val newStackMultiplier = getTotalStackMultiplier() / oldMultiplier * newMultiplier for (stack in backpackItemStackHandler.inventory) { - if (stack.isEmpty) + if (stack.isEmpty || !Config.canStackWithStackUpgrade(stack)) continue if (stack.count > stack.maxStackSize * newStackMultiplier) @@ -175,7 +192,7 @@ class BackpackWrapper( val byAddMultiplier = getTotalStackMultiplier(false) for (stack in backpackItemStackHandler.inventory) { - if (stack.isEmpty) + if (stack.isEmpty || !Config.canStackWithStackUpgrade(stack)) continue if (stack.count > stack.maxStackSize * byAddMultiplier) @@ -224,6 +241,23 @@ class BackpackWrapper( else filterUpgrades.any { it.canInsert(stack) } } + fun ensureCapturedMobLayoutCurrent() { + if (updatingCapturedMobLayout) + return + + updatingCapturedMobLayout = true + try { + MobCatcherStorage.ensureLayoutCurrent(this) + } finally { + updatingCapturedMobLayout = false + } + } + + fun isSlotBlockedByMobCatcher(slotIndex: Int): Boolean { + ensureCapturedMobLayoutCurrent() + return MobCatcherStorage.isSlotBlocked(this, slotIndex) + } + fun onBeforeInsert(stack: ItemStack): ItemStack = if (shouldVoid(stack, false, false)) ItemStack.EMPTY else stack @@ -444,9 +478,12 @@ class BackpackWrapper( private fun insertIntoSimulation(simulation: ExposedItemStackHandler, stack: ItemStack): ItemStack { var remaining = stack for (slot in 0 until simulation.slots) { + if (isSlotBlockedByMobCatcher(slot)) { + continue + } val existing = simulation.getStackInSlot(slot) if (existing.isEmpty) { - val moved = minOf(remaining.count, remaining.maxStackSize * getTotalStackMultiplier()) + val moved = minOf(remaining.count, getStackLimit(remaining)) simulation.setStackInSlot(slot, ItemHandlerHelper.copyStackWithSize(remaining, moved)) remaining = ItemHandlerHelper.copyStackWithSize(remaining, remaining.count - moved) if (remaining.isEmpty) { @@ -457,7 +494,7 @@ class BackpackWrapper( if (!ItemHandlerHelper.canItemStacksStack(existing, remaining)) { continue } - val moved = minOf(remaining.count, existing.maxStackSize * getTotalStackMultiplier() - existing.count) + val moved = minOf(remaining.count, getStackLimit(existing) - existing.count) if (moved > 0) { existing.grow(moved) remaining = ItemHandlerHelper.copyStackWithSize(remaining, remaining.count - moved) @@ -587,17 +624,24 @@ class BackpackWrapper( fun toggleKeepSearchPhrase() { keepSearchPhrase = !keepSearchPhrase + if (!keepSearchPhrase) { + searchPhrase = "" + } } fun toggleAnotherPlayerCanOpen() { + if (!Config.allowOpeningOtherPlayerBackpacks) { + anotherPlayerCanOpen = false + return + } anotherPlayerCanOpen = !anotherPlayerCanOpen } fun isItemDisplaySlotSelected(slotIndex: Int): Boolean = - slotIndex in itemDisplaySlots + !Config.itemDisplayDisabled && slotIndex in itemDisplaySlots fun selectItemDisplaySlot(slotIndex: Int) { - if (slotIndex !in 0 until backpackInventorySize() || slotIndex in itemDisplaySlots) { + if (Config.itemDisplayDisabled || slotIndex !in 0 until backpackInventorySize() || slotIndex in itemDisplaySlots) { return } if (itemDisplaySlots.size + 1 > 1) { @@ -612,22 +656,25 @@ class BackpackWrapper( } fun getFirstItemDisplaySlot(): Int = - itemDisplaySlots.firstOrNull() ?: -1 + if (Config.itemDisplayDisabled) -1 else itemDisplaySlots.firstOrNull() ?: -1 fun getItemDisplaySlots(): Set = - itemDisplaySlots + if (Config.itemDisplayDisabled) emptySet() else itemDisplaySlots fun getItemDisplayRotation(slotIndex: Int): Int = itemDisplayRotations[slotIndex] ?: 0 fun rotateItemDisplaySlot(slotIndex: Int, clockwise: Boolean) { - if (slotIndex !in itemDisplaySlots) { + if (Config.itemDisplayDisabled || slotIndex !in itemDisplaySlots) { return } itemDisplayRotations[slotIndex] = (getItemDisplayRotation(slotIndex) + if (clockwise) 45 else -45 + 360) % 360 } fun getDisplayItem(): DisplayItem? { + if (Config.itemDisplayDisabled) { + return null + } val slotIndex = getFirstItemDisplaySlot() if (slotIndex !in 0 until backpackInventorySize()) { return null @@ -642,12 +689,15 @@ class BackpackWrapper( // This is only meant to used for bogosorter as RSB already implemented a sorting mechanism fun getSortableSlotIndexes(): List = - (0.. gatherCapabilityUpgrades(capability: Capability): List = upgradeItemStackHandler.inventory @@ -672,6 +722,12 @@ class BackpackWrapper( fun canAddBatteryUpgrade(): Boolean = !hasBatteryUpgrade() + fun hasMobCatcherUpgrade(): Boolean = + upgradeItemStackHandler.inventory.any { it.getCapability(Capabilities.MOB_CATCHER_UPGRADE_CAPABILITY, null) != null } + + fun canAddMobCatcherUpgrade(): Boolean = + !hasMobCatcherUpgrade() + fun canFitBatteryEnergyWithMultiplier(stackMultiplier: Int): Boolean = gatherCapabilityUpgrades(Capabilities.IBATTERY_UPGRADE_CAPABILITY) .all { it.energyStored <= it.getMaxEnergyStored(this, stackMultiplier) } @@ -692,18 +748,20 @@ class BackpackWrapper( backpackItemStackHandler.getStackInSlot(index) override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack = - backpackItemStackHandler.insertItem(slot, stack, simulate) + if (isSlotBlockedByMobCatcher(slot)) stack else backpackItemStackHandler.insertItem(slot, stack, simulate) override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack = - backpackItemStackHandler.extractItem(slot, amount, simulate) + if (isSlotBlockedByMobCatcher(slot)) ItemStack.EMPTY else backpackItemStackHandler.extractItem(slot, amount, simulate) override fun getSlotLimit(slot: Int): Int = - backpackItemStackHandler.getSlotLimit(slot) + if (isSlotBlockedByMobCatcher(slot)) 0 else backpackItemStackHandler.getSlotLimit(slot) override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.BACKPACK_CAPABILITY || capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || - capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && hasTankUpgrade() || + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && Config.itemFluidHandlerEnabled && hasTankUpgrade() || + capability == CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY && + Config.itemFluidHandlerEnabled && hasTankUpgrade() && !containerStack.isEmpty || capability == CapabilityEnergy.ENERGY && hasBatteryUpgrade() @Suppress("UNCHECKED_CAST") @@ -712,7 +770,10 @@ class BackpackWrapper( capability == Capabilities.BACKPACK_CAPABILITY -> this as T capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY -> this as T capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && - hasTankUpgrade() -> BackpackFluidHandler(this) as T + Config.itemFluidHandlerEnabled && hasTankUpgrade() -> BackpackFluidHandler(this) as T + capability == CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY && + Config.itemFluidHandlerEnabled && hasTankUpgrade() && !containerStack.isEmpty -> + BackpackFluidItemHandler(containerStack, this) as T capability == CapabilityEnergy.ENERGY && hasBatteryUpgrade() -> BackpackEnergyStorage(this) as T else -> null } @@ -727,10 +788,12 @@ class BackpackWrapper( nbt.setTag(UPGRADE_SLOTS_TAG, upgradesNbt) nbt.setInteger(BACKPACK_INVENTORY_SIZE_TAG, backpackInventorySize()) nbt.setInteger(UPGRADE_SLOTS_SIZE_TAG, upgradeSlotsSize()) - + nbt.setInteger(MAIN_COLOR_TAG, mainColor) nbt.setInteger(ACCENT_COLOR_TAG, accentColor) + customName?.let { nbt.setString(CUSTOM_NAME_TAG, it) } + // Settings val memoryNbt = NBTTagCompound() BackpackItemStackHelper.saveAllSlotsExtended(memoryNbt, backpackItemStackHandler.memorizedSlotStack) @@ -751,6 +814,9 @@ class BackpackWrapper( mainSettingsNbt.setBoolean(MAIN_SETTINGS_SHIFT_CLICK_INTO_OPEN_TAB_TAG, shiftClickIntoOpenTab) mainSettingsNbt.setBoolean(MAIN_SETTINGS_KEEP_TAB_OPEN_TAG, keepTabOpen) mainSettingsNbt.setBoolean(MAIN_SETTINGS_KEEP_SEARCH_PHRASE_TAG, keepSearchPhrase) + if (keepSearchPhrase && searchPhrase.isNotEmpty()) { + mainSettingsNbt.setString(MAIN_SETTINGS_SEARCH_PHRASE_TAG, searchPhrase) + } mainSettingsNbt.setBoolean(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG, anotherPlayerCanOpen) nbt.setTag(MAIN_SETTINGS_TAG, mainSettingsNbt) @@ -762,6 +828,9 @@ class BackpackWrapper( itemDisplayNbt.setByte(ITEM_DISPLAY_COLOR_TAG, itemDisplayColor.ordinal.toByte()) itemDisplayNbt.setString(ITEM_DISPLAY_SIDE_TAG, itemDisplaySide.serializedName) nbt.setTag(ITEM_DISPLAY_SETTINGS_TAG, itemDisplayNbt) + ensureCapturedMobLayoutCurrent() + nbt.setTag(MobCatcherStorage.CAPTURED_MOBS_TAG, MobCatcherStorage.serialize(capturedMobs)) + nbt.setInteger(MobCatcherStorage.CAPTURED_MOBS_COLUMNS_TAG, capturedMobsColumns) nbt.setUniqueId(UUID_TAG, uuid) return nbt @@ -776,11 +845,14 @@ class BackpackWrapper( uuid = nbt.getUniqueId(UUID_TAG)!! backpackItemStackHandler = BackpackItemStackHandler(backpackInventorySize(), this) - upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize()) - + upgradeItemStackHandler = UpgradeItemStackHandler(upgradeSlotsSize(), this) + mainColor = nbt.getInteger(MAIN_COLOR_TAG) accentColor = nbt.getInteger(ACCENT_COLOR_TAG) + if (nbt.hasKey(CUSTOM_NAME_TAG)) + customName = nbt.getString(CUSTOM_NAME_TAG) + if (nbt.hasKey(BACKPACK_INVENTORY_TAG)) BackpackItemStackHelper.loadAllItemsExtended( nbt.getCompoundTag(BACKPACK_INVENTORY_TAG), @@ -817,7 +889,13 @@ class BackpackWrapper( mainSettingsNbt.getBoolean(MAIN_SETTINGS_KEEP_TAB_OPEN_TAG) else true keepSearchPhrase = mainSettingsNbt.getBoolean(MAIN_SETTINGS_KEEP_SEARCH_PHRASE_TAG) - anotherPlayerCanOpen = mainSettingsNbt.getBoolean(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG) + searchPhrase = + if (keepSearchPhrase && mainSettingsNbt.hasKey(MAIN_SETTINGS_SEARCH_PHRASE_TAG)) + mainSettingsNbt.getString(MAIN_SETTINGS_SEARCH_PHRASE_TAG) + else "" + anotherPlayerCanOpen = Config.allowOpeningOtherPlayerBackpacks && + (!mainSettingsNbt.hasKey(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG) || + mainSettingsNbt.getBoolean(MAIN_SETTINGS_ANOTHER_PLAYER_CAN_OPEN_TAG)) } itemDisplaySlots.clear() @@ -839,6 +917,14 @@ class BackpackWrapper( itemDisplaySide = DisplaySide.fromName(itemDisplayNbt.getString(ITEM_DISPLAY_SIDE_TAG)) } + capturedMobs.clear() + capturedMobs.addAll(MobCatcherStorage.deserialize(nbt.getTagList(MobCatcherStorage.CAPTURED_MOBS_TAG, 10))) + capturedMobsColumns = if (nbt.hasKey(MobCatcherStorage.CAPTURED_MOBS_COLUMNS_TAG)) { + nbt.getInteger(MobCatcherStorage.CAPTURED_MOBS_COLUMNS_TAG) + } else { + MobCatcherStorage.getColumns(this) + } + sortType = SortType.entries[nbt.getByte(SORT_TYPE_TAG).toInt()] } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt index 7424b65..45b696c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedDepositUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.DepositUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedDepositUpgradeWrapper : AdvancedUpgradeWrapper(), IDepositUpgrade { +class AdvancedDepositUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedDepositUpgrade.filterSlots, Config.advancedDepositUpgrade.slotsInRow), + IDepositUpgrade { override val settingsLangKey: String = "gui.advanced_deposit_settings".asTranslationKey() override fun canDeposit(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class AdvancedDepositUpgradeWrapper : AdvancedUpgradeWrapper capability == Capabilities.ADVANCED_DEPOSIT_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt index 3e88504..2353a53 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFeedingUpgradeWrapper.kt @@ -2,17 +2,20 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackDataFixer import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.FeedingUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.BackpackItemStackHelper import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey -import net.minecraft.item.ItemFood import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.items.IItemHandler -class AdvancedFeedingUpgradeWrapper : AdvancedUpgradeWrapper(), IFeedingUpgrade { +class AdvancedFeedingUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedFeedingUpgrade.filterSlots, Config.advancedFeedingUpgrade.slotsInRow), + IFeedingUpgrade { companion object { private const val HUNGER_FEEDING_STRATEGY_TAG = "HungerFeedingStrategy" private const val HURT_FEEDING_STRATEGY_TAG = "HurtFeedingStrategy" @@ -20,32 +23,26 @@ class AdvancedFeedingUpgradeWrapper : AdvancedUpgradeWrapper override val settingsLangKey: String = "gui.advanced_feeding_settings".asTranslationKey() - override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(16) { + override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(Config.advancedFeedingUpgrade.filterSlots) { override fun isItemValid(slot: Int, stack: ItemStack): Boolean = - stack.item is ItemFood + IFeedingUpgrade.isValidFood(stack) } var hungerFeedingStrategy: FeedingStrategy.Hunger = FeedingStrategy.Hunger.HALF - var healthFeedingStrategy: FeedingStrategy.HEALTH = FeedingStrategy.HEALTH.IGNORE + var healthFeedingStrategy: FeedingStrategy.Health = FeedingStrategy.Health.IGNORE override fun checkFilter(stack: ItemStack): Boolean = - stack.item is ItemFood && super.checkFilter(stack) + IFeedingUpgrade.isValidFood(stack) && super.checkFilter(stack) override fun getFoodSlot(handler: IItemHandler, foodLevel: Int, health: Float, maxHealth: Float): Int { for (slot in 0 until handler.slots) { - val stack = handler.getStackInSlot(slot) + val hunger = BackpackItemStackHelper.getHungerFromSlot(handler, slot, ::checkFilter) ?: continue - if (!checkFilter(stack)) - continue - - val item = stack.item as? ItemFood ?: continue - val healingAmount = item.getHealAmount(stack) - - if (maxHealth > health && healthFeedingStrategy == FeedingStrategy.HEALTH.ALWAYS) + if (maxHealth > health && healthFeedingStrategy == FeedingStrategy.Health.ALWAYS) return slot val flag = when (hungerFeedingStrategy) { - FeedingStrategy.Hunger.FULL -> healingAmount <= 20 - foodLevel - FeedingStrategy.Hunger.HALF -> healingAmount / 2 <= 20 - foodLevel + FeedingStrategy.Hunger.FULL -> hunger <= 20 - foodLevel + FeedingStrategy.Hunger.HALF -> hunger / 2 <= 20 - foodLevel FeedingStrategy.Hunger.ALWAYS -> foodLevel < 20 } @@ -71,7 +68,7 @@ class AdvancedFeedingUpgradeWrapper : AdvancedUpgradeWrapper override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) hungerFeedingStrategy = FeedingStrategy.Hunger.entries[nbt.getByte(HUNGER_FEEDING_STRATEGY_TAG).toInt()] - healthFeedingStrategy = FeedingStrategy.HEALTH.entries[nbt.getByte(HURT_FEEDING_STRATEGY_TAG).toInt()] + healthFeedingStrategy = FeedingStrategy.Health.entries[nbt.getByte(HURT_FEEDING_STRATEGY_TAG).toInt()] BackpackDataFixer.fixFeedingUpgrade(filterItems) } @@ -82,9 +79,9 @@ class AdvancedFeedingUpgradeWrapper : AdvancedUpgradeWrapper ALWAYS; } - enum class HEALTH { + enum class Health { ALWAYS, IGNORE; } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt index 3f9fe59..7f61aca 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.FilterUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -8,7 +9,9 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedFilterUpgradeWrapper : AdvancedUpgradeWrapper(), IFilterUpgrade { +class AdvancedFilterUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedFilterUpgrade.filterSlots, Config.advancedFilterUpgrade.slotsInRow), + IFilterUpgrade { override val settingsLangKey: String = "gui.advanced_filter_settings".asTranslationKey() override var filterWay: IFilterUpgrade.FilterWayType = IFilterUpgrade.FilterWayType.IN_OUT diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt index 20ebc0e..04db38d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedPickupUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.PickupUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedPickupUpgradeWrapper : AdvancedUpgradeWrapper(), IPickupUpgrade { +class AdvancedPickupUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedPickupUpgrade.filterSlots, Config.advancedPickupUpgrade.slotsInRow), + IPickupUpgrade { override val settingsLangKey: String = "gui.advanced_pickup_settings".asTranslationKey() override fun canPickup(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class AdvancedPickupUpgradeWrapper : AdvancedUpgradeWrapper() capability == Capabilities.ADVANCED_PICKUP_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt index a0fa35a..d2cfbd1 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedRestockUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.RestockUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class AdvancedRestockUpgradeWrapper : AdvancedUpgradeWrapper(), IRestockUpgrade { +class AdvancedRestockUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedRestockUpgrade.filterSlots, Config.advancedRestockUpgrade.slotsInRow), + IRestockUpgrade { override val settingsLangKey: String = "gui.advanced_restock_settings".asTranslationKey() override fun canRestock(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class AdvancedRestockUpgradeWrapper : AdvancedUpgradeWrapper capability == Capabilities.ADVANCED_RESTOCK_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt index 64ff348..67fdaa0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt @@ -10,7 +10,8 @@ import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.Constants -abstract class AdvancedUpgradeWrapper(filterSlots: Int = 16) : UpgradeWrapper(), IToggleable, IAdvancedFilterable where T : UpgradeItem { +abstract class AdvancedUpgradeWrapper(filterSlots: Int = 16, override val slotsInRow: Int = 4) : + UpgradeWrapper(), IToggleable, IAdvancedFilterable where T : UpgradeItem { override var enabled = true override var filterType = IBasicFilterable.FilterType.WHITELIST override val filterItems: ExposedItemStackHandler = ExposedItemStackHandler(filterSlots) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt index 1bbd550..d70882c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt @@ -7,7 +7,8 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -abstract class BasicUpgradeWrapper(filterSlots: Int = 9) : UpgradeWrapper(), IToggleable, IBasicFilterable where T : UpgradeItem { +abstract class BasicUpgradeWrapper(filterSlots: Int = 9, override val slotsInRow: Int = 3) : + UpgradeWrapper(), IToggleable, IBasicFilterable where T : UpgradeItem { override var enabled = true override var filterType = IBasicFilterable.FilterType.WHITELIST override val filterItems = ExposedItemStackHandler(filterSlots) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt index 924f2cd..b273dc2 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.BatteryUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -19,8 +20,6 @@ class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgr private const val INVENTORY_TAG = "Inventory" private const val INPUT_SLOT = 0 private const val OUTPUT_SLOT = 1 - private const val ENERGY_PER_ROW = 10000 - private const val MAX_INPUT_OUTPUT_PER_ROW = 20 } override val settingsLangKey = "gui.battery_settings".asTranslationKey() @@ -41,10 +40,10 @@ class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgr } override fun getMaxEnergyStored(wrapper: BackpackWrapper): Int = - getMaxEnergyStored(wrapper, maxOf(1, wrapper.getTotalStackMultiplier())) + getMaxEnergyStored(wrapper, wrapper.getTotalStackMultiplier()) override fun getMaxEnergyStored(wrapper: BackpackWrapper, stackMultiplier: Int): Int = - getSlotRows(wrapper) * ENERGY_PER_ROW * maxOf(1, stackMultiplier) + (getSlotRows(wrapper) * Config.batteryUpgrade.energyPerSlotRow * getAdjustedStackMultiplier(stackMultiplier)).toInt() override fun receiveEnergy(wrapper: BackpackWrapper, maxReceive: Int, simulate: Boolean): Int { val accepted = minOf(maxReceive, getMaxInOut(wrapper), getMaxEnergyStored(wrapper) - energyStored) @@ -109,11 +108,14 @@ class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgr } private fun getMaxInOut(wrapper: BackpackWrapper): Int = - maxOf(1, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * maxOf(1, wrapper.getTotalStackMultiplier())) + maxOf(1, (getSlotRows(wrapper) * Config.batteryUpgrade.maxInputOutput * getAdjustedStackMultiplier(wrapper.getTotalStackMultiplier())).toInt()) private fun getSlotRows(wrapper: BackpackWrapper): Int = maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) + private fun getAdjustedStackMultiplier(stackMultiplier: Int): Double = + 1.0 + Config.batteryUpgrade.stackMultiplierRatio * (stackMultiplier - 1) + override fun serializeNBT(): NBTTagCompound { val nbt = super.serializeNBT() nbt.setInteger(ENERGY_TAG, energyStored) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt index b5eb365..562e338 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.CompactingUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -11,7 +12,9 @@ import net.minecraft.util.EnumFacing import net.minecraft.world.World import net.minecraftforge.common.capabilities.Capability -open class CompactingUpgradeWrapper : BasicUpgradeWrapper(), ICompactingUpgrade { +open class CompactingUpgradeWrapper : + BasicUpgradeWrapper(Config.compactingUpgrade.filterSlots, Config.compactingUpgrade.slotsInRow), + ICompactingUpgrade { companion object { private const val COMPACT_NON_UNCRAFTABLE_TAG = "CompactNonUncraftable" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" @@ -54,7 +57,9 @@ open class CompactingUpgradeWrapper : BasicUpgradeWrapper super.hasCapability(capability, facing) } -class AdvancedCompactingUpgradeWrapper : AdvancedUpgradeWrapper(), ICompactingUpgrade { +class AdvancedCompactingUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedCompactingUpgrade.filterSlots, Config.advancedCompactingUpgrade.slotsInRow), + ICompactingUpgrade { companion object { private const val COMPACT_NON_UNCRAFTABLE_TAG = "CompactNonUncraftable" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt index c793039..042b349 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DepositUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.DepositUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class DepositUpgradeWrapper : BasicUpgradeWrapper(), IDepositUpgrade { +class DepositUpgradeWrapper : + BasicUpgradeWrapper(Config.depositUpgrade.filterSlots, Config.depositUpgrade.slotsInRow), + IDepositUpgrade { override val settingsLangKey: String = "gui.deposit_settings".asTranslationKey() override fun canDeposit(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class DepositUpgradeWrapper : BasicUpgradeWrapper(), IDeposi capability == Capabilities.DEPOSIT_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt index 264e543..1b921cc 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FeedingUpgradeWrapper.kt @@ -2,38 +2,35 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackDataFixer import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.FeedingUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.BackpackItemStackHelper import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey -import net.minecraft.item.ItemFood import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.items.IItemHandler -class FeedingUpgradeWrapper : BasicUpgradeWrapper(), IFeedingUpgrade { +class FeedingUpgradeWrapper : + BasicUpgradeWrapper(Config.feedingUpgrade.filterSlots, Config.feedingUpgrade.slotsInRow), + IFeedingUpgrade { override val settingsLangKey: String = "gui.feeding_settings".asTranslationKey() - override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(9) { + override val filterItems: ExposedItemStackHandler = object : ExposedItemStackHandler(Config.feedingUpgrade.filterSlots) { override fun isItemValid(slot: Int, stack: ItemStack): Boolean = - stack.item is ItemFood + IFeedingUpgrade.isValidFood(stack) } override fun checkFilter(stack: ItemStack): Boolean = - stack.item is ItemFood && super.checkFilter(stack) + IFeedingUpgrade.isValidFood(stack) && super.checkFilter(stack) override fun getFoodSlot(handler: IItemHandler, foodLevel: Int, health: Float, maxHealth: Float): Int { for (slot in 0 until handler.slots) { - val stack = handler.getStackInSlot(slot) + val hunger = BackpackItemStackHelper.getHungerFromSlot(handler, slot, ::checkFilter) ?: continue - if (!checkFilter(stack)) - continue - - val item = stack.item as? ItemFood ?: continue - val healingAmount = item.getHealAmount(stack) - - if (healingAmount <= 20 - foodLevel) + if (hunger <= 20 - foodLevel) return slot } @@ -50,4 +47,4 @@ class FeedingUpgradeWrapper : BasicUpgradeWrapper(), IFeedin BackpackDataFixer.fixFeedingUpgrade(filterItems) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt index a921ef4..fa653a8 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.FilterUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -8,7 +9,9 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class FilterUpgradeWrapper : BasicUpgradeWrapper(), IFilterUpgrade { +class FilterUpgradeWrapper : + BasicUpgradeWrapper(Config.filterUpgrade.filterSlots, Config.filterUpgrade.slotsInRow), + IFilterUpgrade { override val settingsLangKey: String = "gui.filter_settings".asTranslationKey() override var filterWay: IFilterUpgrade.FilterWayType = IFilterUpgrade.FilterWayType.IN_OUT @@ -41,4 +44,4 @@ class FilterUpgradeWrapper : BasicUpgradeWrapper(), IFilterUp super.deserializeNBT(nbt) filterWay = IFilterUpgrade.FilterWayType.entries[nbt.getByte(IFilterUpgrade.FILTER_WAY_TAG).toInt()] } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt index 56a2206..fbc30da 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt @@ -106,6 +106,8 @@ interface IAdvancedFilterable : IBasicFilterable { object Impl : IAdvancedFilterable { override val filterItems: ExposedItemStackHandler get() = ExposedItemStackHandler(0) + override val slotsInRow: Int + get() = 1 override var filterType: IBasicFilterable.FilterType get() = IBasicFilterable.Impl.filterType set(_) {} @@ -126,4 +128,4 @@ interface IAdvancedFilterable : IBasicFilterable { get() = false set(_) {} } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt index 0bb0003..7fd472d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IBasicFilterable.kt @@ -14,6 +14,7 @@ interface IBasicFilterable : ISidelessCapabilityProvider { } val filterItems: ExposedItemStackHandler + val slotsInRow: Int var filterType: FilterType fun checkFilter(stack: ItemStack): Boolean = when (filterType) { @@ -32,6 +33,8 @@ interface IBasicFilterable : ISidelessCapabilityProvider { object Impl : IBasicFilterable { override val filterItems: ExposedItemStackHandler get() = ExposedItemStackHandler(0) + override val slotsInRow: Int + get() = 1 override var filterType: FilterType get() = FilterType.WHITELIST set(_) {} @@ -39,4 +42,4 @@ interface IBasicFilterable : ISidelessCapabilityProvider { override fun checkFilter(itemStack: ItemStack): Boolean = false } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IFeedingUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IFeedingUpgrade.kt index 93a266b..c803f0c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IFeedingUpgrade.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IFeedingUpgrade.kt @@ -1,16 +1,26 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade +import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemFood +import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.items.IItemHandler +import squeek.applecore.api.AppleCoreAPI sealed interface IFeedingUpgrade : ISidelessCapabilityProvider, INBTSerializable { + companion object { + fun isValidFood(stack: ItemStack): Boolean = + if (RetroSophisticatedBackpacks.appleCoreLoaded) AppleCoreAPI.accessor.isFood(stack) + else stack.item is ItemFood + } + /** * Returns the first available food that matches the upgrade's criteria * diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt index 713e0e3..20c239d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.JukeboxUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -240,7 +241,7 @@ open class JukeboxUpgradeWrapper(private val slots: Int = 1) : UpgradeWrapper.hasCapability(capability, facing) } -class AdvancedJukeboxUpgradeWrapper : JukeboxUpgradeWrapper(12) { +class AdvancedJukeboxUpgradeWrapper : JukeboxUpgradeWrapper(Config.advancedJukeboxUpgrade.numberOfSlots) { override val settingsLangKey = "gui.advanced_jukebox_settings".asTranslationKey() override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt index 1cee70d..4dd3b34 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/MagnetUpgradeWrapper.kt @@ -2,14 +2,19 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.MagnetUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -open class MagnetUpgradeWrapper(filterSlots: Int = 9, override val range: Double = 3.0) : - BasicUpgradeWrapper(filterSlots), IMagnetUpgrade { +open class MagnetUpgradeWrapper( + filterSlots: Int = Config.magnetUpgrade.filterSlots, + slotsInRow: Int = Config.magnetUpgrade.slotsInRow, + override val range: Double = Config.magnetUpgrade.magnetRange.toDouble() +) : + BasicUpgradeWrapper(filterSlots, slotsInRow), IMagnetUpgrade { override val settingsLangKey = "gui.magnet_settings".asTranslationKey() init { @@ -25,9 +30,11 @@ open class MagnetUpgradeWrapper(filterSlots: Int = 9, override val range: Double super.hasCapability(capability, facing) } -class AdvancedMagnetUpgradeWrapper : AdvancedUpgradeWrapper(), IMagnetUpgrade { +class AdvancedMagnetUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedMagnetUpgrade.filterSlots, Config.advancedMagnetUpgrade.slotsInRow), + IMagnetUpgrade { override val settingsLangKey = "gui.advanced_magnet_settings".asTranslationKey() - override val range = 5.0 + override val range = Config.advancedMagnetUpgrade.magnetRange.toDouble() init { filterType = IBasicFilterable.FilterType.BLACKLIST diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt index e1950e6..63be82a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PickupUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.PickupUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class PickupUpgradeWrapper : BasicUpgradeWrapper(), IPickupUpgrade { +class PickupUpgradeWrapper : + BasicUpgradeWrapper(Config.pickupUpgrade.filterSlots, Config.pickupUpgrade.slotsInRow), + IPickupUpgrade { override val settingsLangKey: String = "gui.pickup_settings".asTranslationKey() override fun canPickup(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class PickupUpgradeWrapper : BasicUpgradeWrapper(), IPickupUp capability == Capabilities.PICKUP_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt index afaa507..b0695ab 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt @@ -3,8 +3,11 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackFluidHandler import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import com.cleanroommc.retrosophisticatedbackpacks.item.PumpUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.block.BlockLiquid import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound @@ -42,7 +45,6 @@ open class PumpUpgradeWrapper( private const val FLUID_HANDLER_COOLDOWN = 20L private const val PLAYER_SEARCH_RANGE = 3.0 private const val WORLD_RANGE = 4 - private const val MAX_INPUT_OUTPUT_PER_ROW = 20 } override val settingsLangKey = "gui.pump_settings".asTranslationKey() @@ -114,6 +116,9 @@ open class PumpUpgradeWrapper( if (stack.isEmpty || stack.count != 1) { return false } + if (stack.item is BackpackItem) { + return false + } val itemHandler = FluidUtil.getFluidHandler(stack.copy()) ?: return false val moved = if (isInput) fillFromFluidHandler(itemHandler, storage, Fluid.BUCKET_VOLUME) else fillFluidHandler(itemHandler, storage, Fluid.BUCKET_VOLUME) @@ -186,7 +191,7 @@ open class PumpUpgradeWrapper( private fun isValidForFluidPlacement(world: World, pos: BlockPos): Boolean { val state = world.getBlockState(pos) - return world.isAirBlock(pos) || !state.material.isSolid || state.block.isReplaceable(world, pos) + return world.isAirBlock(pos) || state.material.isLiquid && state.getValue(BlockLiquid.LEVEL) != 0 } private fun fillFromFluidHandler(source: IFluidHandler, storage: IFluidHandler, maxDrain: Int): Boolean { @@ -212,11 +217,14 @@ open class PumpUpgradeWrapper( } private fun getMaxInOut(wrapper: BackpackWrapper): Int = - maxOf(Fluid.BUCKET_VOLUME, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * maxOf(1, wrapper.getTotalStackMultiplier())) + maxOf(Fluid.BUCKET_VOLUME, (getSlotRows(wrapper) * Config.pumpUpgrade.maxInputOutput * getAdjustedStackMultiplier(wrapper)).toInt()) private fun getSlotRows(wrapper: BackpackWrapper): Int = maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) + private fun getAdjustedStackMultiplier(wrapper: BackpackWrapper): Double = + 1.0 + Config.pumpUpgrade.stackMultiplierRatio * (wrapper.getTotalStackMultiplier() - 1) + private fun distanceSq(first: BlockPos, second: BlockPos): Int { val dx = first.x - second.x val dy = first.y - second.y @@ -263,7 +271,7 @@ open class PumpUpgradeWrapper( } class AdvancedPumpUpgradeWrapper : PumpUpgradeWrapper( - filterSlots = 4, + filterSlots = Config.pumpUpgrade.filterSlots, interactWithHandDefault = true, interactWithWorldDefault = false, interactWithFluidHandlersDefault = true diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt index 20b25f3..0922cb6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.RefillUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.entity.player.EntityPlayer @@ -14,8 +15,11 @@ import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.Constants import net.minecraftforge.items.ItemHandlerHelper -open class RefillUpgradeWrapper(filterSlots: Int = 6) : - BasicUpgradeWrapper(filterSlots), IRefillUpgrade { +open class RefillUpgradeWrapper( + filterSlots: Int = Config.refillUpgrade.filterSlots, + slotsInRow: Int = Config.refillUpgrade.slotsInRow +) : + BasicUpgradeWrapper(filterSlots, slotsInRow), IRefillUpgrade { override val settingsLangKey = "gui.refill_settings".asTranslationKey() init { @@ -156,7 +160,8 @@ open class RefillUpgradeWrapper(filterSlots: Int = 6) : } } -class AdvancedRefillUpgradeWrapper : RefillUpgradeWrapper(12) { +class AdvancedRefillUpgradeWrapper : + RefillUpgradeWrapper(Config.advancedRefillUpgrade.filterSlots, Config.advancedRefillUpgrade.slotsInRow) { companion object { private const val TARGET_SLOTS_TAG = "TargetSlots" private const val SLOT_TAG = "Slot" diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt index 44884c2..029c052 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RestockUpgradeWrapper.kt @@ -1,13 +1,16 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.RestockUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class RestockUpgradeWrapper : BasicUpgradeWrapper(), IRestockUpgrade { +class RestockUpgradeWrapper : + BasicUpgradeWrapper(Config.restockUpgrade.filterSlots, Config.restockUpgrade.slotsInRow), + IRestockUpgrade { override val settingsLangKey: String = "gui.restock_settings".asTranslationKey() override fun canRestock(stack: ItemStack): Boolean = @@ -17,4 +20,4 @@ class RestockUpgradeWrapper : BasicUpgradeWrapper(), IRestoc capability == Capabilities.RESTOCK_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt index 4600a6d..a867129 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHandler import com.cleanroommc.retrosophisticatedbackpacks.item.TankUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -27,12 +28,10 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { private const val INPUT_RESULT_SLOT = 2 private const val OUTPUT_RESULT_SLOT = 3 private const val BUCKET = 1000 - private const val CAPACITY_PER_ROW = 4000 - private const val MAX_INPUT_OUTPUT_PER_ROW = 20 } override val settingsLangKey = "gui.tank_settings".asTranslationKey() - override val tankCapacity = CAPACITY_PER_ROW * 3 + override val tankCapacity = Config.tankUpgrade.capacityPerSlotRow * 3 private var fluid: FluidStack? = null private val inventory = object : ExposedItemStackHandler(4) { override fun isItemValid(slot: Int, stack: ItemStack): Boolean = @@ -47,16 +46,16 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { fluid?.copy() override fun getTankCapacity(wrapper: BackpackWrapper): Int = - maxOf(BUCKET, getSlotRows(wrapper) * CAPACITY_PER_ROW * getStackMultiplier(wrapper)) + maxOf(BUCKET, (getSlotRows(wrapper) * Config.tankUpgrade.capacityPerSlotRow * getAdjustedStackMultiplier(wrapper)).toInt()) private fun getMaxInOut(wrapper: BackpackWrapper): Int = - maxOf(BUCKET, getSlotRows(wrapper) * MAX_INPUT_OUTPUT_PER_ROW * getStackMultiplier(wrapper)) + maxOf(BUCKET, (getSlotRows(wrapper) * Config.tankUpgrade.maxInputOutput * getAdjustedStackMultiplier(wrapper)).toInt()) private fun getSlotRows(wrapper: BackpackWrapper): Int = maxOf(1, (wrapper.backpackInventorySize() + 8) / 9) - private fun getStackMultiplier(wrapper: BackpackWrapper): Int = - maxOf(1, wrapper.getTotalStackMultiplier()) + private fun getAdjustedStackMultiplier(wrapper: BackpackWrapper): Double = + 1.0 + Config.tankUpgrade.stackMultiplierRatio * (wrapper.getTotalStackMultiplier() - 1) override fun fill(wrapper: BackpackWrapper, resource: FluidStack, doFill: Boolean, ignoreInOutLimit: Boolean): Int { val current = fluid @@ -98,7 +97,7 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { } override fun tick(wrapper: BackpackWrapper, world: World) { - if (world.totalWorldTime % 20L != 0L) { + if (world.totalWorldTime % Config.tankUpgrade.autoFillDrainContainerCooldown.coerceAtLeast(1).toLong() != 0L) { return } tryDrainInput(wrapper) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt index 70c47cd..8ff380e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import com.cleanroommc.retrosophisticatedbackpacks.item.ToolSwapperUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey @@ -28,7 +29,8 @@ import java.util.LinkedList open class ToolSwapperUpgradeWrapper( private val hasSettingsTab: Boolean = false, private val swapToolOnKeyPress: Boolean = false, -) : BasicUpgradeWrapper(8), IToolSwapperUpgrade { +) : BasicUpgradeWrapper(Config.toolSwapperUpgrade.filterSlots, Config.toolSwapperUpgrade.slotsInRow), + IToolSwapperUpgrade { companion object { private const val SHOULD_SWAP_WEAPON_TAG = "ShouldSwapWeapon" private const val TOOL_SWAP_MODE_TAG = "ToolSwapMode" diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt index 7b1ce1d..90a97db 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeFilterUtils.matchesAllowEmpty +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.VoidUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack @@ -9,14 +10,19 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing import net.minecraftforge.common.capabilities.Capability -class VoidUpgradeWrapper : BasicUpgradeWrapper(), IVoidUpgrade { +class VoidUpgradeWrapper : + BasicUpgradeWrapper(Config.voidUpgrade.filterSlots, Config.voidUpgrade.slotsInRow), + IVoidUpgrade { companion object { private const val VOID_TYPE_TAG = "VoidType" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" } override val settingsLangKey = "gui.void_settings".asTranslationKey() - var voidType = VoidType.ALWAYS + var voidType = normalizeVoidType(VoidType.ALWAYS) + set(value) { + field = normalizeVoidType(value) + } var shouldWorkInGui = false init { @@ -50,20 +56,28 @@ class VoidUpgradeWrapper : BasicUpgradeWrapper(), IVoidUpgrade shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } + private fun normalizeVoidType(type: VoidType): VoidType = + if (!Config.voidUpgrade.voidAlwaysEnabled && type == VoidType.ALWAYS) VoidType.SLOT_OVERFLOW else type + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.VOID_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || super.hasCapability(capability, facing) } -class AdvancedVoidUpgradeWrapper : AdvancedUpgradeWrapper(), IVoidUpgrade { +class AdvancedVoidUpgradeWrapper : + AdvancedUpgradeWrapper(Config.advancedVoidUpgrade.filterSlots, Config.advancedVoidUpgrade.slotsInRow), + IVoidUpgrade { companion object { private const val VOID_TYPE_TAG = "VoidType" private const val SHOULD_WORK_IN_GUI_TAG = "ShouldWorkInGui" } override val settingsLangKey = "gui.advanced_void_settings".asTranslationKey() - var voidType = VoidType.ALWAYS + var voidType = normalizeVoidType(VoidType.ALWAYS) + set(value) { + field = normalizeVoidType(value) + } var shouldWorkInGui = false init { @@ -97,6 +111,9 @@ class AdvancedVoidUpgradeWrapper : AdvancedUpgradeWrapper(), IV shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } + private fun normalizeVoidType(type: VoidType): VoidType = + if (!Config.advancedVoidUpgrade.voidAlwaysEnabled && type == VoidType.ALWAYS) VoidType.SLOT_OVERFLOW else type + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.ADVANCED_VOID_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) || diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt new file mode 100644 index 0000000..3c6e966 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMob.kt @@ -0,0 +1,30 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.ResourceLocation +import java.util.UUID + +data class CapturedMob( + val id: UUID, + val entityType: ResourceLocation, + val entityNbt: NBTTagCompound, + val slot: Int, + val width: Int, + val height: Int, + val slotCost: Int, + val hostile: Boolean, + val displayName: String, + val currentHealth: Int, + val maxHealth: Int +) { + fun occupiesSlot(inventorySlot: Int, columns: Int): Boolean { + if (columns <= 0 || inventorySlot < 0) { + return false + } + val originX = slot % columns + val originY = slot / columns + val slotX = inventorySlot % columns + val slotY = inventorySlot / columns + return slotX >= originX && slotX < originX + width && slotY >= originY && slotY < originY + height + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt new file mode 100644 index 0000000..a47706c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/CapturedMobFootprint.kt @@ -0,0 +1,6 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +data class CapturedMobFootprint(val width: Int, val height: Int) { + val area: Int + get() = width * height +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt new file mode 100644 index 0000000..44aa863 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherHandler.kt @@ -0,0 +1,288 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer +import com.cleanroommc.retrosophisticatedbackpacks.config.Config +import com.cleanroommc.retrosophisticatedbackpacks.handler.CapabilityHandler +import com.cleanroommc.retrosophisticatedbackpacks.handler.NetworkHandler +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem +import com.cleanroommc.retrosophisticatedbackpacks.network.S2CMobCatcherContentsPacket +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.block.Block +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityFlying +import net.minecraft.entity.EntityList +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.IEntityOwnable +import net.minecraft.entity.SharedMonsterAttributes +import net.minecraft.entity.boss.EntityDragon +import net.minecraft.entity.boss.EntityWither +import net.minecraft.entity.monster.IMob +import net.minecraft.entity.passive.EntityWaterMob +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.player.EntityPlayerMP +import net.minecraft.init.SoundEvents +import net.minecraft.inventory.IInventory +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumActionResult +import net.minecraft.util.EnumFacing +import net.minecraft.util.ResourceLocation +import net.minecraft.util.SoundCategory +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.RayTraceResult +import net.minecraft.util.math.Vec3d +import net.minecraft.util.text.TextComponentTranslation +import net.minecraft.world.World +import java.util.UUID +import kotlin.math.ceil + +object MobCatcherHandler { + private const val RELEASE_REACH = 5.0 + + fun tryCapture(player: EntityPlayer, entity: EntityLivingBase): EnumActionResult { + val stack = player.heldItemMainhand + if (stack.item !is BackpackItem) { + return EnumActionResult.PASS + } + val backpackWrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return EnumActionResult.PASS + val upgradeWrapper = getBestUpgrade(backpackWrapper) ?: return EnumActionResult.PASS + if (player.world.isRemote) { + return EnumActionResult.SUCCESS + } + + val result = capture(player as EntityPlayerMP, backpackWrapper, entity, upgradeWrapper.isAdvanced) + player.sendStatusMessage(TextComponentTranslation(result.messageKey.asTranslationKey(), *result.args), true) + return if (result.success) EnumActionResult.SUCCESS else EnumActionResult.FAIL + } + + private fun capture( + player: EntityPlayerMP, + backpackWrapper: BackpackWrapper, + entity: EntityLivingBase, + advanced: Boolean + ): CaptureResult { + getEligibilityError(player, entity, advanced)?.let { return fail(player, it) } + + val hostile = isHostile(entity) + val slotCost = getSlotCost(entity, hostile) + val maxSlotCost = if (advanced) Config.mobCatcherUpgrade.advancedMaxSlotCost else Config.mobCatcherUpgrade.basicMaxSlotCost + if (slotCost > maxSlotCost) { + return fail(player, "gui.status.mob_catcher_too_large", slotCost, maxSlotCost) + } + + val footprint = MobCatcherStorage.getFootprint(entity, slotCost) + val slot = MobCatcherStorage.findEmptyRectangle(backpackWrapper, footprint) + ?: return fail(player, "gui.status.mob_catcher_no_space", footprint.width, footprint.height) + val entityType = EntityList.getKey(entity) + ?: return fail(player, "gui.status.mob_catcher_invalid_entity") + val entityTag = NBTTagCompound() + entity.writeToNBT(entityTag) + entityTag.setString("id", entityType.toString()) + entityTag.removeTag("UUIDMost") + entityTag.removeTag("UUIDLeast") + + val capturedMob = CapturedMob( + UUID.randomUUID(), + entityType, + entityTag, + slot, + footprint.width, + footprint.height, + slotCost, + hostile, + getCapturedMobDisplayName(entity), + ceil(entity.health.toDouble()).toInt(), + ceil(getEffectiveMaxHealth(entity)).toInt() + ) + MobCatcherStorage.addCapturedMob(backpackWrapper, capturedMob) + entity.setDead() + syncBackpack(player, backpackWrapper) + playMobCatcherSound(player, true, 0.7f) + return CaptureResult(true, "gui.status.mob_catcher_captured", arrayOf(capturedMob.displayName)) + } + + private fun getEligibilityError(player: EntityPlayerMP, entity: EntityLivingBase, advanced: Boolean): String? { + if (entity is EntityPlayer) { + return "gui.status.mob_catcher_players_blocked" + } + if (entity is EntityDragon || entity is EntityWither) { + return "gui.status.mob_catcher_boss_blocked" + } + if (entity.isRiding || entity.isBeingRidden) { + return "gui.status.mob_catcher_passengers_blocked" + } + val entityType = EntityList.getKey(entity) + if (entityType == null || entityType in configuredEntityTypes(Config.mobCatcherUpgrade.entityBlockList)) { + return "gui.status.mob_catcher_blocklisted" + } + if (entity is IEntityOwnable && entity.ownerId != null && entity.ownerId != player.uniqueID) { + return "gui.status.mob_catcher_not_owner" + } + if (Config.mobCatcherUpgrade.disallowInventoryEntities && entity is IInventory) { + return "gui.status.mob_catcher_inventory_blocked" + } + if (!advanced && isHostile(entity)) { + return "gui.status.mob_catcher_hostile_needs_advanced" + } + return null + } + + fun release(player: EntityPlayerMP, capturedMobId: UUID) { + val container = player.openContainer as? BackpackContainer ?: return + val backpackWrapper = container.backpackWrapper + val capturedMob = MobCatcherStorage.getCapturedMob(backpackWrapper, capturedMobId) ?: return + val entity = createEntity(player.world, capturedMob) as? EntityLivingBase ?: run { + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_release_failed".asTranslationKey()), true) + return + } + val target = getReleasePosition(player, entity) ?: run { + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_no_release_space".asTranslationKey()), true) + playMobCatcherSound(player, false, 0.8f) + return + } + entity.setLocationAndAngles(target.x, target.y, target.z, player.rotationYaw, 0f) + entity.setUniqueId(UUID.randomUUID()) + if (!player.world.spawnEntity(entity)) { + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_release_failed".asTranslationKey()), true) + return + } + MobCatcherStorage.removeCapturedMob(backpackWrapper, capturedMobId) + syncBackpack(player, backpackWrapper) + player.sendStatusMessage(TextComponentTranslation("gui.status.mob_catcher_released".asTranslationKey(), capturedMob.displayName), true) + playMobCatcherSound(player, true, 1.2f) + } + + private fun createEntity(world: World, capturedMob: CapturedMob): Entity? { + val entity = EntityList.createEntityByIDFromName(capturedMob.entityType, world) ?: return null + entity.readFromNBT(capturedMob.entityNbt) + return entity + } + + private fun getReleasePosition(player: EntityPlayerMP, entity: EntityLivingBase): Vec3d? { + val eye = player.getPositionEyes(1f) + val look = player.lookVec + val hit = player.world.rayTraceBlocks(eye, eye.add(look.scale(RELEASE_REACH)), false, true, false) + if (hit != null && hit.typeOfHit == RayTraceResult.Type.BLOCK) { + getValidReleasePosition(player, entity, hit.blockPos.offset(hit.sideHit))?.let { return it } + getValidReleasePosition(player, entity, hit.blockPos.up())?.let { return it } + } + + var horizontal = Vec3d(look.x, 0.0, look.z) + if (horizontal.lengthSquared() < 1.0E-4) { + horizontal = Vec3d.fromPitchYaw(0f, player.rotationYaw) + } + val direction = horizontal.normalize() + val maxFallbackDistance = maxOf( + 2, + minOf(RELEASE_REACH.toInt(), ceil(entity.width / 2.0 + player.width / 2.0 + 1.0).toInt()) + ) + for (distance in 1..maxFallbackDistance) { + val candidate = player.positionVector.add(direction.scale(distance.toDouble())) + getValidReleasePosition(player, entity, BlockPos(candidate.x, player.posY, candidate.z))?.let { return it } + } + return null + } + + private fun getValidReleasePosition(player: EntityPlayerMP, entity: EntityLivingBase, spawnPos: BlockPos): Vec3d? { + val pos = getReleasePositionOnGround(player, entity, spawnPos) ?: return null + val bounds = AxisAlignedBB( + pos.x - entity.width / 2.0, + pos.y, + pos.z - entity.width / 2.0, + pos.x + entity.width / 2.0, + pos.y + entity.height, + pos.z + entity.width / 2.0 + ) + return if (player.world.getCollisionBoxes(entity, bounds).isEmpty() && + player.world.checkNoEntityCollision(bounds, entity) + ) pos else null + } + + private fun getReleasePositionOnGround(player: EntityPlayerMP, entity: EntityLivingBase, spawnPos: BlockPos): Vec3d? { + if (canReleaseWithoutGround(entity)) { + return Vec3d(spawnPos.x + 0.5, spawnPos.y.toDouble(), spawnPos.z + 0.5) + } + val groundPos = spawnPos.down() + val bounds = player.world.getBlockState(groundPos).getCollisionBoundingBox(player.world, groundPos) + if (bounds == null || bounds == Block.NULL_AABB) { + return null + } + return Vec3d(spawnPos.x + 0.5, groundPos.y + bounds.maxY, spawnPos.z + 0.5) + } + + private fun canReleaseWithoutGround(entity: EntityLivingBase): Boolean = + entity is EntityFlying || entity is EntityWaterMob || entity is net.minecraft.entity.passive.EntityFlying || entity.hasNoGravity() + + fun getBestUpgrade(backpackWrapper: BackpackWrapper): MobCatcherUpgradeWrapper? { + val upgrades = backpackWrapper.gatherCapabilityUpgrades(Capabilities.MOB_CATCHER_UPGRADE_CAPABILITY) + return upgrades.firstOrNull { it.isAdvanced } ?: upgrades.firstOrNull() + } + + fun isHostile(entity: EntityLivingBase): Boolean { + val entityType = EntityList.getKey(entity) ?: return entity is IMob + if (entityType in configuredEntityTypes(Config.mobCatcherUpgrade.passiveOverrides)) { + return false + } + return entityType in configuredEntityTypes(Config.mobCatcherUpgrade.hostileOverrides) || entity is IMob + } + + fun getSlotCost(entity: EntityLivingBase, hostile: Boolean): Int { + val maxHealth = getEffectiveMaxHealth(entity) + val currentHealth = maxOf(0.0, entity.health.toDouble()) + val baseCost = maxHealth / 2.0 + minOf(currentHealth, maxHealth) / 2.0 + val multiplier = if (hostile) Config.mobCatcherUpgrade.hostileMultiplier else Config.mobCatcherUpgrade.animalMultiplier + return maxOf(1, ceil(baseCost * multiplier).toInt()) + } + + fun getEffectiveMaxHealth(entity: EntityLivingBase): Double = + maxOf( + 1.0, + entity.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).attributeValue, + entity.maxHealth.toDouble(), + entity.health.toDouble() + ) + + private fun getCapturedMobDisplayName(entity: EntityLivingBase): String = + if (entity.hasCustomName()) entity.customNameTag else entity.displayName.unformattedText + + private fun configuredEntityTypes(configuredEntityTypes: Array): Set = + configuredEntityTypes.mapNotNull { + try { + ResourceLocation(it) + } catch (_: RuntimeException) { + null + } + }.toSet() + + private fun fail(player: EntityPlayerMP, messageKey: String, vararg args: Any): CaptureResult { + playMobCatcherSound(player, false, 0.8f) + return CaptureResult(false, messageKey, args) + } + + private fun playMobCatcherSound(player: EntityPlayerMP, success: Boolean, basePitch: Float) { + val sound = if (success) SoundEvents.ENTITY_ITEM_PICKUP else SoundEvents.BLOCK_NOTE_BASS + val pitch = basePitch + (player.rng.nextFloat() - 0.5f) * 0.16f + player.world.playSound(null, player.position, sound, SoundCategory.PLAYERS, 0.7f, pitch) + } + + private fun syncBackpack(player: EntityPlayerMP, backpackWrapper: BackpackWrapper) { + player.openContainer.detectAndSendChanges() + player.inventoryContainer.detectAndSendChanges() + CapabilityHandler.updateBackpackInventory(backpackWrapper) + syncCapturedMobsToViewers(player, backpackWrapper) + } + + private fun syncCapturedMobsToViewers(player: EntityPlayerMP, backpackWrapper: BackpackWrapper) { + player.server.playerList.players + .filter { + it == player || (it.openContainer as? BackpackContainer)?.backpackWrapper?.uuid == backpackWrapper.uuid + } + .forEach { + NetworkHandler.INSTANCE.sendTo(S2CMobCatcherContentsPacket(backpackWrapper), it) + } + } + + private data class CaptureResult(val success: Boolean, val messageKey: String, val args: Array = emptyArray()) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt new file mode 100644 index 0000000..dd31813 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherStorage.kt @@ -0,0 +1,553 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.EntityList +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.nbt.NBTTagList +import net.minecraft.util.ResourceLocation +import net.minecraftforge.items.ItemHandlerHelper +import kotlin.math.abs +import kotlin.math.ceil +import kotlin.math.ln + +object MobCatcherStorage { + const val CAPTURED_MOBS_TAG = "capturedMobs" + const val CAPTURED_MOBS_COLUMNS_TAG = "capturedMobsColumns" + + private const val ID_TAG = "id" + private const val ENTITY_TYPE_TAG = "entityType" + private const val ENTITY_NBT_TAG = "entityNbt" + private const val SLOT_TAG = "slot" + private const val WIDTH_TAG = "width" + private const val HEIGHT_TAG = "height" + private const val SLOT_COST_TAG = "slotCost" + private const val HOSTILE_TAG = "hostile" + private const val DISPLAY_NAME_TAG = "displayName" + private const val CURRENT_HEALTH_TAG = "currentHealth" + private const val MAX_HEALTH_TAG = "maxHealth" + private const val TAG_COMPOUND = 10 + private const val FOOTPRINT_ASPECT_WIDENING = 1.4 + private const val FOOTPRINT_ASPECT_WEIGHT = 10.0 + private const val FOOTPRINT_OVERFILL_WEIGHT = 0.75 + private const val FOOTPRINT_SCORE_EPSILON = 0.001 + private const val MOB_PART_PREFIX = "mob:" + private const val STACK_PART_PREFIX = "stack:" + private const val FIXED_PART_PREFIX = "fixed:" + + fun getCapturedMobs(backpackWrapper: BackpackWrapper): List = + backpackWrapper.capturedMobs + + fun setCapturedMobs(backpackWrapper: BackpackWrapper, capturedMobs: List) { + backpackWrapper.capturedMobs.clear() + backpackWrapper.capturedMobs.addAll(capturedMobs) + backpackWrapper.capturedMobsColumns = getColumns(backpackWrapper) + } + + fun addCapturedMob(backpackWrapper: BackpackWrapper, capturedMob: CapturedMob) { + backpackWrapper.capturedMobs.add(capturedMob) + backpackWrapper.capturedMobsColumns = getColumns(backpackWrapper) + } + + fun removeCapturedMob(backpackWrapper: BackpackWrapper, capturedMobId: java.util.UUID): Boolean { + val removed = backpackWrapper.capturedMobs.removeIf { it.id == capturedMobId } + if (removed && backpackWrapper.capturedMobs.isEmpty()) { + backpackWrapper.capturedMobsColumns = getColumns(backpackWrapper) + } + return removed + } + + fun getCapturedMob(backpackWrapper: BackpackWrapper, capturedMobId: java.util.UUID): CapturedMob? = + backpackWrapper.capturedMobs.firstOrNull { it.id == capturedMobId } + + fun getCapturedMobsTag(backpackWrapper: BackpackWrapper): NBTTagCompound { + backpackWrapper.ensureCapturedMobLayoutCurrent() + return NBTTagCompound().also { + it.setTag(CAPTURED_MOBS_TAG, serialize(getCapturedMobs(backpackWrapper))) + it.setInteger(CAPTURED_MOBS_COLUMNS_TAG, backpackWrapper.capturedMobsColumns) + } + } + + fun applyCapturedMobsTag(backpackWrapper: BackpackWrapper, nbt: NBTTagCompound) { + backpackWrapper.capturedMobs.clear() + backpackWrapper.capturedMobs.addAll(deserializeCapturedMobsTag(nbt)) + backpackWrapper.capturedMobsColumns = if (nbt.hasKey(CAPTURED_MOBS_COLUMNS_TAG)) { + nbt.getInteger(CAPTURED_MOBS_COLUMNS_TAG) + } else { + getColumns(backpackWrapper) + } + backpackWrapper.ensureCapturedMobLayoutCurrent() + } + + fun isSlotBlocked(backpackWrapper: BackpackWrapper, slot: Int): Boolean { + val columns = getColumns(backpackWrapper) + return getCapturedMobs(backpackWrapper).any { it.occupiesSlot(slot, columns) } + } + + fun canFitBasicTier(backpackWrapper: BackpackWrapper, maxSlotCost: Int): Boolean = + getCapturedMobs(backpackWrapper).all { !it.hostile && it.slotCost <= maxSlotCost } + + fun canFitWithAdditionalInventoryControls(backpackWrapper: BackpackWrapper, additionalControls: Int): Boolean { + if (additionalControls <= 0) { + return true + } + backpackWrapper.ensureCapturedMobLayoutCurrent() + val currentColumns = getColumns(backpackWrapper) + return canFitLayout(backpackWrapper, (currentColumns - additionalControls * 2).coerceAtLeast(1), currentColumns) + } + + fun findEmptyRectangle(backpackWrapper: BackpackWrapper, footprint: CapturedMobFootprint): Int? { + backpackWrapper.ensureCapturedMobLayoutCurrent() + val columns = getColumns(backpackWrapper) + val rows = ceil(backpackWrapper.backpackInventorySize().toDouble() / columns).toInt() + val capturedMobs = getCapturedMobs(backpackWrapper) + return findEmptyRectangle(backpackWrapper, footprint, columns, rows, capturedMobs) + } + + fun ensureLayoutCurrent(backpackWrapper: BackpackWrapper) { + val currentColumns = getColumns(backpackWrapper) + val previousColumns = backpackWrapper.capturedMobsColumns.takeIf { it > 0 } ?: currentColumns + val capturedMobs = getCapturedMobs(backpackWrapper) + if (capturedMobs.isEmpty()) { + backpackWrapper.capturedMobsColumns = currentColumns + return + } + if (previousColumns == currentColumns) { + return + } + + val compact = currentColumns > previousColumns + val fitResult = fitInventoryLayout( + getInventoryLayoutParts(backpackWrapper, capturedMobs, previousColumns, currentColumns), + backpackWrapper.backpackInventorySize(), + currentColumns, + compact + ) + if (!fitResult.fits) { + return + } + + applyInventoryLayout(backpackWrapper, fitResult) + backpackWrapper.capturedMobsColumns = currentColumns + } + + private fun canFitLayout(backpackWrapper: BackpackWrapper, targetColumns: Int, previousColumns: Int): Boolean { + if (targetColumns == previousColumns) { + return true + } + val capturedMobs = getCapturedMobs(backpackWrapper) + if (capturedMobs.isEmpty()) { + return true + } + return fitInventoryLayout( + getInventoryLayoutParts(backpackWrapper, capturedMobs, previousColumns, targetColumns), + backpackWrapper.backpackInventorySize(), + targetColumns, + compact = targetColumns > previousColumns + ).fits + } + + private fun getInventoryLayoutParts( + backpackWrapper: BackpackWrapper, + capturedMobs: List, + previousColumns: Int, + currentColumns: Int + ): List { + val parts = mutableListOf() + for (slot in 0 until backpackWrapper.backpackInventorySize()) { + val mobAtOrigin = capturedMobs.firstOrNull { it.slot == slot } + if (mobAtOrigin != null) { + parts += LayoutPart( + MOB_PART_PREFIX + mobAtOrigin.id, + getTargetSlot(mobAtOrigin.slot, previousColumns, currentColumns), + mobAtOrigin.width, + mobAtOrigin.height, + getOccupiedSlots(mobAtOrigin, previousColumns, backpackWrapper.backpackInventorySize()) + ) + continue + } + if (capturedMobs.any { it.occupiesSlot(slot, previousColumns) }) { + continue + } + + val stack = backpackWrapper.backpackItemStackHandler.getStackInSlot(slot) + if (stack.isEmpty) { + continue + } + val fixed = backpackWrapper.isSlotLocked(slot) || backpackWrapper.isSlotMemorized(slot) + parts += LayoutPart( + (if (fixed) FIXED_PART_PREFIX else STACK_PART_PREFIX) + slot, + slot, + 1, + 1, + setOf(slot) + ) + } + return parts + } + + private fun applyInventoryLayout(backpackWrapper: BackpackWrapper, fitResult: LayoutFitResult) { + val stackMoves = fitResult.fittedSlots.mapNotNull { (partId, targetSlot) -> + if (!partId.startsWith(STACK_PART_PREFIX)) { + return@mapNotNull null + } + val sourceSlot = partId.removePrefix(STACK_PART_PREFIX).toIntOrNull() ?: return@mapNotNull null + if (sourceSlot == targetSlot || + sourceSlot !in 0 until backpackWrapper.backpackInventorySize() || + targetSlot !in 0 until backpackWrapper.backpackInventorySize() + ) { + return@mapNotNull null + } + val stack = backpackWrapper.backpackItemStackHandler.getStackInSlot(sourceSlot) + if (stack.isEmpty) null else StackMove(sourceSlot, targetSlot, stack.copy()) + } + + if (stackMoves.isNotEmpty()) { + val sourceSlots = stackMoves.mapTo(mutableSetOf()) { it.sourceSlot } + val targetSlots = stackMoves.mapTo(mutableSetOf()) { it.targetSlot } + if (targetSlots.any { !backpackWrapper.backpackItemStackHandler.getStackInSlot(it).isEmpty && it !in sourceSlots }) { + return + } + stackMoves.forEach { backpackWrapper.backpackItemStackHandler.setStackInSlot(it.sourceSlot, net.minecraft.item.ItemStack.EMPTY) } + stackMoves.forEach { + backpackWrapper.backpackItemStackHandler.setStackInSlot( + it.targetSlot, + ItemHandlerHelper.copyStackWithSize(it.stack, it.stack.count) + ) + } + } + + val fittedMobs = getCapturedMobs(backpackWrapper).map { capturedMob -> + fitResult.fittedSlots[MOB_PART_PREFIX + capturedMob.id]?.let { capturedMob.copy(slot = it) } ?: capturedMob + } + backpackWrapper.capturedMobs.clear() + backpackWrapper.capturedMobs.addAll(fittedMobs) + } + + private fun findEmptyRectangle( + backpackWrapper: BackpackWrapper, + footprint: CapturedMobFootprint, + columns: Int, + rows: Int, + capturedMobs: List + ): Int? { + for (y in 0..rows - footprint.height) { + for (x in 0..columns - footprint.width) { + val slot = y * columns + x + if (isRectangleEmpty(backpackWrapper, slot, footprint, columns, capturedMobs)) { + return slot + } + } + } + return null + } + + private fun isRectangleEmpty( + backpackWrapper: BackpackWrapper, + slot: Int, + footprint: CapturedMobFootprint, + columns: Int, + capturedMobs: List + ): Boolean { + for (y in 0 until footprint.height) { + for (x in 0 until footprint.width) { + val checkedSlot = slot + y * columns + x + if (checkedSlot !in 0 until backpackWrapper.backpackInventorySize()) { + return false + } + if (!backpackWrapper.getStackInSlot(checkedSlot).isEmpty) { + return false + } + if (capturedMobs.any { it.occupiesSlot(checkedSlot, columns) }) { + return false + } + } + } + return true + } + + fun getFootprint(entity: EntityLivingBase, slotCost: Int): CapturedMobFootprint { + val entityWidth = maxOf(entity.width.toDouble(), 0.25) + val entityHeight = maxOf(entity.height.toDouble(), 0.25) + val targetAspect = entityWidth / entityHeight * FOOTPRINT_ASPECT_WIDENING + val maxSlotCost = maxOf(1, slotCost) + var best = CapturedMobFootprint(1, maxSlotCost) + var bestScore = Double.MAX_VALUE + var bestAspectError = Double.MAX_VALUE + var bestOverfill = Int.MAX_VALUE + + for (width in 1..maxSlotCost) { + for (height in 1..maxSlotCost) { + val area = width * height + if (area < slotCost) { + continue + } + val aspect = width.toDouble() / height + val aspectError = abs(ln(aspect / targetAspect)) + val overfill = area - slotCost + val score = aspectError * FOOTPRINT_ASPECT_WEIGHT + overfill * FOOTPRINT_OVERFILL_WEIGHT + if (isBetterFootprint( + score, + aspectError, + overfill, + width, + height, + bestScore, + bestAspectError, + bestOverfill, + best + ) + ) { + best = CapturedMobFootprint(width, height) + bestScore = score + bestAspectError = aspectError + bestOverfill = overfill + } + } + } + return best + } + + private fun isBetterFootprint( + score: Double, + aspectError: Double, + overfill: Int, + width: Int, + height: Int, + bestScore: Double, + bestAspectError: Double, + bestOverfill: Int, + best: CapturedMobFootprint + ): Boolean { + if (score < bestScore - FOOTPRINT_SCORE_EPSILON) return true + if (score > bestScore + FOOTPRINT_SCORE_EPSILON) return false + if (aspectError < bestAspectError - FOOTPRINT_SCORE_EPSILON) return true + if (aspectError > bestAspectError + FOOTPRINT_SCORE_EPSILON) return false + if (width != best.width) return width > best.width + if (height != best.height) return height < best.height + return overfill < bestOverfill + } + + fun getColumns(backpackWrapper: BackpackWrapper): Int { + val backgroundColumns = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 + val columnsTaken = (backpackWrapper.tankUpgradeSlots().take(2).size + backpackWrapper.batteryUpgradeSlots().take(1).size) * 2 + return (backgroundColumns - columnsTaken).coerceAtLeast(1) + } + + private fun getTargetSlot(slot: Int, columns: Int, targetColumns: Int): Int = + slot / columns * targetColumns + slot % columns + + private fun getOccupiedSlots(capturedMob: CapturedMob, columns: Int, inventorySlots: Int): Set { + val occupiedSlots = mutableSetOf() + for (y in 0 until capturedMob.height) { + for (x in 0 until capturedMob.width) { + val slot = capturedMob.slot + y * columns + x + if (slot < inventorySlots) { + occupiedSlots += slot + } + } + } + return occupiedSlots + } + + private fun fitInventoryLayout( + parts: List, + targetSlots: Int, + targetColumns: Int, + compact: Boolean + ): LayoutFitResult { + val result = fitInventoryLayoutInternal(parts, targetSlots, targetColumns, compact, compact) + if (compact || result.fits) { + return result + } + + val compactResult = fitInventoryLayoutInternal(parts, targetSlots, targetColumns, compact = true, preserveStacks = false) + if (compactResult.fits) { + return compactResult + } + + val reorderedCompactResult = fitInventoryLayoutInternal( + orderPartsForCompaction(parts), + targetSlots, + targetColumns, + compact = true, + preserveStacks = false, + fillGapsWithStacks = true + ) + return if (reorderedCompactResult.fits) reorderedCompactResult else compactResult + } + + private fun orderPartsForCompaction(parts: List): List = + parts.sortedWith( + compareBy { compactionPriority(it) } + .thenByDescending { it.width * it.height } + .thenBy { it.firstSlot } + ) + + private fun compactionPriority(part: LayoutPart): Int = + when { + part.id.startsWith(FIXED_PART_PREFIX) -> 0 + part.id.startsWith(STACK_PART_PREFIX) -> 2 + else -> 1 + } + + private fun fitInventoryLayoutInternal( + parts: List, + targetSlots: Int, + targetColumns: Int, + compact: Boolean, + preserveStacks: Boolean, + fillGapsWithStacks: Boolean = false + ): LayoutFitResult { + val occupiedSlots = mutableSetOf() + val fittedSlots = mutableMapOf() + var nextSlot = 0 + + for ((partIndex, part) in parts.withIndex()) { + val fittedSlot = findNextFit( + part, + if (fillGapsWithStacks && part.id.startsWith(STACK_PART_PREFIX)) 0 else nextSlot, + targetSlots, + targetColumns, + occupiedSlots, + compact, + preserveStacks + ) + if (fittedSlot < 0) { + return LayoutFitResult( + false, + fittedSlots, + parts.drop(partIndex).flatMapTo(mutableSetOf()) { it.sourceSlots } + ) + } + + occupy(part, fittedSlot, targetColumns, occupiedSlots) + fittedSlots[part.id] = fittedSlot + nextSlot = if (!compact && fittedSlot == part.firstSlot) { + maxOf(nextSlot, getSlotAfterPart(part, fittedSlot, targetColumns)) + } else { + fittedSlot + part.width + } + } + + return LayoutFitResult(true, fittedSlots) + } + + private fun findNextFit( + part: LayoutPart, + nextSlot: Int, + targetSlots: Int, + targetColumns: Int, + occupiedSlots: Set, + compact: Boolean, + preserveStacks: Boolean + ): Int { + if (part.id.startsWith(FIXED_PART_PREFIX)) { + return if (fits(part, part.firstSlot, targetSlots, targetColumns, occupiedSlots)) part.firstSlot else -1 + } + if (shouldPreserveFirstSlot(part, compact, preserveStacks) && + part.firstSlot < targetSlots && + fits(part, part.firstSlot, targetSlots, targetColumns, occupiedSlots) + ) { + return part.firstSlot + } + + val startSlot = if (compact || part.firstSlot >= targetSlots) nextSlot else maxOf(nextSlot, part.firstSlot) + for (slot in startSlot until targetSlots) { + if (fits(part, slot, targetSlots, targetColumns, occupiedSlots)) { + return slot + } + } + return -1 + } + + private fun shouldPreserveFirstSlot(part: LayoutPart, compact: Boolean, preserveStacks: Boolean): Boolean = + !compact || preserveStacks && part.id.startsWith(STACK_PART_PREFIX) + + private fun fits(part: LayoutPart, slot: Int, targetSlots: Int, targetColumns: Int, occupiedSlots: Set): Boolean { + val x = slot % targetColumns + if (x + part.width > targetColumns) { + return false + } + for (y in 0 until part.height) { + for (partX in 0 until part.width) { + val checkedSlot = slot + y * targetColumns + partX + if (checkedSlot >= targetSlots || checkedSlot in occupiedSlots) { + return false + } + } + } + return true + } + + private fun occupy(part: LayoutPart, slot: Int, targetColumns: Int, occupiedSlots: MutableSet) { + for (y in 0 until part.height) { + for (x in 0 until part.width) { + occupiedSlots += slot + y * targetColumns + x + } + } + } + + private fun getSlotAfterPart(part: LayoutPart, slot: Int, targetColumns: Int): Int = + slot + (part.height - 1) * targetColumns + part.width + + fun serialize(capturedMobs: List): NBTTagList = + NBTTagList().also { list -> capturedMobs.sortedBy { it.slot }.forEach { list.appendTag(serialize(it)) } } + + fun deserialize(list: NBTTagList): List = + (0 until list.tagCount()).mapNotNull { deserialize(list.getCompoundTagAt(it)) } + + private fun serialize(capturedMob: CapturedMob): NBTTagCompound = + NBTTagCompound().also { tag -> + tag.setUniqueId(ID_TAG, capturedMob.id) + tag.setString(ENTITY_TYPE_TAG, capturedMob.entityType.toString()) + tag.setTag(ENTITY_NBT_TAG, capturedMob.entityNbt.copy()) + tag.setInteger(SLOT_TAG, capturedMob.slot) + tag.setInteger(WIDTH_TAG, capturedMob.width) + tag.setInteger(HEIGHT_TAG, capturedMob.height) + tag.setInteger(SLOT_COST_TAG, capturedMob.slotCost) + tag.setBoolean(HOSTILE_TAG, capturedMob.hostile) + tag.setString(DISPLAY_NAME_TAG, capturedMob.displayName) + tag.setInteger(CURRENT_HEALTH_TAG, capturedMob.currentHealth) + tag.setInteger(MAX_HEALTH_TAG, capturedMob.maxHealth) + } + + private fun deserialize(tag: NBTTagCompound): CapturedMob? { + val entityType = ResourceLocation(tag.getString(ENTITY_TYPE_TAG)) + if (!EntityList.isRegistered(entityType)) { + return null + } + return CapturedMob( + tag.getUniqueId(ID_TAG) ?: return null, + entityType, + tag.getCompoundTag(ENTITY_NBT_TAG), + tag.getInteger(SLOT_TAG), + tag.getInteger(WIDTH_TAG).coerceAtLeast(1), + tag.getInteger(HEIGHT_TAG).coerceAtLeast(1), + tag.getInteger(SLOT_COST_TAG).coerceAtLeast(1), + tag.getBoolean(HOSTILE_TAG), + tag.getString(DISPLAY_NAME_TAG), + tag.getInteger(CURRENT_HEALTH_TAG), + tag.getInteger(MAX_HEALTH_TAG).coerceAtLeast(1) + ) + } + + fun deserializeCapturedMobsTag(nbt: NBTTagCompound): List = + deserialize(nbt.getTagList(CAPTURED_MOBS_TAG, TAG_COMPOUND)) + + private data class LayoutPart( + val id: String, + val firstSlot: Int, + val width: Int, + val height: Int, + val sourceSlots: Set + ) + + private data class LayoutFitResult( + val fits: Boolean, + val fittedSlots: Map, + val errorSlots: Set = emptySet() + ) + + private data class StackMove(val sourceSlot: Int, val targetSlot: Int, val stack: net.minecraft.item.ItemStack) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt new file mode 100644 index 0000000..c6d637c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/mobcatcher/MobCatcherUpgradeWrapper.kt @@ -0,0 +1,19 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.item.MobCatcherUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.util.EnumFacing +import net.minecraftforge.common.capabilities.Capability + +class MobCatcherUpgradeWrapper(private val advanced: Boolean = false) : UpgradeWrapper() { + override val settingsLangKey: String = "" + + val isAdvanced: Boolean + get() = advanced + + override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = + capability == Capabilities.MOB_CATCHER_UPGRADE_CAPABILITY || + super.hasCapability(capability, facing) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt index f3f20a6..8d4d33b 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt @@ -2,6 +2,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui import com.cleanroommc.modularui.api.drawable.IDrawable import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.layout.IViewportStack import com.cleanroommc.modularui.api.widget.Interactable import com.cleanroommc.modularui.drawable.ItemDrawable import com.cleanroommc.modularui.drawable.UITexture @@ -12,12 +13,11 @@ import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetTheme import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.value.sync.PanelSyncManager -import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.modularui.widget.Widget import com.cleanroommc.modularui.widgets.SlotGroupWidget import com.cleanroommc.modularui.widgets.TextWidget import com.cleanroommc.modularui.widgets.slot.ItemSlot import com.cleanroommc.modularui.widgets.slot.SlotGroup -import com.cleanroommc.retrosophisticatedbackpacks.Tags import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHelper import com.cleanroommc.retrosophisticatedbackpacks.backpack.SortType import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper @@ -33,6 +33,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.LockedPlayerS import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlot import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularUpgradeSlot import com.cleanroommc.retrosophisticatedbackpacks.config.ClientConfig +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.item.UpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSH import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSlotSH @@ -41,11 +42,17 @@ import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.ceilDiv import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.setEnabledIfAndEnabled +import net.minecraft.client.Minecraft import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack +import net.minecraft.client.gui.Gui +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.util.ITooltipFlag +import net.minecraft.util.text.TextFormatting import net.minecraftforge.fml.common.Loader import net.minecraftforge.items.wrapper.PlayerInvWrapper import net.minecraftforge.items.wrapper.PlayerMainInvWrapper +import java.util.Locale import kotlin.math.min class BackpackPanel( @@ -60,6 +67,11 @@ class BackpackPanel( private const val HEIGHT_WITHOUT_STORAGE_SLOTS = 114 private const val STORAGE_INVENTORY_X = 7 private const val STORAGE_INVENTORY_Y = 17 + private const val SEARCH_BOX_MIN_WIDTH = 10 + private const val SEARCH_BOX_HEIGHT = 10 + private const val SEARCH_BOX_UNFOCUSED_COLOR = 0xBBBBBB + private const val SEARCH_BOX_ANIMATION_MS = 200L + internal const val DISABLED_SLOT_X_POS = -2000 internal const val VISIBLE_BACKPACK_ROWS = 5 internal const val PLAYER_INVENTORY_BOTTOM = 8 internal const val INVENTORY_CONTROL_COLUMNS = 2 @@ -158,6 +170,11 @@ class BackpackPanel( private var rebuildWidgetsQueued = false private var lastUpgradeStructureSignature = emptyList() private var reopenBackpackQueued = false + private val searchSlotDisplayIndices = IntArray(backpackWrapper.backpackInventorySize()) { it } + private var searchVisibleSlots = backpackWrapper.backpackInventorySize() + private var lastSearchLayoutKey = "" + var searchLayoutVersion = 0 + private set var isSettingMode: Boolean = false set(value) { if (field == value) @@ -173,11 +190,18 @@ class BackpackPanel( closeSettingTabs() updateUpgradeWidgets() } + updateSearchLayout(force = true) scheduleResize() } + private val searchTerms: List + get() = backpackWrapper.searchPhrase.trim() + .split(Regex("\\s+")) + .filter(String::isNotEmpty) + override fun onUpdate() { super.onUpdate() + updateSearchLayout() if (!rebuildWidgetsQueued) queueRebuildIfUpgradeStructureChanged() if (reopenBackpackQueued) { @@ -224,19 +248,21 @@ class BackpackPanel( recalculateLayout() size(panelWidth, panelHeight) + updateSearchLayout(force = true) upgradeSlotWidgets.clear() tabWidgets.clear() upgradeSlotGroupWidget = UpgradeSlotGroupWidget(this, backpackWrapper.upgradeSlotsSize()) currentItemDisplaySelectedSlot = -1 addPlayerInventoryWidgets() - addSortingButtons() - addTransferButtons() addBackpackInventorySlots() addUpgradeSlots() addSettingTab() addUpgradeTabs() addTexts(player) + addSortingButtons() + addSearchBox() + addTransferButtons() closeSettingTabs() lastUpgradeStructureSignature = upgradeStructureSignature() updateUpgradeWidgets() @@ -371,11 +397,10 @@ class BackpackPanel( .top(4) .right(rightAnchor) .size(12) - val sortButton = ButtonWidget() + val sortButton = TransferButtonWidget(RSBTextures.SOLID_UP_ARROW_ICON, RSBTextures.SOLID_UP_ARROW_ICON) .top(4) .right(rightAnchor + 14) .size(12) - .overlay(RSBTextures.SOLID_UP_ARROW_ICON) .setEnabledIf { !isSettingMode } @@ -474,15 +499,296 @@ class BackpackPanel( .child(transferToBackpackButton) } + internal fun addSearchBox() { + val rightAnchor = if (Loader.isModLoaded("bogosorter")) 30 else 7 + val sortButtonLeft = panelWidth - (rightAnchor + 14) - 12 + val left = 7 + val width = (sortButtonLeft - 1 - left).coerceAtLeast(SEARCH_BOX_MIN_WIDTH) + if (width <= 0) { + return + } + + child( + SearchBoxWidget() + .top(5) + .left(left) + .size(width, SEARCH_BOX_HEIGHT) + .setEnabledIf { !isSettingMode } + ) + } + internal fun addPlayerInventoryWidgets() { child( SlotGroupWidget.playerInventory(PLAYER_INVENTORY_BOTTOM - 1, false) { _, _ -> NoBackgroundItemSlot() } + .disableSortButtons() .left(playerInventoryLabelX - 1) ) } + internal fun hasSearchPhrase(): Boolean = + searchTerms.isNotEmpty() + + internal fun isSearchViewActive(): Boolean = + !isSettingMode && hasSearchPhrase() + + internal fun updateSearchLayout(force: Boolean = false) { + val key = if (isSearchViewActive()) + "${isSettingMode}|${backpackWrapper.searchPhrase}|${searchInventorySignature()}" + else "${isSettingMode}|${backpackWrapper.searchPhrase}|${backpackWrapper.backpackInventorySize()}" + if (!force && key == lastSearchLayoutKey) { + return + } + + lastSearchLayoutKey = key + searchVisibleSlots = 0 + + if (!isSearchViewActive()) { + for (slotIndex in searchSlotDisplayIndices.indices) { + searchSlotDisplayIndices[slotIndex] = slotIndex + } + searchVisibleSlots = backpackWrapper.backpackInventorySize() + } else { + for (slotIndex in searchSlotDisplayIndices.indices) { + val stack = backpackWrapper.getStackInSlot(slotIndex) + searchSlotDisplayIndices[slotIndex] = + if (!backpackWrapper.isSlotBlockedByMobCatcher(slotIndex) && !stack.isEmpty && matchesSearch(stack)) + searchVisibleSlots++ + else DISABLED_SLOT_X_POS + } + } + + searchLayoutVersion++ + } + + internal fun isSearchSlotVisible(slotIndex: Int): Boolean = + !isSearchViewActive() || searchSlotDisplayIndices.getOrNull(slotIndex)?.let { it >= 0 } == true + + internal fun searchSlotX(slotIndex: Int): Int { + val displayIndex = searchSlotDisplayIndices.getOrNull(slotIndex) ?: return DISABLED_SLOT_X_POS + return if (displayIndex < 0) DISABLED_SLOT_X_POS else displayIndex % rowSize * SLOT_SIZE + } + + internal fun searchSlotY(slotIndex: Int): Int { + val displayIndex = searchSlotDisplayIndices.getOrNull(slotIndex) ?: return 0 + return if (displayIndex < 0) 0 else displayIndex / rowSize * SLOT_SIZE + } + + internal fun searchVisibleSlotCount(): Int = + if (isSearchViewActive()) searchVisibleSlots else backpackWrapper.backpackInventorySize() + + internal fun searchDisplayRows(): Int = + if (isSearchViewActive()) searchVisibleSlots.coerceAtLeast(1).ceilDiv(rowSize).coerceAtLeast(visibleColSize) + else colSize + + private fun searchInventorySignature(): String = + buildString { + append(backpackWrapper.backpackInventorySize()) + for (slotIndex in 0 until backpackWrapper.backpackInventorySize()) { + val stack = backpackWrapper.getStackInSlot(slotIndex) + append('|') + if (stack.isEmpty) { + append("empty") + } else { + append(stack.item.registryName) + .append(':') + .append(stack.metadata) + .append(':') + .append(stack.count) + } + append(':') + .append(backpackWrapper.isSlotBlockedByMobCatcher(slotIndex)) + } + } + + internal fun matchesSearch(stack: ItemStack): Boolean { + val terms = searchTerms + if (terms.isEmpty()) { + return true + } + if (stack.isEmpty) { + return false + } + + val displayName = stack.displayName.lowercase(Locale.ROOT) + val registryName = stack.item.registryName + val modId = registryName?.namespace?.lowercase(Locale.ROOT) ?: "" + val tooltipLines by lazy { + stack.getTooltip(player, ITooltipFlag.TooltipFlags.NORMAL) + .joinToString("\n") { TextFormatting.getTextWithoutFormattingCodes(it) ?: it } + .lowercase(Locale.ROOT) + } + + return terms.all { rawTerm -> + val term = rawTerm.lowercase(Locale.ROOT) + when { + term.startsWith("@") -> modId.contains(term.drop(1)) + term.startsWith("#") -> tooltipLines.contains(term.drop(1)) + else -> displayName.contains(term) + } + } + } + + private fun setSearchPhrase(phrase: String) { + val trimmed = phrase.take(50) + if (backpackWrapper.searchPhrase == trimmed) { + return + } + backpackWrapper.searchPhrase = trimmed + updateSearchLayout(force = true) + backpackSyncHandler.syncToServer(BackpackSH.UPDATE_SEARCH_PHRASE) { + it.writeString(trimmed) + } + } + + private inner class SearchBoxWidget : VanillaTextFieldWidget(1, SEARCH_BOX_MIN_WIDTH - 2, 8) { + private var lastSyncedText = backpackWrapper.searchPhrase + private var lastFocusChangeTime = Minecraft.getSystemTime() + private var currentWidth = -1 + private var currentTheme = WidgetTheme.getDefault().theme + + init { + textField.setMaxStringLength(50) + textField.setText(backpackWrapper.searchPhrase) + textField.setTextColor(if (backpackWrapper.searchPhrase.isEmpty()) SEARCH_BOX_UNFOCUSED_COLOR else 0xFFFFFF) + textField.setDisabledTextColour(SEARCH_BOX_UNFOCUSED_COLOR) + tooltipBuilder { + it.addLine(IKey.lang("gui.search".asTranslationKey())) + .addLine(IKey.lang("gui.search_detail".asTranslationKey()).style(IKey.GRAY)) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + } + + override fun isInside(stack: IViewportStack, mx: Int, my: Int, absolute: Boolean): Boolean { + if (isSettingMode) { + return false + } + val x = if (absolute) stack.unTransformX(mx.toFloat(), my.toFloat()) else mx + val y = if (absolute) stack.unTransformY(mx.toFloat(), my.toFloat()) else my + return y >= 0 && y < area.height && x >= visualX() && x < area.width + } + + override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) {} + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + currentTheme = widgetTheme.theme + } + + override fun drawForeground(context: ModularGuiContext) { + if (isSettingMode) { + return + } + GlStateManager.color(1f, 1f, 1f, 1f) + val visualWidth = visualWidth() + val visualX = area.x + area.width - visualWidth + Gui.drawRect(visualX, area.y, visualX + visualWidth, area.y + area.height, 0xFF777777.toInt()) + if (!isFocused() && textField.text.isEmpty()) { + RSBTextures.SEARCH_ICON.draw( + context, + visualX, + area.y, + SEARCH_BOX_MIN_WIDTH, + SEARCH_BOX_HEIGHT, + currentTheme + ) + } else { + drawTextField() + } + GlStateManager.color(1f, 1f, 1f, 1f) + super.drawForeground(context) + } + + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (isSettingMode) { + return Interactable.Result.IGNORE + } + val mouseX = context.mouseX + val mouseY = context.mouseY + if (mouseY < 0 || mouseY >= area.height || mouseX < visualX() || mouseX >= area.width) { + return Interactable.Result.IGNORE + } + if (mouseButton == 1) { + onTextChanged("") + return Interactable.Result.SUCCESS + } + if (mouseButton != 0) { + return Interactable.Result.STOP + } + return super.onMousePressed(mouseButton) + } + + override fun onUpdate() { + super.onUpdate() + if (isSettingMode) { + if (isFocused()) { + context.removeFocus() + } + return + } + animateWidth() + if (backpackWrapper.searchPhrase != lastSyncedText && backpackWrapper.searchPhrase != textField.text) { + lastSyncedText = backpackWrapper.searchPhrase + textField.setText(lastSyncedText) + } + } + + override fun onTextChanged(text: String) { + val trimmed = text.take(50) + if (textField.text != trimmed) { + textField.setText(trimmed) + } + if (trimmed == lastSyncedText) { + return + } + lastSyncedText = trimmed + setSearchPhrase(lastSyncedText) + } + + override fun onFocusChanged(focused: Boolean) { + lastFocusChangeTime = Minecraft.getSystemTime() + textField.setTextColor(if (focused) 0xFFFFFF else SEARCH_BOX_UNFOCUSED_COLOR) + } + + private fun visualWidth(): Int { + animateWidth() + return currentWidth.coerceIn(SEARCH_BOX_MIN_WIDTH, area.width) + } + + private fun visualX(): Int = area.width - visualWidth() + + override fun textFieldX(): Int = area.x + visualX() + 1 + + override fun textFieldY(): Int = area.y + 1 + + override fun textFieldWidth(): Int = visualWidth() - 6 + + override fun textFieldHeight(): Int = SEARCH_BOX_HEIGHT + + override fun mouseXForTextField(): Int = area.x + context.mouseX + + override fun mouseYForTextField(): Int = area.y + context.mouseY + + private fun animateWidth() { + val target = if (isFocused() || textField.text.isNotEmpty()) area.width else SEARCH_BOX_MIN_WIDTH + if (currentWidth < 0) { + currentWidth = target + return + } + if (currentWidth == target) { + return + } + val elapsed = (Minecraft.getSystemTime() - lastFocusChangeTime).coerceAtLeast(0L) + val ratio = (elapsed.toFloat() / SEARCH_BOX_ANIMATION_MS).coerceIn(0f, 1f) + val eased = if (ratio < 0.5f) 4f * ratio * ratio * ratio else 1f - Math.pow((-2f * ratio + 2f).toDouble(), 3.0).toFloat() / 2f + currentWidth = if (target == area.width) { + (SEARCH_BOX_MIN_WIDTH + (area.width - SEARCH_BOX_MIN_WIDTH) * eased).toInt() + } else { + (area.width - (area.width - SEARCH_BOX_MIN_WIDTH) * eased).toInt() + }.coerceIn(SEARCH_BOX_MIN_WIDTH, area.width) + } + } + internal fun addBackpackInventorySlots() { val inventoryArea = SlotGroupWidget().disableSortButtons() .size(inventoryAreaWidth, storageInventoryHeight) @@ -508,6 +814,7 @@ class BackpackPanel( ) .pos(backpackSlotsWidth + inventoryScrollbarWidth + controlIndex * TankInventoryControlWidget.WIDTH, 0) .name("tank_inventory_control_$slot") + .setEnabledIf { !isSettingMode && !isSearchViewActive() } ) controlIndex++ } @@ -525,6 +832,7 @@ class BackpackPanel( ) .pos(backpackSlotsWidth + inventoryScrollbarWidth + controlIndex * BatteryInventoryControlWidget.WIDTH, 0) .name("battery_inventory_control_$slot") + .setEnabledIf { !isSettingMode && !isSearchViewActive() } ) controlIndex++ } @@ -538,7 +846,10 @@ class BackpackPanel( upgradeSlotGroupWidget.setEnabledIf { !isSettingMode } for (i in 0 until backpackWrapper.upgradeSlotsSize()) { - val itemSlot = NoBackgroundItemSlot().syncHandler("upgrades", i).pos(5, 5 + i * 16).name("slot_${i}") + val itemSlot = NoBackgroundItemSlot(RSBTextures.EMPTY_UPGRADE_SLOT) + .syncHandler("upgrades", i) + .pos(5, 5 + i * 16) + .name("slot_${i}") upgradeSlotWidgets.add(itemSlot) upgradeSlotGroupWidget.child(itemSlot) @@ -558,6 +869,13 @@ class BackpackPanel( backpackSettingTabWidget.tooltipDynamic { it.clearText() .addLine(IKey.lang("gui.backpack_settings.tooltip".asTranslationKey())) + .addLine( + IKey.lang( + if (backpackSettingTabWidget.showExpanded) + "gui.backpack_settings.tooltip_open_detail".asTranslationKey() + else "gui.backpack_settings.tooltip_detail".asTranslationKey() + ).style(IKey.GRAY) + ) .pos(RichTooltip.Pos.NEXT_TO_MOUSE) } @@ -613,8 +931,10 @@ class BackpackPanel( } child(SettingTabWidget().setEnabledIf { !isSettingMode }) - .child(itemDisplaySettingTabWidget) - .child(memorySettingTabWidget) + if (!Config.itemDisplayDisabled) { + child(itemDisplaySettingTabWidget) + } + child(memorySettingTabWidget) .child(sortingSettingTabWidget) .child(backpackSettingTabWidget) .child(backToBackpackTab) @@ -687,7 +1007,7 @@ class BackpackPanel( } fun openItemDisplaySettings(tabWidget: TabWidget, open: Boolean) { - if (!isSettingMode) + if (!isSettingMode || Config.itemDisplayDisabled) return itemDisplaySettingTabWidget.showExpanded = open @@ -715,7 +1035,7 @@ class BackpackPanel( backpackSettingTabWidget.isEnabled = isSettingMode memorySettingTabWidget.isEnabled = isSettingMode sortingSettingTabWidget.isEnabled = isSettingMode - itemDisplaySettingTabWidget.isEnabled = isSettingMode + itemDisplaySettingTabWidget.isEnabled = isSettingMode && !Config.itemDisplayDisabled isBackpackSettingTabOpened = false isMemorySettingTabOpened = false shouldMemorizeRespectNBT = false @@ -748,6 +1068,9 @@ class BackpackPanel( private fun updateSettingTabEnabledStates(openTab: TabWidget, open: Boolean) { listOf(backpackSettingTabWidget, sortingSettingTabWidget, memorySettingTabWidget, itemDisplaySettingTabWidget) .forEach { it.isEnabled = !open || it == openTab } + if (Config.itemDisplayDisabled) { + itemDisplaySettingTabWidget.isEnabled = false + } } private fun closeUpgradeTabs(syncToServer: Boolean) { @@ -988,7 +1311,7 @@ class BackpackPanel( wrapper ) ) - tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, 12) + tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, wrapper.discInventory.slots) } is JukeboxUpgradeWrapper -> { @@ -998,7 +1321,7 @@ class BackpackPanel( wrapper ) ) - tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, 1) + tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, wrapper.discInventory.slots) } is AdvancedToolSwapperUpgradeWrapper -> { @@ -1046,7 +1369,7 @@ class BackpackPanel( wrapper ) ) - tabWidget.expandedWidget = BatteryUpgradeWidget(slotIndex, wrapper, stack, backpackWrapper) + tabWidget.expandedWidget = BatteryUpgradeWidget(slotIndex, wrapper, stack) } is AnvilUpgradeWrapper -> { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt index 5c068bf..1f7e6f8 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt @@ -32,18 +32,23 @@ object RSBTextures { val IN_OUT_ICON = icon("in_out", 0, 32) val IN_ICON = icon("in", 16, 32) val OUT_ICON = icon("out", 32, 32) - val PUMP_INPUT_ICON = controlIcon(144, 0) - val PUMP_OUTPUT_ICON = controlIcon(160, 0) - val PUMP_WORLD_ICON = controlIcon(176, 0) - val PUMP_NO_WORLD_ICON = controlIcon(192, 0) - val PUMP_HAND_ICON = controlIcon(208, 0) - val PUMP_NO_HAND_ICON = controlIcon(224, 0) - val PUMP_FLUID_HANDLER_ICON = controlIcon(0, 112) - val PUMP_NO_FLUID_HANDLER_ICON = controlIcon(16, 112) + val PUMP_INPUT_ICON = icon("pump_input", 144, 0) + val PUMP_OUTPUT_ICON = icon("pump_output", 160, 0) + val PUMP_WORLD_ICON = icon("pump_world", 176, 0) + val PUMP_NO_WORLD_ICON = icon("pump_no_world", 192, 0) + val PUMP_HAND_ICON = icon("pump_hand", 208, 0) + val PUMP_NO_HAND_ICON = icon("pump_no_hand", 224, 0) + val PUMP_FLUID_HANDLER_ICON = icon("pump_fluid_handler", 0, 112) + val PUMP_NO_FLUID_HANDLER_ICON = icon("pump_no_fluid_handler", 16, 112) val ADD_ICON = icon("add", 96, 32) val REMOVE_ICON = icon("remove", 112, 32) val BRAIN_ICON = icon("brain", 128, 32) + val ANVIL_NAME_BACKGROUND = controlIcon(28, 99, 100, 16) + val ANVIL_NAME_BACKGROUND_DISABLED = controlIcon(28, 115, 100, 16) + val ANVIL_PLUS_SIGN = controlIcon(113, 203, 13, 13) + val ANVIL_ARROW = controlIcon(56, 221, 14, 15) + val ANVIL_RED_CROSS = controlIcon(113, 216, 15, 15) val ONE_IN_FOUR_SLOT_ICON = icon("one_in_four_slot", 0, 80) val ALL_FOUR_SLOT_ICON = icon("all_in_four_slot", 16, 80) @@ -88,6 +93,16 @@ object RSBTextures { .imageSize(256, 256) .xy(47, 0, 18, 18) .build() + val SMALL_BUTTON = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(29, 18, 12, 12) + .build() + val SMALL_BUTTON_HOVERED = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(41, 18, 12, 12) + .build() val CONTEXT_BUTTON_LEFT = buttonPiece(29, 0, 16, 18) val CONTEXT_BUTTON_LEFT_HOVERED = buttonPiece(47, 0, 16, 18) val CONTEXT_BUTTON_MIDDLE = buttonPiece(31, 0, 14, 18) @@ -155,14 +170,15 @@ object RSBTextures { val BAR_BACKGROUND_TOP = barBackground(29, 30) val BAR_BACKGROUND_MIDDLE = barBackground(29, 48) val BAR_BACKGROUND_BOTTOM = barBackground(29, 66) - val SHIFT_CLICK_OPEN_TAB_ON = controlIcon(80, 32) - val SHIFT_CLICK_OPEN_TAB_OFF = controlIcon(64, 96) - val KEEP_TAB_OPEN_ON = controlIcon(80, 80) - val KEEP_TAB_OPEN_OFF = controlIcon(80, 96) - val KEEP_SEARCH_PHRASE_ON = controlIcon(208, 32) - val KEEP_SEARCH_PHRASE_OFF = controlIcon(224, 32) - val ANOTHER_PLAYER_CAN_OPEN_ON = controlIcon(176, 32) - val ANOTHER_PLAYER_CAN_OPEN_OFF = controlIcon(192, 32) + val SHIFT_CLICK_OPEN_TAB_ON = icon("shift_click_open_tab_on", 80, 32) + val SHIFT_CLICK_OPEN_TAB_OFF = icon("shift_click_open_tab_off", 64, 96) + val KEEP_TAB_OPEN_ON = icon("keep_tab_open_on", 80, 80) + val KEEP_TAB_OPEN_OFF = icon("keep_tab_open_off", 80, 96) + val KEEP_SEARCH_PHRASE_ON = icon("keep_search_phrase_on", 208, 32) + val KEEP_SEARCH_PHRASE_OFF = icon("keep_search_phrase_off", 224, 32) + val SEARCH_ICON = icon("search", 208, 32) + val ANOTHER_PLAYER_CAN_OPEN_ON = icon("another_player_can_open_on", 176, 32) + val ANOTHER_PLAYER_CAN_OPEN_OFF = icon("another_player_can_open_off", 192, 32) private fun icon(name: String, x: Int, y: Int, w: Int = 16, h: Int = 16): UITexture = UITexture.builder() diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt index ae80dd9..77e1aee 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/UpgradeSlotUpdateGroup.kt @@ -138,20 +138,20 @@ class UpgradeSlotUpdateGroup( } syncManager.registerSlotGroup(SlotGroup("crafting_matrix_$slotIndex", 3, false)) - - - craftingOutputSlot = { - val slot = IndexedModularCraftingSlot(slotIndex, craftingStackHandler.delegatedStackHandler, 9) - slot.slotGroup("crafting_result_$slotIndex") - + craftingOutputSlot = run { + val slot = IndexedModularCraftingSlot( + this@UpgradeSlotUpdateGroup.slotIndex, + this@UpgradeSlotUpdateGroup.craftingStackHandler.delegatedStackHandler, + 9 + ) + slot.slotGroup("crafting_result_${this@UpgradeSlotUpdateGroup.slotIndex}") syncManager.syncValue( - "crafting_result_$slotIndex", + "crafting_result_${this@UpgradeSlotUpdateGroup.slotIndex}", 0, ItemSlotSH(slot) ) - slot - }.invoke() + } craftingInfo = CraftingSlotInfo(craftingMatrixSlots, craftingOutputSlot) syncManager.registerSlotGroup(SlotGroup("crafting_result_$slotIndex", 1, false)) @@ -247,5 +247,4 @@ class UpgradeSlotUpdateGroup( anvilStackHandler.setDelegatedStackHandler(wrapper::getInventory) anvilStackHandler.syncToServer(DelegatedStackHandlerSH.UPDATE_ANVIL) } - } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt index 04a080e..b4ccd67 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt @@ -20,8 +20,8 @@ class BackToBackpackTabWidget : Widget(), Interactable init { size(TAB_TEXTURE.width, TAB_TEXTURE.height) - .right(-TAB_TEXTURE.width + 4) - .top(4) + .right(-TAB_TEXTURE.width + 2) + .top(0) .background(TAB_TEXTURE.get(-1, false)) .tooltipStatic { it.addLine(IKey.lang("gui.back_to_backpack.tooltip".asTranslationKey())) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt index a287e5c..3f5dbd3 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt @@ -12,6 +12,9 @@ import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.Backp class BackpackInventoryScrollWidget(panel: BackpackPanel) : ScrollWidget(VerticalScrollData(false, SCROLLBAR_WIDTH)) { + private val panel = panel + private var lastSearchLayoutVersion = panel.searchLayoutVersion + init { val scrollData = scrollArea.scrollY scrollData.scrollSize = panel.colSize * SLOT_SIZE @@ -22,6 +25,18 @@ class BackpackInventoryScrollWidget(panel: BackpackPanel) : child(createSlots(panel, panel.colSize)) } + override fun onUpdate() { + super.onUpdate() + val scrollData = scrollArea.scrollY + scrollData.scrollSize = panel.searchDisplayRows() * SLOT_SIZE + if (lastSearchLayoutVersion != panel.searchLayoutVersion) { + lastSearchLayoutVersion = panel.searchLayoutVersion + scrollData.scrollTo(scrollArea, 0) + } else { + scrollData.clamp(scrollArea) + } + } + companion object { const val SCROLLBAR_WIDTH = 4 private const val SLOT_SIZE = 18 @@ -38,6 +53,12 @@ class BackpackInventoryScrollWidget(panel: BackpackPanel) : .name("slot_$i") ) } + slots.child( + MobCatcherInventoryControlWidget(panel) + .pos(0, 0) + .name("mob_catcher_inventory_control") + .setEnabledIf { !panel.isSettingMode && !panel.isSearchViewActive() } + ) return slots } } @@ -56,7 +77,8 @@ class BackpackInventoryScrollWidget(panel: BackpackPanel) : override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { val theme = widgetTheme.theme - for (i in 0 until panel.backpackWrapper.backpackInventorySize()) { + panel.updateSearchLayout() + for (i in 0 until panel.searchVisibleSlotCount()) { RSBTextures.SLOT_BACKGROUND.draw( context, i % panel.rowSize * SLOT_SIZE, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt index e59e266..7fdf45c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt @@ -11,6 +11,7 @@ import com.cleanroommc.modularui.widgets.ButtonWidget import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.sync.BackpackSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault @@ -21,14 +22,14 @@ class BackpackMainSettingsWidget( private val panel: BackpackPanel, private val parentTabWidget: TabWidget ) : ExpandedTabWidget( - 2, + 3, RSBTextures.BACKPACK_SETTINGS_ICON, "gui.backpack_settings".asTranslationKey(), width = 93, expandDirection = ExpandDirection.RIGHT ) { private val contextButton = ContextButtonWidget(panel.backpackWrapper) - .pos(4, 20) + .pos(4, 24) .onMousePressed { if (it == 0) { panel.backpackWrapper.toggleSettingsContext() @@ -42,12 +43,14 @@ class BackpackMainSettingsWidget( val key = if (panel.backpackWrapper.settingsContext == BackpackWrapper.SettingsContext.PLAYER) "gui.settings_button.context_player.tooltip" else "gui.settings_button.context_backpack.tooltip" - it.addLine(IKey.lang(key.asTranslationKey())).pos(RichTooltip.Pos.NEXT_TO_MOUSE) + it.addLine(IKey.lang(key.asTranslationKey())) + .addLine(IKey.lang("${key}_detail".asTranslationKey()).style(IKey.GRAY)) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) } private val shiftClickButton = toggleButton( 4, - 42, + 52, { panel.backpackWrapper.shiftClickIntoOpenTab }, RSBTextures.SHIFT_CLICK_OPEN_TAB_ON, RSBTextures.SHIFT_CLICK_OPEN_TAB_OFF, @@ -57,7 +60,7 @@ class BackpackMainSettingsWidget( ) private val keepTabOpenButton = toggleButton( 26, - 42, + 52, { panel.backpackWrapper.keepTabOpen }, RSBTextures.KEEP_TAB_OPEN_ON, RSBTextures.KEEP_TAB_OPEN_OFF, @@ -67,7 +70,7 @@ class BackpackMainSettingsWidget( ) private val keepSearchPhraseButton = toggleButton( 48, - 42, + 52, { panel.backpackWrapper.keepSearchPhrase }, RSBTextures.KEEP_SEARCH_PHRASE_ON, RSBTextures.KEEP_SEARCH_PHRASE_OFF, @@ -77,7 +80,7 @@ class BackpackMainSettingsWidget( ) private val otherPlayerButton = toggleButton( 70, - 42, + 52, { panel.backpackWrapper.anotherPlayerCanOpen }, RSBTextures.ANOTHER_PLAYER_CAN_OPEN_ON, RSBTextures.ANOTHER_PLAYER_CAN_OPEN_OFF, @@ -91,7 +94,9 @@ class BackpackMainSettingsWidget( .child(shiftClickButton) .child(keepTabOpenButton) .child(keepSearchPhraseButton) - .child(otherPlayerButton) + if (Config.allowOpeningOtherPlayerBackpacks) { + child(otherPlayerButton) + } } override fun updateTabState() { @@ -125,6 +130,8 @@ class BackpackMainSettingsWidget( IKey.lang( "gui.settings_button.$tooltipName.${if (state()) "on" else "off"}".asTranslationKey() ) + ).addLine( + IKey.lang("gui.settings_button.$tooltipName.detail".asTranslationKey()).style(IKey.GRAY) ).pos(RichTooltip.Pos.NEXT_TO_MOUSE) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt index 4b39293..eb68f5a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt @@ -9,6 +9,7 @@ import com.cleanroommc.modularui.widgets.ButtonWidget import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraft.client.renderer.GlStateManager class CyclicVariantButtonWidget( private val variants: List, @@ -47,15 +48,18 @@ class CyclicVariantButtonWidget( } } - override fun draw(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { - if (hasCustomTexture) { - if (isHovering) { - hoveredTexture.draw(context, 0, 0, buttonWidth, buttonHeight, widgetTheme.getThemeOrDefault()) - } else { - notHoveredTexture.draw(context, 0, 0, buttonWidth, buttonHeight, widgetTheme.getThemeOrDefault()) + override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + if (hasCustomTexture || buttonWidth != 20 || buttonHeight != 20) { + val texture = when { + buttonWidth == 12 && buttonHeight == 12 && isHovering -> RSBTextures.SMALL_BUTTON_HOVERED + buttonWidth == 12 && buttonHeight == 12 -> RSBTextures.SMALL_BUTTON + isHovering -> hoveredTexture + else -> notHoveredTexture } + texture.draw(context, 0, 0, buttonWidth, buttonHeight, widgetTheme.getThemeOrDefault()) + } else { + super.drawBackground(context, widgetTheme) } - super.draw(context, widgetTheme) } override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { @@ -63,7 +67,9 @@ class CyclicVariantButtonWidget( val drawable = variants[index].drawable context?.let { + GlStateManager.color(1f, 1f, 1f, 1f) drawable.draw(context, iconOffset, iconOffset, iconSize, iconSize, widgetTheme.getThemeOrDefault()) + GlStateManager.color(1f, 1f, 1f, 1f) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt index 8db8983..0ee1543 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/DynamicIconButtonWidget.kt @@ -4,15 +4,24 @@ import com.cleanroommc.modularui.api.drawable.IDrawable import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraft.client.renderer.GlStateManager class DynamicIconButtonWidget( private val icon: () -> IDrawable, private val iconOffset: Int = 1, private val iconSize: Int = 16 ) : ButtonWidget() { + override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + val theme = widgetTheme.getThemeOrDefault() + if (isHovering) RSBTextures.STANDARD_BUTTON_HOVERED.draw(context, 0, 0, 18, 18, theme) + else RSBTextures.STANDARD_BUTTON.draw(context, 0, 0, 18, 18, theme) + } + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { - super.drawOverlay(context, widgetTheme) + GlStateManager.color(1f, 1f, 1f, 1f) icon().draw(context, iconOffset, iconOffset, iconSize, iconSize, widgetTheme.getThemeOrDefault()) + GlStateManager.color(1f, 1f, 1f, 1f) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt index 3d84012..b1ad863 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt @@ -66,7 +66,7 @@ class ItemDisplaySettingsWidget( .tooltipAutoUpdate(true) .tooltipDynamic { it.addLine(IKey.lang("gui.settings_button.item_display_color".asTranslationKey())) - .addLine(IKey.str(panel.backpackWrapper.itemDisplayColor.name.lowercase())) + .addLine(IKey.lang("gui.settings_button.item_display_color_detail".asTranslationKey()).style(IKey.GRAY)) .pos(RichTooltip.Pos.NEXT_TO_MOUSE) } @@ -96,7 +96,8 @@ class ItemDisplaySettingsWidget( .tooltipDynamic { it.addLine( IKey.lang("gui.settings_button.display_side_${panel.backpackWrapper.itemDisplaySide.serializedName}".asTranslationKey()) - ).pos(RichTooltip.Pos.NEXT_TO_MOUSE) + ).addLine(IKey.lang("gui.settings_button.display_side_detail".asTranslationKey()).style(IKey.GRAY)) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) } init { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt new file mode 100644 index 0000000..8fd9e88 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MobCatcherInventoryControlWidget.kt @@ -0,0 +1,536 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.layout.IViewportStack +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.drawable.GuiDraw +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widget.Widget +import com.cleanroommc.retrosophisticatedbackpacks.Tags +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.CapturedMob +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.BackpackPanel +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.handler.NetworkHandler +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SMobCatcherReleasePacket +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.OpenGlHelper +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.EntityList +import net.minecraft.util.ResourceLocation +import net.minecraft.util.text.TextFormatting +import org.lwjgl.opengl.GL11 +import kotlin.math.floor +import kotlin.math.max +import kotlin.math.min +import kotlin.math.sqrt + +class MobCatcherInventoryControlWidget(private val panel: BackpackPanel) : + Widget(), Interactable { + companion object { + private const val SLOT_SIZE = 18 + private const val CAPTURED_MOB_SLOT_OFFSET = 1 + private val GUI_CONTROLS = ResourceLocation(Tags.MOD_ID, "textures/gui/gui_controls.png") + private const val GUI_CONTROLS_TEXTURE_WIDTH = 256 + private const val GUI_CONTROLS_TEXTURE_HEIGHT = 256 + private const val CAPTURED_MOB_BACKGROUND_U = 29 + private const val CAPTURED_MOB_BACKGROUND_V = 30 + private const val CAPTURED_MOB_BACKGROUND_WIDTH = 18 + private const val CAPTURED_MOB_BACKGROUND_HEIGHT = 54 + private const val CAPTURED_MOB_BACKGROUND_COLOR = 0xFF2B2B2B.toInt() + private const val CAPTURED_MOB_BACKGROUND_LAYER_COLOR = 0x184A4A4A + private const val BODY_YAW_RANGE = 50f + private const val HEAD_STATIC_YAW_RANGE = 24f + private const val HEAD_IDLE_YAW_AMPLITUDE = 33f + private const val HEAD_STATIC_PITCH_RANGE = 6f + private const val HEAD_IDLE_PITCH_AMPLITUDE = 10f + private const val HEAD_IDLE_MIN_CYCLE_TICKS = 340f + private const val HEAD_IDLE_CYCLE_VARIATION_TICKS = 180f + private const val HEAD_IDLE_MOVE_TICKS = 30f + private const val HEAD_IDLE_HOLD_TICKS = 15f + } + + private val renderEntities = mutableMapOf() + + init { + size(panel.backpackSlotsWidth, panel.colSize * SLOT_SIZE) + tooltipAutoUpdate(true) + tooltipDynamic { tooltip -> + val hovered = hoveredCapturedMob(getContext().mouseX, getContext().mouseY) ?: return@tooltipDynamic + val entity = renderEntity(hovered) + tooltip.addLine(IKey.str(tooltipDisplayName(hovered, entity))) + tooltip.addLine( + IKey.lang("gui.mob_catcher.click_to_release".asTranslationKey()) + .style(TextFormatting.GRAY, TextFormatting.ITALIC) + ) + tooltip.addLine( + IKey.str( + "${TextFormatting.RED}\u2665 ${hovered.currentHealth}/${hovered.maxHealth}" + ) + ) + tooltip.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } + } + + override fun isInside(stack: IViewportStack, mx: Int, my: Int, absolute: Boolean): Boolean { + if (panel.isSearchViewActive()) + return false + + val x = if (absolute) stack.unTransformX(mx.toFloat(), my.toFloat()) else mx + val y = if (absolute) stack.unTransformY(mx.toFloat(), my.toFloat()) else my + return hoveredCapturedMob(x, y) != null + } + + override fun canHoverThrough(): Boolean = true + + override fun canClickThrough(): Boolean = true + + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (panel.isSearchViewActive()) + return Interactable.Result.IGNORE + + if (mouseButton != 0) { + return Interactable.Result.STOP + } + val capturedMob = hoveredCapturedMob(context.mouseX, context.mouseY) ?: return Interactable.Result.IGNORE + NetworkHandler.INSTANCE.sendToServer(C2SMobCatcherReleasePacket(capturedMob.id)) + Interactable.playButtonClickSound() + return Interactable.Result.SUCCESS + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + if (panel.isSearchViewActive()) + return + + panel.backpackWrapper.ensureCapturedMobLayoutCurrent() + val theme = widgetTheme.theme + val hoveredMob = hoveredCapturedMob(context.mouseX, context.mouseY) + val capturedMobs = MobCatcherStorage.getCapturedMobs(panel.backpackWrapper) + .filter { isValidBackpackSlot(it.slot) } + .map { capturedMob -> + CapturedMobRenderInfo( + capturedMob, + slotX(capturedMob.slot), + slotY(capturedMob.slot), + capturedMob.width * SLOT_SIZE, + capturedMob.height * SLOT_SIZE + ) + } + + for (renderInfo in capturedMobs) { + renderCapturedMobArea(renderInfo.x, renderInfo.y, renderInfo.capturedMob.width, renderInfo.capturedMob.height) + } + for (renderInfo in capturedMobs) { + renderEntity(renderInfo.capturedMob)?.let { entity -> + val state = EntityRenderState.capture(entity) + try { + prepareEntityForRender(entity, renderInfo.capturedMob, context) + val scale = getRenderScale(entity, renderInfo.width, renderInfo.height) + renderEntityInInventory( + renderInfo.x + renderInfo.width / 2, + getRenderBottomY(entity, renderInfo.y, renderInfo.height, scale), + scale, + entity, + context.partialTicks + ) + } finally { + state.restore(entity) + } + } + } + capturedMobs.firstOrNull { hoveredMob?.id == it.capturedMob.id }?.let { + RSBTextures.SOLID_DOWN_ARROW_ICON.draw(context, it.x + it.width - 14, it.y + it.height - 14, 12, 12, theme) + } + } + + private fun renderCapturedMobArea(x: Int, y: Int, widthSlots: Int, heightSlots: Int) { + val backgroundX = x - 1 + val backgroundY = y - 1 + val width = widthSlots * SLOT_SIZE + val height = heightSlots * SLOT_SIZE + renderTiledControlBackground( + backgroundX, + backgroundY, + width, + height, + CAPTURED_MOB_BACKGROUND_U, + CAPTURED_MOB_BACKGROUND_V, + CAPTURED_MOB_BACKGROUND_WIDTH, + CAPTURED_MOB_BACKGROUND_HEIGHT + ) + renderCapturedMobBackgroundLayers(backgroundX + 1, backgroundY + 1, width - 2, height - 2) + } + + private fun renderCapturedMobBackgroundLayers(x: Int, y: Int, width: Int, height: Int) { + GuiDraw.drawRect(x.toFloat(), y.toFloat(), width.toFloat(), height.toFloat(), CAPTURED_MOB_BACKGROUND_COLOR) + val layers = max(1, min(5, min(width, height) / 5)) + for (layer in 0 until layers) { + val insetX = 1 + layer * width / (layers * 3) + val insetY = 1 + layer * height / (layers * 3) + val alpha = 24 + layer * 12 + val color = (alpha shl 24) or (CAPTURED_MOB_BACKGROUND_LAYER_COLOR and 0x00FFFFFF) + GuiDraw.drawRect( + (x + insetX).toFloat(), + (y + insetY).toFloat(), + (width - insetX * 2).toFloat(), + (height - insetY * 2).toFloat(), + color + ) + } + restoreTexturedGuiState() + } + + private fun restoreTexturedGuiState() { + GlStateManager.enableTexture2D() + GlStateManager.enableAlpha() + GlStateManager.disableBlend() + GlStateManager.color(1f, 1f, 1f, 1f) + } + + private fun renderTiledControlBackground( + x: Int, + y: Int, + width: Int, + height: Int, + u: Int, + v: Int, + textureWidth: Int, + textureHeight: Int + ) { + val leftWidth = 1 + val topHeight = 1 + val rightWidth = min(1, width - leftWidth) + val bottomHeight = min(1, height - topHeight) + val sourceRightU = u + textureWidth - rightWidth + val sourceBottomV = v + textureHeight - bottomHeight + val centerWidth = width - leftWidth - rightWidth + val centerHeight = height - topHeight - bottomHeight + val sourceCenterWidth = textureWidth - leftWidth - rightWidth + val sourceCenterHeight = textureHeight - topHeight - bottomHeight + + GlStateManager.color(1f, 1f, 1f, 1f) + drawGuiControlsTexture(x, y, leftWidth, topHeight, u, v) + drawGuiControlsTexture(x + leftWidth + centerWidth, y, rightWidth, topHeight, sourceRightU, v) + drawGuiControlsTexture(x, y + topHeight + centerHeight, leftWidth, bottomHeight, u, sourceBottomV) + drawGuiControlsTexture( + x + leftWidth + centerWidth, + y + topHeight + centerHeight, + rightWidth, + bottomHeight, + sourceRightU, + sourceBottomV + ) + renderTiledTexture(x + leftWidth, y, centerWidth, topHeight, u + leftWidth, v, sourceCenterWidth, topHeight) + renderTiledTexture( + x + leftWidth, + y + topHeight + centerHeight, + centerWidth, + bottomHeight, + u + leftWidth, + sourceBottomV, + sourceCenterWidth, + bottomHeight + ) + renderTiledTexture(x, y + topHeight, leftWidth, centerHeight, u, v + topHeight, leftWidth, sourceCenterHeight) + renderTiledTexture( + x + leftWidth + centerWidth, + y + topHeight, + rightWidth, + centerHeight, + sourceRightU, + v + topHeight, + rightWidth, + sourceCenterHeight + ) + renderTiledTexture( + x + leftWidth, + y + topHeight, + centerWidth, + centerHeight, + u + leftWidth, + v + topHeight, + sourceCenterWidth, + sourceCenterHeight + ) + } + + private fun renderTiledTexture( + x: Int, + y: Int, + width: Int, + height: Int, + u: Int, + v: Int, + textureWidth: Int, + textureHeight: Int + ) { + if (width <= 0 || height <= 0 || textureWidth <= 0 || textureHeight <= 0) { + return + } + var renderedY = 0 + while (renderedY < height) { + val chunkHeight = min(textureHeight, height - renderedY) + var renderedX = 0 + while (renderedX < width) { + val chunkWidth = min(textureWidth, width - renderedX) + drawGuiControlsTexture(x + renderedX, y + renderedY, chunkWidth, chunkHeight, u, v) + renderedX += chunkWidth + } + renderedY += chunkHeight + } + } + + private fun drawGuiControlsTexture(x: Int, y: Int, width: Int, height: Int, u: Int, v: Int) { + if (width <= 0 || height <= 0) { + return + } + GuiDraw.drawTexture( + GUI_CONTROLS, + x.toFloat(), + y.toFloat(), + width.toFloat(), + height.toFloat(), + u, + v, + GUI_CONTROLS_TEXTURE_WIDTH, + GUI_CONTROLS_TEXTURE_HEIGHT + ) + } + + private fun renderEntityInInventory(posX: Int, posY: Float, scale: Int, entity: EntityLivingBase, partialTicks: Float) { + val renderManager = Minecraft.getMinecraft().renderManager + val previousViewY = renderManager.playerViewY + val previousShadow = renderManager.isRenderShadow + val previousBrightnessX = OpenGlHelper.lastBrightnessX + val previousBrightnessY = OpenGlHelper.lastBrightnessY + restoreTexturedGuiState() + GlStateManager.enableColorMaterial() + GlStateManager.enableDepth() + GlStateManager.pushMatrix() + try { + GlStateManager.translate(posX.toFloat(), posY, 50f) + GlStateManager.scale((-scale).toFloat(), scale.toFloat(), scale.toFloat()) + GlStateManager.rotate(180f, 0f, 0f, 1f) + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 220f, 220f) + enableFrontEntityLighting() + GlStateManager.disableCull() + renderManager.setPlayerViewY(180f) + renderManager.setRenderShadow(false) + renderManager.renderEntity(entity, 0.0, 0.0, 0.0, 0f, partialTicks, false) + } finally { + renderManager.setRenderShadow(previousShadow) + renderManager.setPlayerViewY(previousViewY) + GlStateManager.popMatrix() + GlStateManager.enableCull() + RenderHelper.disableStandardItemLighting() + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, previousBrightnessX, previousBrightnessY) + GlStateManager.disableRescaleNormal() + GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit) + GlStateManager.disableTexture2D() + GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit) + GlStateManager.disableDepth() + restoreTexturedGuiState() + } + } + + private fun enableFrontEntityLighting() { + GlStateManager.enableLighting() + GlStateManager.enableLight(0) + GlStateManager.enableLight(1) + GlStateManager.enableColorMaterial() + GlStateManager.colorMaterial(GL11.GL_FRONT_AND_BACK, GL11.GL_AMBIENT_AND_DIFFUSE) + setFrontEntityLight(GL11.GL_LIGHT0, 0f, 0.65f, 1f, 0.55f) + setFrontEntityLight(GL11.GL_LIGHT1, 0f, -0.25f, 1f, 0.35f) + GlStateManager.shadeModel(GL11.GL_FLAT) + GlStateManager.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, RenderHelper.setColorBuffer(0.32f, 0.32f, 0.32f, 1f)) + } + + private fun setFrontEntityLight(light: Int, x: Float, y: Float, z: Float, diffuse: Float) { + val length = sqrt((x * x + y * y + z * z).toDouble()).toFloat().takeIf { it > 0f } ?: 1f + GlStateManager.glLight(light, GL11.GL_POSITION, RenderHelper.setColorBuffer(x / length, y / length, z / length, 0f)) + GlStateManager.glLight(light, GL11.GL_DIFFUSE, RenderHelper.setColorBuffer(diffuse, diffuse, diffuse, 1f)) + GlStateManager.glLight(light, GL11.GL_AMBIENT, RenderHelper.setColorBuffer(0f, 0f, 0f, 1f)) + GlStateManager.glLight(light, GL11.GL_SPECULAR, RenderHelper.setColorBuffer(0f, 0f, 0f, 1f)) + } + + private fun hoveredCapturedMob(mouseX: Int, mouseY: Int): CapturedMob? { + panel.backpackWrapper.ensureCapturedMobLayoutCurrent() + return MobCatcherStorage.getCapturedMobs(panel.backpackWrapper).firstOrNull { capturedMob -> + if (!isValidBackpackSlot(capturedMob.slot)) { + return@firstOrNull false + } + val x = slotX(capturedMob.slot) - 1 + val y = slotY(capturedMob.slot) - 1 + mouseX >= x && mouseX < x + capturedMob.width * SLOT_SIZE && + mouseY >= y && mouseY < y + capturedMob.height * SLOT_SIZE + } + } + + private fun isValidBackpackSlot(slot: Int): Boolean = + slot in 0 until panel.backpackWrapper.backpackInventorySize() + + private fun slotX(slot: Int): Int = slot % panel.rowSize * SLOT_SIZE + CAPTURED_MOB_SLOT_OFFSET + + private fun slotY(slot: Int): Int = slot / panel.rowSize * SLOT_SIZE + CAPTURED_MOB_SLOT_OFFSET + + private fun renderEntity(capturedMob: CapturedMob): EntityLivingBase? { + renderEntities[capturedMob.id]?.let { return it } + val world = Minecraft.getMinecraft().world ?: return null + val entity = EntityList.createEntityByIDFromName(capturedMob.entityType, world) as? EntityLivingBase ?: return null + entity.readFromNBT(capturedMob.entityNbt.copy() as net.minecraft.nbt.NBTTagCompound) + renderEntities[capturedMob.id] = entity + return entity + } + + private fun tooltipDisplayName(capturedMob: CapturedMob, entity: EntityLivingBase?): String = + when { + entity == null -> capturedMob.displayName + entity.hasCustomName() -> entity.customNameTag + else -> entity.displayName.unformattedText + } + + private fun prepareEntityForRender(entity: EntityLivingBase, capturedMob: CapturedMob, context: ModularGuiContext) { + val renderTime = renderTime(capturedMob, context) + resetCapturedEntityVisualState(entity) + entity.setLocationAndAngles(0.0, 0.0, 0.0, 0f, 0f) + val bodyRot = (uuidFloat(capturedMob.id, 0) - 0.5f) * BODY_YAW_RANGE + val headOffset = -HEAD_STATIC_YAW_RANGE / 2f + uuidFloat(capturedMob.id, 1) * HEAD_STATIC_YAW_RANGE + + idlePoseOffset(capturedMob.id, renderTime, 0, HEAD_IDLE_YAW_AMPLITUDE) + val pitch = -HEAD_STATIC_PITCH_RANGE / 2f + uuidFloat(capturedMob.id, 2) * HEAD_STATIC_PITCH_RANGE + + idlePoseOffset(capturedMob.id, renderTime, 1, HEAD_IDLE_PITCH_AMPLITUDE) + entity.ticksExisted = renderTime.toInt() + entity.renderYawOffset = bodyRot + entity.prevRenderYawOffset = bodyRot + entity.rotationYaw = bodyRot + entity.prevRotationYaw = bodyRot + entity.rotationYawHead = bodyRot + headOffset + entity.prevRotationYawHead = entity.rotationYawHead + entity.rotationPitch = pitch + entity.prevRotationPitch = pitch + } + + private fun resetCapturedEntityVisualState(entity: EntityLivingBase) { + entity.hurtResistantTime = 0 + entity.hurtTime = 0 + entity.maxHurtTime = 0 + entity.deathTime = 0 + entity.attackedAtYaw = 0f + entity.limbSwing = 0f + entity.limbSwingAmount = 0f + entity.prevLimbSwingAmount = 0f + } + + private fun renderTime(capturedMob: CapturedMob, context: ModularGuiContext): Float { + val player = Minecraft.getMinecraft().player + val baseTime = player?.ticksExisted?.toFloat() ?: context.tick.toFloat() + return baseTime + context.partialTicks + uuidFloat(capturedMob.id, 3) * 200f + } + + private fun idlePoseOffset(uuid: java.util.UUID, renderTime: Float, salt: Int, amplitude: Float): Float { + val cycleLength = HEAD_IDLE_MIN_CYCLE_TICKS + uuidFloat(uuid, salt + 4) * HEAD_IDLE_CYCLE_VARIATION_TICKS + val cycle = floor(renderTime / cycleLength).toInt() + val phase = renderTime - cycle * cycleLength + val target = (cycleFloat(uuid, cycle, salt) - 0.5f) * 2f * amplitude + return when { + phase < HEAD_IDLE_MOVE_TICKS -> smoothStep(phase / HEAD_IDLE_MOVE_TICKS) * target + phase < HEAD_IDLE_MOVE_TICKS + HEAD_IDLE_HOLD_TICKS -> target + phase < HEAD_IDLE_MOVE_TICKS * 2f + HEAD_IDLE_HOLD_TICKS -> + (1f - smoothStep((phase - HEAD_IDLE_MOVE_TICKS - HEAD_IDLE_HOLD_TICKS) / HEAD_IDLE_MOVE_TICKS)) * target + else -> 0f + } + } + + private fun smoothStep(value: Float): Float = + value * value * (3f - 2f * value) + + private fun cycleFloat(uuid: java.util.UUID, cycle: Int, salt: Int): Float = + Math.floorMod(uuid.hashCode() * 31 + cycle * 131 + salt * 17, 1000) / 999f + + private fun uuidFloat(uuid: java.util.UUID, salt: Int): Float = + Math.floorMod(uuid.hashCode() + salt * 31, 1000) / 999f + + private fun getRenderScale(entity: EntityLivingBase, width: Int, height: Int): Int { + val entityWidth = max(entity.width, 0.25f) + val entityHeight = max(entity.height, 0.25f) + return max(8, (min((width - 6) / entityWidth, (height - 6) / entityHeight) * 0.5625f).toInt()) + } + + private fun getRenderBottomY(entity: EntityLivingBase, y: Int, height: Int, scale: Int): Float = + y + height / 2f + entity.height * scale / 2f + + private data class EntityRenderState( + val renderYawOffset: Float, + val prevRenderYawOffset: Float, + val rotationYaw: Float, + val prevRotationYaw: Float, + val rotationYawHead: Float, + val prevRotationYawHead: Float, + val rotationPitch: Float, + val prevRotationPitch: Float, + val ticksExisted: Int, + val hurtResistantTime: Int, + val hurtTime: Int, + val maxHurtTime: Int, + val deathTime: Int, + val attackedAtYaw: Float, + val limbSwing: Float, + val limbSwingAmount: Float, + val prevLimbSwingAmount: Float + ) { + fun restore(entity: EntityLivingBase) { + entity.renderYawOffset = renderYawOffset + entity.prevRenderYawOffset = prevRenderYawOffset + entity.rotationYaw = rotationYaw + entity.prevRotationYaw = prevRotationYaw + entity.rotationYawHead = rotationYawHead + entity.prevRotationYawHead = prevRotationYawHead + entity.rotationPitch = rotationPitch + entity.prevRotationPitch = prevRotationPitch + entity.ticksExisted = ticksExisted + entity.hurtResistantTime = hurtResistantTime + entity.hurtTime = hurtTime + entity.maxHurtTime = maxHurtTime + entity.deathTime = deathTime + entity.attackedAtYaw = attackedAtYaw + entity.limbSwing = limbSwing + entity.limbSwingAmount = limbSwingAmount + entity.prevLimbSwingAmount = prevLimbSwingAmount + } + + companion object { + fun capture(entity: EntityLivingBase): EntityRenderState = + EntityRenderState( + entity.renderYawOffset, + entity.prevRenderYawOffset, + entity.rotationYaw, + entity.prevRotationYaw, + entity.rotationYawHead, + entity.prevRotationYawHead, + entity.rotationPitch, + entity.prevRotationPitch, + entity.ticksExisted, + entity.hurtResistantTime, + entity.hurtTime, + entity.maxHurtTime, + entity.deathTime, + entity.attackedAtYaw, + entity.limbSwing, + entity.limbSwingAmount, + entity.prevLimbSwingAmount + ) + } + } + + private data class CapturedMobRenderInfo( + val capturedMob: CapturedMob, + val x: Int, + val y: Int, + val width: Int, + val height: Int + ) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt index 38c20cb..524e611 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt @@ -20,8 +20,8 @@ class SettingTabWidget : Widget(), Interactable { init { size(TAB_TEXTURE.width, TAB_TEXTURE.height) - .right(-TAB_TEXTURE.width + 4) - .top(4) + .right(-TAB_TEXTURE.width + 2) + .top(0) .background(TAB_TEXTURE.get(-1, false)) .tooltipStatic { it.addLine(IKey.lang("gui.settings".asTranslationKey())) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt index d31ce07..fa3e53d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt @@ -10,6 +10,7 @@ import com.cleanroommc.modularui.widget.SingleChildWidget import com.cleanroommc.modularui.widget.sizer.Unit import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.setEnabledIfAndEnabled +import net.minecraft.client.renderer.GlStateManager class TabWidget( private val tabIndex: Int, @@ -47,11 +48,11 @@ class TabWidget( var onToggle: ((Boolean) -> Unit)? = null init { - size(TAB_TEXTURE.width, TAB_TEXTURE.height).top({ 4.0 + tabOrder * 30.0 }, Unit.Measure.PIXEL) + size(TAB_TEXTURE.width, TAB_TEXTURE.height).top({ tabOrder * 30.0 }, Unit.Measure.PIXEL) when (expandDirection) { - ExpandDirection.LEFT -> left(-TAB_TEXTURE.width + 4) - ExpandDirection.RIGHT -> right(-TAB_TEXTURE.width + 4) + ExpandDirection.LEFT -> left(-TAB_TEXTURE.width - 2) + ExpandDirection.RIGHT -> right(-TAB_TEXTURE.width + 2) } } @@ -85,7 +86,9 @@ class TabWidget( if (showExpanded) return + GlStateManager.color(1f, 1f, 1f, 1f) tabIcon?.draw(context, 8, 6, 16, 16, widgetTheme.getThemeOrDefault()) + GlStateManager.color(1f, 1f, 1f, 1f) } override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TransferButtonWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TransferButtonWidget.kt index 4ba1be8..980931b 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TransferButtonWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TransferButtonWidget.kt @@ -5,17 +5,22 @@ import com.cleanroommc.modularui.api.widget.Interactable import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraft.client.renderer.GlStateManager class TransferButtonWidget(private val matchedIcon: IDrawable, private val allIcon: IDrawable) : ButtonWidget() { - override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { - super.drawOverlay(context, widgetTheme) + override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + val theme = widgetTheme.getThemeOrDefault() + if (isHovering) RSBTextures.SMALL_BUTTON_HOVERED.draw(context, 0, 0, 12, 12, theme) + else RSBTextures.SMALL_BUTTON.draw(context, 0, 0, 12, 12, theme) + } - if (Interactable.hasShiftDown()) { - allIcon.drawAtZero(context, area, widgetTheme.getThemeOrDefault()) - } else { - matchedIcon.drawAtZero(context, area, widgetTheme.getThemeOrDefault()) - } + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + GlStateManager.color(1f, 1f, 1f, 1f) + val icon = if (Interactable.hasShiftDown()) allIcon else matchedIcon + icon.draw(context, 0, 0, 12, 12, widgetTheme.getThemeOrDefault()) + GlStateManager.color(1f, 1f, 1f, 1f) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt index 0a8ec31..77f59ba 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/UpgradeSlotGroupWidget.kt @@ -72,11 +72,6 @@ class UpgradeSlotGroupWidget(private val panel: BackpackPanel, private val slotS ) LOWER_TAB_TEXTURE.draw(context, 0, heightWithoutBottom, 25, 6, widgetTheme.getThemeOrDefault()) - for (slot in 0 until slotSize) { - if (panel.backpackWrapper.upgradeItemStackHandler.getStackInSlot(slot).isEmpty) { - RSBTextures.EMPTY_UPGRADE_SLOT.draw(context, 6, 6 + slot * 16, 16, 16, widgetTheme.getThemeOrDefault()) - } - } } class UpgradeToggleWidget(private val panel: BackpackPanel, private val slotIndex: Int) : diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/VanillaTextFieldWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/VanillaTextFieldWidget.kt new file mode 100644 index 0000000..6ec8f81 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/VanillaTextFieldWidget.kt @@ -0,0 +1,146 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets + +import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.api.widget.IFocusedWidget +import com.cleanroommc.modularui.api.widget.Interactable +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.widget.Widget +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiTextField +import org.lwjgl.input.Keyboard + +abstract class VanillaTextFieldWidget>( + textY: Int, + textWidth: Int, + textHeight: Int +) : Widget(), Interactable, IFocusedWidget { + companion object { + private var focusedTextField: VanillaTextFieldWidget<*>? = null + + fun handleCommittedCharacter(character: Char): Boolean { + val focused = focusedTextField ?: return false + if (!focused.isFocused()) { + focusedTextField = null + return false + } + return focused.typeCharacter(character, 0) + } + } + + protected val textField = GuiTextField(0, Minecraft.getMinecraft().fontRenderer, 0, textY, textWidth, textHeight) + + init { + background(IDrawable.EMPTY) + textField.setEnableBackgroundDrawing(false) + textField.setCanLoseFocus(false) + } + + protected var text: String + get() = textField.text + set(value) { + if (textField.text != value) { + textField.setText(value) + } + } + + protected open fun textFieldX(): Int = 0 + + protected open fun textFieldY(): Int = 0 + + protected open fun textFieldWidth(): Int = area.width + + protected open fun textFieldHeight(): Int = area.height + + protected open fun mouseXForTextField(): Int = context.mouseX + + protected open fun mouseYForTextField(): Int = context.mouseY + + protected open fun onTextChanged(text: String) {} + + protected open fun onEditingFinished() {} + + protected open fun onFocusChanged(focused: Boolean) {} + + protected fun setTextColor(color: Int) { + textField.setTextColor(color) + } + + protected fun setDisabledTextColor(color: Int) { + textField.setDisabledTextColour(color) + } + + protected fun setMaxStringLength(length: Int) { + textField.setMaxStringLength(length) + } + + protected fun drawTextField() { + updateTextFieldBounds() + textField.drawTextBox() + } + + protected fun updateTextFieldBounds() { + textField.x = textFieldX() + textField.y = textFieldY() + textField.width = textFieldWidth().coerceAtLeast(1) + textField.height = textFieldHeight().coerceAtLeast(1) + } + + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (mouseButton != 0) { + return Interactable.Result.STOP + } + updateTextFieldBounds() + textField.setFocused(true) + textField.mouseClicked(mouseXForTextField(), mouseYForTextField(), mouseButton) + return Interactable.Result.SUCCESS + } + + override fun onKeyPressed(character: Char, keyCode: Int): Interactable.Result { + if (!isFocused()) { + return Interactable.Result.IGNORE + } + if (keyCode == Keyboard.KEY_ESCAPE || keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER) { + context.removeFocus() + return Interactable.Result.SUCCESS + } + + return if (typeCharacter(character, keyCode) || keyCode != Keyboard.KEY_TAB) { + Interactable.Result.SUCCESS + } else { + Interactable.Result.IGNORE + } + } + + private fun typeCharacter(character: Char, keyCode: Int): Boolean { + val oldText = textField.text + val handled = textField.textboxKeyTyped(character, keyCode) + if (textField.text != oldText) { + onTextChanged(textField.text) + } + return handled + } + + override fun onUpdate() { + super.onUpdate() + textField.updateCursorCounter() + } + + override fun isFocused(): Boolean = context.isFocused(this) + + override fun onFocus(context: ModularGuiContext) { + focusedTextField = this + textField.setFocused(true) + onFocusChanged(true) + Keyboard.enableRepeatEvents(true) + } + + override fun onRemoveFocus(context: ModularGuiContext) { + if (focusedTextField === this) { + focusedTextField = null + } + textField.setFocused(false) + onFocusChanged(false) + Keyboard.enableRepeatEvents(false) + onEditingFinished() + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt index 7627eaf..ae91681 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt @@ -52,8 +52,20 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa get() = panel.isSortingSettingTabOpened private val isInItemDisplaySettingMode: Boolean get() = panel.isItemDisplaySettingTabOpened + private val isBlockedByCapturedMob: Boolean + get() = wrapper.isSlotBlockedByMobCatcher(slot.slotIndex) + private val isHiddenBySearch: Boolean + get() = !panel.isSearchSlotVisible(slot.slotIndex) + + override fun onUpdate() { + super.onUpdate() + updateSearchPosition() + } override fun buildTooltip(stack: ItemStack, tooltip: RichTooltip) { + if (isBlockedByCapturedMob || isHiddenBySearch) + return + val memorizedStack = wrapper.getMemorizedStack(slot.slotIndex) if (stack.isEmpty && memorizedStack.isEmpty) @@ -105,6 +117,8 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa override fun onMousePressed(mouseButton: Int): Interactable.Result = when { + isBlockedByCapturedMob -> Interactable.Result.STOP + isHiddenBySearch -> Interactable.Result.STOP isInItemDisplaySettingMode -> handleItemDisplaySlotClick(mouseButton) isInMemorySettingMode -> handleMemorySlotClick(mouseButton) isInSortSettingMode -> handleSortSlotClick(mouseButton) @@ -114,10 +128,13 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa } override fun onMouseRelease(mouseButton: Int): Boolean = - if (isInSettingMode) true + if (isBlockedByCapturedMob || isHiddenBySearch || isInSettingMode) true else super.onMouseRelease(mouseButton) override fun onMouseDrag(mouseButton: Int, timeSinceClick: Long) { + if (isBlockedByCapturedMob || isHiddenBySearch) { + return + } if (isInMemorySettingMode) { handleMemorySlotClick(mouseButton) return @@ -203,6 +220,10 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa @SideOnly(Side.CLIENT) override fun draw(context: ModularGuiContext?, widgetThemeEntry: WidgetThemeEntry<*>?) { context?.let { + updateSearchPosition() + if (isBlockedByCapturedMob) + return + val widgetTheme = widgetThemeEntry?.theme ?: WidgetTheme.getDefault().theme if (isInSettingMode) { @@ -215,6 +236,9 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa if (wrapper.isSlotLocked(slot.slotIndex)) drawLockedSlot(it, widgetTheme) + if (isHiddenBySearch) + return + super.draw(context, widgetThemeEntry) if (slot.stack.isEmpty && !memoryStack.isEmpty) { @@ -226,6 +250,20 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa } } + private fun updateSearchPosition() { + if (!isSynced) + return + + val slotIndex = slot.slotIndex + val x = panel.searchSlotX(slotIndex) + val y = panel.searchSlotY(slotIndex) + if (area.rx == x && area.ry == y) + return + + area.rx = x + area.ry = y + } + private fun handleStashClick(): Boolean { val player = Minecraft.getMinecraft().player ?: return false val carried = player.inventory.itemStack diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt index b2234e6..fd670c3 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/NoBackgroundItemSlot.kt @@ -1,10 +1,20 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widgets.slot.ItemSlot +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault -open class NoBackgroundItemSlot : ItemSlot() { +open class NoBackgroundItemSlot(private val emptyOverlay: IDrawable? = null) : ItemSlot() { init { background(IDrawable.EMPTY) } + + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawOverlay(context, widgetTheme) + if (emptyOverlay != null && isSynced && slot.stack.isEmpty) { + emptyOverlay.draw(context, 1, 1, 16, 16, widgetTheme.getThemeOrDefault()) + } + } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFeedingUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFeedingUpgradeWidget.kt index d6ea881..4f2b6e6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFeedingUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFeedingUpgradeWidget.kt @@ -58,7 +58,7 @@ class AdvancedFeedingUpgradeWidget( } heartButtonWidget = CyclicVariantButtonWidget(HEART_VARIANTS, wrapper.healthFeedingStrategy.ordinal) { - wrapper.healthFeedingStrategy = AdvancedFeedingUpgradeWrapper.FeedingStrategy.HEALTH.entries[it] + wrapper.healthFeedingStrategy = AdvancedFeedingUpgradeWrapper.FeedingStrategy.Health.entries[it] updateWrapper() } @@ -76,4 +76,4 @@ class AdvancedFeedingUpgradeWidget( it.writeEnumValue(wrapper.healthFeedingStrategy) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt index f236917..f160ff7 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt @@ -215,7 +215,7 @@ class AdvancedFilterWidget( filterSlots = mutableListOf() val filterSlotCount = filterableWrapper.filterItems.slots - val slotsInRow = minOf(4, filterSlotCount) + val slotsInRow = if (filterSlotCount > 0) filterableWrapper.slotsInRow.coerceIn(1, filterSlotCount) else 1 for (i in 0 until filterSlotCount) { val slot = PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt index da98804..1e6ceb1 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AnvilUpgradeWidget.kt @@ -1,19 +1,25 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade +import com.cleanroommc.modularui.api.drawable.IDrawable import com.cleanroommc.modularui.api.drawable.IKey import com.cleanroommc.modularui.api.widget.Interactable -import com.cleanroommc.modularui.drawable.GuiDraw +import com.cleanroommc.modularui.drawable.ItemDrawable import com.cleanroommc.modularui.screen.RichTooltip import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetThemeEntry -import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.modularui.widget.Widget import com.cleanroommc.modularui.widgets.SlotGroupWidget -import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AnvilUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.VanillaTextFieldWidget import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.client.resources.I18n +import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack class AnvilUpgradeWidget( @@ -23,69 +29,124 @@ class AnvilUpgradeWidget( ) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 5, stack, wrapper.settingsLangKey, width = 103) { init { size(103, 92) - child(AnvilNameField().pos(5, 25).size(90, 15)) + child(AnvilNameField().pos(4, 24).size(90, 14)) val slots = SlotGroupWidget().name("anvil_$slotIndex").disableSortButtons() - slots.size(67, 18).pos(4, 43) + slots.size(56, 18).pos(3, 42) slots.child(NoBackgroundItemSlot().syncHandler("anvil_$slotIndex", 0).pos(0, 0)) - slots.child(NoBackgroundItemSlot().syncHandler("anvil_$slotIndex", 1).pos(49, 0)) + slots.child(NoBackgroundItemSlot().syncHandler("anvil_$slotIndex", 1).pos(38, 0)) child(slots) - child(resultButton().pos(80, 43)) - child(shiftClickButton().pos(5, 68)) + child(AnvilResultWidget().pos(79, 42)) } override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - RSBTextures.SLOT_BACKGROUND.draw(context, 4, 43, 18, 18, widgetTheme.theme) - RSBTextures.SLOT_BACKGROUND.draw(context, 53, 43, 18, 18, widgetTheme.theme) - RSBTextures.SLOT_BACKGROUND.draw(context, 80, 43, 18, 18, widgetTheme.theme) - RSBTextures.ADD_ICON.draw(context, 29, 45, 13, 13, widgetTheme.theme) - RSBTextures.DOWN_ARROW_ICON.draw(context, 68, 45, 12, 12, widgetTheme.theme) - GuiDraw.drawText("Cost: ${wrapper.maximumCost}", 5f, 62f, 0.75f, 0x404040, false) + val player = context.mc.player + val result = if (player == null) ItemStack.EMPTY else wrapper.updateRepairOutput(player, player.world) + val theme = widgetTheme.theme + val textFieldBackground = + if (wrapper.getInventory().getStackInSlot(0).isEmpty) RSBTextures.ANVIL_NAME_BACKGROUND_DISABLED + else RSBTextures.ANVIL_NAME_BACKGROUND + textFieldBackground.draw(context, 3, 23, 94, 16, theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 3, 42, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 41, 42, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 79, 42, 18, 18, widgetTheme.theme) + RSBTextures.ANVIL_PLUS_SIGN.draw(context, 25, 45, 13, 13, theme) + RSBTextures.ANVIL_ARROW.draw(context, 62, 44, 14, 15, theme) + if (!wrapper.getInventory().getStackInSlot(0).isEmpty && result.isEmpty) { + RSBTextures.ANVIL_RED_CROSS.draw(context, 62, 44, 15, 15, theme) + } + drawCost(player, result) super.draw(context, widgetTheme) } - private fun resultButton(): ButtonWidget<*> = - ButtonWidget() - .size(18) - .onMousePressed { - if (it != 0) false else { - slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_TAKE_RESULT) {} - true - } + private fun drawCost(player: EntityPlayer?, result: ItemStack) { + val cost = wrapper.maximumCost + if (cost <= 0) { + return + } + val tooExpensive = player != null && cost >= 40 && !player.capabilities.isCreativeMode + val text = when { + tooExpensive -> I18n.format("container.repair.expensive") + result.isEmpty -> return + else -> I18n.format("container.repair.cost", cost) + } + val color = if (tooExpensive || player?.let { !wrapper.canTakeResult(it) } == true) 16736352 else 8453920 + val font = Minecraft.getMinecraft().fontRenderer + val x = 3 + val y = 62 + val maxWidth = 94 + val lines = font.listFormattedStringToWidth(text, maxWidth) + Gui.drawRect(x, y, x + maxWidth, y + lines.size * 12, 1325400064) + var yOffset = 0 + for (line in lines) { + font.drawStringWithShadow(line, x + 2 + (maxWidth - font.getStringWidth(line)) / 2f, y + 2 + yOffset.toFloat(), color) + yOffset += 12 + } + } + + private inner class AnvilNameField : VanillaTextFieldWidget(3, 90, 12) { + init { + textField.setMaxStringLength(50) + textField.setText(wrapper.itemName) + textField.setTextColor(-1) + textField.setDisabledTextColour(-1) + } + + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + drawTextField() + } + + override fun onUpdate() { + super.onUpdate() + if (!isFocused() && textField.text != wrapper.itemName) { + textField.setText(wrapper.itemName) } - .tooltipDynamic { + } + + override fun onTextChanged(text: String) { + wrapper.itemName = text + } + + override fun onEditingFinished() { + wrapper.itemName = textField.text + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_ITEM_NAME) { it.writeString(wrapper.itemName) } + } + } + + private inner class AnvilResultWidget : Widget(), Interactable { + init { + size(18) + tooltipDynamic { val player = context.mc.player - val result = wrapper.updateRepairOutput(player, player.world) - if (result.isEmpty) it.addLine(IKey.lang("gui.anvil_no_result".asTranslationKey())) - else it.addLine(IKey.str(result.displayName)) + val result = if (player == null) ItemStack.EMPTY else wrapper.updateRepairOutput(player, player.world) + if (result.isEmpty) { + it.addLine(IKey.lang("gui.anvil_no_result".asTranslationKey())) + } else { + it.addLine(IKey.str(result.displayName)) + } it.pos(RichTooltip.Pos.NEXT_TO_MOUSE) - } + }.tooltipAutoUpdate(true) + } - private fun shiftClickButton(): ButtonWidget<*> = - ButtonWidget() - .size(20) - .overlay(if (wrapper.shouldShiftClickIntoStorage) RSBTextures.CHECK_ICON else RSBTextures.CROSS_ICON) - .onMousePressed { - if (it != 0) false else { - wrapper.shouldShiftClickIntoStorage = !wrapper.shouldShiftClickIntoStorage - slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_SHIFT_CLICK) {} - true - } + override fun onMousePressed(mouseButton: Int): Interactable.Result { + if (mouseButton != 0) { + return Interactable.Result.IGNORE } - .tooltipStatic { - it.addLine(IKey.lang("gui.anvil_shift_click_storage".asTranslationKey())) - it.pos(RichTooltip.Pos.NEXT_TO_MOUSE) + val player = context.mc.player ?: return Interactable.Result.IGNORE + if (wrapper.updateRepairOutput(player, player.world).isEmpty || !wrapper.canTakeResult(player)) { + return Interactable.Result.IGNORE } - - private inner class AnvilNameField : TextFieldWidget() { - init { - setText(wrapper.itemName) - setMaxLength(40) + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_TAKE_RESULT) {} + Interactable.playButtonClickSound() + return Interactable.Result.SUCCESS } - override fun onRemoveFocus(context: ModularGuiContext) { - super.onRemoveFocus(context) - wrapper.itemName = text - slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ANVIL_ITEM_NAME) { it.writeString(wrapper.itemName) } + override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + val player = context.mc.player ?: return + val result = wrapper.updateRepairOutput(player, player.world) + if (!result.isEmpty) { + ItemDrawable(result).draw(context, 1, 1, 16, 16, widgetTheme.getThemeOrDefault()) + } + super.draw(context, widgetTheme) } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt index 68594b4..13f473b 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt @@ -49,7 +49,7 @@ class BasicFilterWidget( filterSlots = mutableListOf() val filterSlotCount = filterableWrapper.filterItems.slots - val slotsInRow = minOf(3, filterSlotCount) + val slotsInRow = if (filterSlotCount > 0) filterableWrapper.slotsInRow.coerceIn(1, filterSlotCount) else 1 for (i in 0 until filterSlotCount) { val slot = PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt index 866fafe..3163bda 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BatteryUpgradeWidget.kt @@ -1,70 +1,30 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade -import com.cleanroommc.modularui.api.drawable.IKey -import com.cleanroommc.modularui.drawable.GuiDraw import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widgets.SlotGroupWidget -import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.BatteryUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot import net.minecraft.item.ItemStack -import net.minecraftforge.items.IItemHandler class BatteryUpgradeWidget( slotIndex: Int, wrapper: BatteryUpgradeWrapper, - stack: ItemStack, - private val backpackWrapper: BackpackWrapper + stack: ItemStack ) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 3, stack, wrapper.settingsLangKey, width = 48) { init { - size(48, 66) + size(48, 48) val slots = SlotGroupWidget().name("battery_$slotIndex").disableSortButtons() - slots.size(42, 18).pos(3, 42) - slots.child(NoBackgroundItemSlot().syncHandler("battery_$slotIndex", 0).pos(0, 0)) - slots.child(NoBackgroundItemSlot().syncHandler("battery_$slotIndex", 1).pos(21, 0)) + slots.size(42, 18).pos(3, 24) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_BATTERY_INPUT_SLOT).syncHandler("battery_$slotIndex", 0).pos(0, 0)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_BATTERY_OUTPUT_SLOT).syncHandler("battery_$slotIndex", 1).pos(21, 0)) child(slots) } override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { super.drawBackground(context, widgetTheme) - RSBTextures.SLOT_BACKGROUND.draw(context, 3, 42, 18, 18, widgetTheme.theme) - RSBTextures.SLOT_BACKGROUND.draw(context, 24, 42, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 3, 24, 18, 18, widgetTheme.theme) + RSBTextures.SLOT_BACKGROUND.draw(context, 24, 24, 18, 18, widgetTheme.theme) } - - override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - GuiDraw.drawText(energyText(wrapper), 4f, 26f, 0.5f, 0x404040, false) - super.draw(context, widgetTheme) - } - - override fun drawOverlay(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - super.drawOverlay(context, widgetTheme) - drawEmptySlotIcons(context, widgetTheme) - } - - private fun drawEmptySlotIcons(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - val inventory = wrapper.getInventory() - drawEmptySlotIcon(context, widgetTheme, inventory, 0, 4, 43, true) - drawEmptySlotIcon(context, widgetTheme, inventory, 1, 25, 43, false) - } - - private fun drawEmptySlotIcon( - context: ModularGuiContext, - widgetTheme: WidgetThemeEntry<*>, - inventory: IItemHandler, - slot: Int, - x: Int, - y: Int, - input: Boolean - ) { - if (!inventory.getStackInSlot(slot).isEmpty) { - return - } - (if (input) RSBTextures.EMPTY_BATTERY_INPUT_SLOT else RSBTextures.EMPTY_BATTERY_OUTPUT_SLOT) - .draw(context, x, y, 16, 16, widgetTheme.theme) - } - - private fun energyText(wrapper: BatteryUpgradeWrapper): String = - "${wrapper.energyStored}/${wrapper.getMaxEnergyStored(backpackWrapper)} FE" } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt index ee5b620..80bcbbd 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt @@ -9,12 +9,25 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpg import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RepeatMode import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack -class JukeboxUpgradeWidget(slotIndex: Int, wrapper: JukeboxUpgradeWrapper, stack: ItemStack, private val slots: Int) : - ExpandedUpgradeTabWidget(slotIndex, wrapper, if (slots > 4) 5 else 4, stack, wrapper.settingsLangKey, width = if (slots > 4) 112 else 80) { +class JukeboxUpgradeWidget( + slotIndex: Int, + wrapper: JukeboxUpgradeWrapper, + stack: ItemStack, + private val slots: Int, + private val slotsInRow: Int = if (slots > 1) Config.advancedJukeboxUpgrade.slotsInRow.coerceIn(1, slots) else 1 +) : ExpandedUpgradeTabWidget( + slotIndex, + wrapper, + if (slots > 4) 5 else 4, + stack, + wrapper.settingsLangKey, + width = if (slots > 4) 112 else 80 +) { companion object { private const val SLOT_SIZE = 18 } @@ -32,7 +45,7 @@ class JukeboxUpgradeWidget(slotIndex: Int, wrapper: JukeboxUpgradeWrapper, stack val discs = SlotGroupWidget().name("jukebox_discs_$slotIndex").disableSortButtons() discs.flex().coverChildren().leftRel(0.5F).top(if (slots > 4) 74 else 72) repeat(slots) { - discs.child(ItemSlot().syncHandler("jukebox_discs_$slotIndex", it).pos(it % 4 * SLOT_SIZE, it / 4 * SLOT_SIZE)) + discs.child(ItemSlot().syncHandler("jukebox_discs_$slotIndex", it).pos(it % slotsInRow * SLOT_SIZE, it / slotsInRow * SLOT_SIZE)) } child(discs) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt index d86b1cc..4ee869a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/PumpUpgradeWidget.kt @@ -8,9 +8,9 @@ import com.cleanroommc.modularui.screen.RichTooltip import com.cleanroommc.modularui.screen.viewport.ModularGuiContext import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widget.Widget -import com.cleanroommc.modularui.widgets.ButtonWidget import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.PumpUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.DynamicIconButtonWidget import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault @@ -23,7 +23,7 @@ open class PumpUpgradeWidget( ) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 3, stack, wrapper.settingsLangKey, width = 48) { init { size(48, 50) - child(toggleButton({ wrapper.isInput }, RSBTextures.PUMP_INPUT_ICON, RSBTextures.PUMP_OUTPUT_ICON, "gui.pump_input".asTranslationKey()) { + child(toggleButton({ wrapper.isInput }, RSBTextures.PUMP_INPUT_ICON, RSBTextures.PUMP_OUTPUT_ICON, "gui.pump_input", "gui.pump_output") { wrapper.isInput = !wrapper.isInput slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_INPUT) { it.writeBoolean(wrapper.isInput) } }.pos(3, 24)) @@ -33,19 +33,26 @@ open class PumpUpgradeWidget( state: () -> Boolean, enabledIcon: IDrawable, disabledIcon: IDrawable, - tooltip: String, + enabledTooltip: String, + disabledTooltip: String, action: () -> Unit - ): ButtonWidget<*> = - ButtonWidget() - .size(20) - .overlay(if (state()) enabledIcon else disabledIcon) + ): DynamicIconButtonWidget = + DynamicIconButtonWidget({ if (state()) enabledIcon else disabledIcon }) + .size(18) .onMousePressed { if (it != 0) false else { action() + Interactable.playButtonClickSound() true } } - .tooltipStatic { it.addLine(IKey.lang(tooltip)).pos(RichTooltip.Pos.NEXT_TO_MOUSE) } + .tooltipAutoUpdate(true) + .tooltipDynamic { + val key = if (state()) enabledTooltip else disabledTooltip + it.addLine(IKey.lang(key.asTranslationKey())) + .addLine(IKey.lang("${key}_detail".asTranslationKey()).style(IKey.GRAY)) + .pos(RichTooltip.Pos.NEXT_TO_MOUSE) + } } class AdvancedPumpUpgradeWidget(slotIndex: Int, wrapper: PumpUpgradeWrapper, stack: ItemStack) : @@ -53,20 +60,20 @@ class AdvancedPumpUpgradeWidget(slotIndex: Int, wrapper: PumpUpgradeWrapper, sta init { size(84, 82) width(84) - child(toggleButton({ wrapper.interactWithFluidHandlers }, RSBTextures.PUMP_FLUID_HANDLER_ICON, RSBTextures.PUMP_NO_FLUID_HANDLER_ICON, "gui.pump_fluid_handlers".asTranslationKey()) { + child(toggleButton({ wrapper.interactWithFluidHandlers }, RSBTextures.PUMP_FLUID_HANDLER_ICON, RSBTextures.PUMP_NO_FLUID_HANDLER_ICON, "gui.pump_fluid_handlers", "gui.pump_no_fluid_handlers") { wrapper.interactWithFluidHandlers = !wrapper.interactWithFluidHandlers slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_FLUID_HANDLERS) {} }.pos(21, 24)) - child(toggleButton({ wrapper.interactWithWorld }, RSBTextures.PUMP_WORLD_ICON, RSBTextures.PUMP_NO_WORLD_ICON, "gui.pump_world".asTranslationKey()) { + child(toggleButton({ wrapper.interactWithWorld }, RSBTextures.PUMP_WORLD_ICON, RSBTextures.PUMP_NO_WORLD_ICON, "gui.pump_world", "gui.pump_no_world") { wrapper.interactWithWorld = !wrapper.interactWithWorld slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_WORLD) {} }.pos(39, 24)) - child(toggleButton({ wrapper.interactWithHand }, RSBTextures.PUMP_HAND_ICON, RSBTextures.PUMP_NO_HAND_ICON, "gui.pump_hand".asTranslationKey()) { + child(toggleButton({ wrapper.interactWithHand }, RSBTextures.PUMP_HAND_ICON, RSBTextures.PUMP_NO_HAND_ICON, "gui.pump_hand", "gui.pump_no_hand") { wrapper.interactWithHand = !wrapper.interactWithHand slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_PUMP_HAND) {} }.pos(57, 24)) for (slot in wrapper.fluidFilters.indices) { - child(FluidFilterSlotWidget(slot, wrapper).pos(3 + slot * 18, 50)) + child(FluidFilterSlotWidget(slot, wrapper).pos(3 + slot * 18, 44)) } } @@ -79,6 +86,7 @@ class AdvancedPumpUpgradeWidget(slotIndex: Int, wrapper: PumpUpgradeWrapper, sta tooltipDynamic { val fluid = pumpWrapper.fluidFilters.getOrNull(filterSlot) it.addLine(if (fluid == null) IKey.lang("gui.none".asTranslationKey()) else IKey.str(fluid.localizedName)) + it.addLine(IKey.lang("gui.pump_fluid_filter_detail".asTranslationKey()).style(IKey.GRAY)) it.pos(RichTooltip.Pos.NEXT_TO_MOUSE) }.tooltipAutoUpdate(true) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt index 05c97d0..44059be 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/TankUpgradeWidget.kt @@ -7,7 +7,6 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.TankUpgrad import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot import net.minecraft.item.ItemStack -import net.minecraftforge.items.IItemHandler class TankUpgradeWidget(slotIndex: Int, wrapper: TankUpgradeWrapper, stack: ItemStack) : ExpandedUpgradeTabWidget(slotIndex, wrapper, 3, stack, wrapper.settingsLangKey, width = 48) { @@ -16,8 +15,8 @@ class TankUpgradeWidget(slotIndex: Int, wrapper: TankUpgradeWrapper, stack: Item val slots = SlotGroupWidget().name("tank_$slotIndex").disableSortButtons() slots.size(42, 50).pos(3, 24) - slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 0).pos(0, 0)) - slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 1).pos(21, 0)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_TANK_INPUT_SLOT).syncHandler("tank_$slotIndex", 0).pos(0, 0)) + slots.child(NoBackgroundItemSlot(RSBTextures.EMPTY_TANK_OUTPUT_SLOT).syncHandler("tank_$slotIndex", 1).pos(21, 0)) slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 2).pos(0, 32)) slots.child(NoBackgroundItemSlot().syncHandler("tank_$slotIndex", 3).pos(21, 32)) child(slots) @@ -32,33 +31,4 @@ class TankUpgradeWidget(slotIndex: Int, wrapper: TankUpgradeWrapper, stack: Item RSBTextures.TANK_ARROW.draw(context, 4, 45, 15, 8, widgetTheme.theme) RSBTextures.TANK_ARROW.draw(context, 25, 45, 15, 8, widgetTheme.theme) } - - override fun drawOverlay(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - super.drawOverlay(context, widgetTheme) - drawEmptySlotIcons(context, widgetTheme) - } - - private fun drawEmptySlotIcons(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { - val inventory = wrapper.getInventory() - drawEmptySlotIcon(context, widgetTheme, inventory, 0, 4, 25, true) - drawEmptySlotIcon(context, widgetTheme, inventory, 1, 25, 25, false) - drawEmptySlotIcon(context, widgetTheme, inventory, 2, 4, 57, true) - drawEmptySlotIcon(context, widgetTheme, inventory, 3, 25, 57, false) - } - - private fun drawEmptySlotIcon( - context: ModularGuiContext, - widgetTheme: WidgetThemeEntry<*>, - inventory: IItemHandler, - slot: Int, - x: Int, - y: Int, - input: Boolean - ) { - if (!inventory.getStackInSlot(slot).isEmpty) { - return - } - (if (input) RSBTextures.EMPTY_TANK_INPUT_SLOT else RSBTextures.EMPTY_TANK_OUTPUT_SLOT) - .draw(context, x, y, 16, 16, widgetTheme.theme) - } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt index 39cb5bd..2ab38d4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularBackpackSlot.kt @@ -12,8 +12,11 @@ class ModularBackpackSlot( wrapper.getMemorizedStack(slotIndex) override fun getSlotStackLimit(): Int = - Int.MAX_VALUE + if (wrapper.isSlotBlockedByMobCatcher(slotIndex)) 0 else Int.MAX_VALUE override fun getItemStackLimit(stack: ItemStack): Int = - stack.maxStackSize * wrapper.getTotalStackMultiplier() -} \ No newline at end of file + if (wrapper.isSlotBlockedByMobCatcher(slotIndex)) 0 else wrapper.getStackLimit(stack) + + override fun isItemValid(stack: ItemStack): Boolean = + !wrapper.isSlotBlockedByMobCatcher(slotIndex) && super.isItemValid(stack) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt index 485e0c1..2ebf60a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/slot/ModularUpgradeSlot.kt @@ -8,6 +8,10 @@ import com.cleanroommc.retrosophisticatedbackpacks.item.InceptionUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.StackUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.UpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.item.BatteryUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.item.MobCatcherUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.item.TankUpgradeItem +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack @@ -43,16 +47,50 @@ class ModularUpgradeSlot( else true } + if (originalUpgradeItem is MobCatcherUpgradeItem) { + if (wrapper.capturedMobs.isEmpty()) { + return true + } + return newUpgradeItem is MobCatcherUpgradeItem && + (newUpgradeItem.advanced || MobCatcherStorage.canFitBasicTier(wrapper, Config.mobCatcherUpgrade.basicMaxSlotCost)) + } + return true } override fun getItemStackLimit(stack: ItemStack): Int = 1 - override fun isItemValid(stack: ItemStack): Boolean = when (val item = stack.item) { - is StackUpgradeItem -> wrapper.canAddStackUpgrade(item.multiplier()) - is ExponentialStackUpgradeItem -> wrapper.canAddExponentialStackUpgrade() - is BatteryUpgradeItem -> wrapper.canAddBatteryUpgrade() - else -> item is UpgradeItem + override fun isItemValid(stack: ItemStack): Boolean { + val item = stack.item as? UpgradeItem ?: return false + if (!canFitConfiguredUpgradeLimit(item)) { + return false + } + return when (item) { + is StackUpgradeItem -> wrapper.canAddStackUpgrade(item.multiplier()) + is ExponentialStackUpgradeItem -> wrapper.canAddExponentialStackUpgrade() + is TankUpgradeItem -> MobCatcherStorage.canFitWithAdditionalInventoryControls( + wrapper, + if (this.stack.item is TankUpgradeItem || wrapper.tankUpgradeSlots().size >= 2) 0 else 1 + ) + is BatteryUpgradeItem -> (this.stack.item is BatteryUpgradeItem || wrapper.canAddBatteryUpgrade()) && + MobCatcherStorage.canFitWithAdditionalInventoryControls( + wrapper, + if (this.stack.item is BatteryUpgradeItem || wrapper.hasBatteryUpgrade()) 0 else 1 + ) + is MobCatcherUpgradeItem -> this.stack.item is MobCatcherUpgradeItem || wrapper.canAddMobCatcherUpgrade() + else -> true + } + } + + private fun canFitConfiguredUpgradeLimit(item: UpgradeItem): Boolean { + val (limitKey, max) = Config.getUpgradeLimit(item) ?: return true + val currentItem = stack.item as? UpgradeItem + val currentCount = wrapper.upgradeItemStackHandler.inventory.count { + val upgrade = it.item as? UpgradeItem ?: return@count false + Config.matchesUpgradeLimit(upgrade, limitKey) + } + val replacingSameLimit = currentItem != null && Config.matchesUpgradeLimit(currentItem, limitKey) + return currentCount - (if (replacingSameLimit) 1 else 0) < max } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/BackpackSubtypeInterpreter.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/BackpackSubtypeInterpreter.kt new file mode 100644 index 0000000..f580cb2 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/BackpackSubtypeInterpreter.kt @@ -0,0 +1,12 @@ +package com.cleanroommc.retrosophisticatedbackpacks.compat.jei + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import mezz.jei.api.ISubtypeRegistry +import net.minecraft.item.ItemStack + +object BackpackSubtypeInterpreter : ISubtypeRegistry.ISubtypeInterpreter { + override fun apply(itemStack: ItemStack): String { + val capability = itemStack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return "" + return "mainColor:${capability.mainColor};accentColor:${capability.accentColor}" + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/RetroSophisticatedBackpacksJEIPlugin.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/RetroSophisticatedBackpacksJEIPlugin.kt new file mode 100644 index 0000000..5fed4d3 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/jei/RetroSophisticatedBackpacksJEIPlugin.kt @@ -0,0 +1,27 @@ +package com.cleanroommc.retrosophisticatedbackpacks.compat.jei + +import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackCraftingTransferInfo +import com.cleanroommc.retrosophisticatedbackpacks.item.Items +import mezz.jei.api.* + +@JEIPlugin +class RetroSophisticatedBackpacksJEIPlugin : IModPlugin { + companion object { + lateinit var helpers: IJeiHelpers + } + + override fun registerItemSubtypes(subtypeRegistry: ISubtypeRegistry) { + for (backpack in Items.BACKPACK_ITEMS) { + subtypeRegistry.registerSubtypeInterpreter(backpack, BackpackSubtypeInterpreter) + } + } + + override fun register(registry: IModRegistry) { + helpers = registry.jeiHelpers + + // By hijacking vanilla recipe types + // We can utilize JEI's built-in recipe transfer handler + val recipeTransferRegistry = registry.recipeTransferRegistry + recipeTransferRegistry.addRecipeTransferHandler(BackpackCraftingTransferInfo()) + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/theoneprobe/OneProbePlugin.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/theoneprobe/OneProbePlugin.kt new file mode 100644 index 0000000..4ef6b7c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/compat/theoneprobe/OneProbePlugin.kt @@ -0,0 +1,53 @@ +package com.cleanroommc.retrosophisticatedbackpacks.compat.theoneprobe + +import com.cleanroommc.retrosophisticatedbackpacks.Tags +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity +import com.google.common.base.Function +import mcjty.theoneprobe.Tools +import mcjty.theoneprobe.api.* +import mcjty.theoneprobe.config.Config +import net.minecraft.block.state.IBlockState +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.world.World + +class OneProbePlugin : Function { + override fun apply(input: ITheOneProbe?): Void? { + input?.registerBlockDisplayOverride(BackpackBlockDisplayOverride) + return null + } + + object BackpackBlockDisplayOverride : IBlockDisplayOverride { + override fun overrideStandardInfo( + mode: ProbeMode, + info: IProbeInfo, + player: EntityPlayer, + world: World, + state: IBlockState, + data: IProbeHitData + ): Boolean { + val te = world.getTileEntity(data.pos) as? BackpackTileEntity ?: return false + val teWrapper = te.wrapper + val stack = ItemStack(state.block, 1) + val stackWrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return false + stackWrapper.mainColor = teWrapper.mainColor + stackWrapper.accentColor = teWrapper.accentColor + + if (Tools.show(mode, Config.getRealConfig().showModName)) { + info.horizontal() + .item(stack) + .vertical() + .itemLabel(stack) + .text("${TextStyleClass.MODNAME}${Tags.MOD_ID}") + } else { + info.horizontal() + .item(stack) + .vertical() + .itemLabel(stack) + } + + return true + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt index 8061f23..2182bd4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/config/Config.kt @@ -1,14 +1,51 @@ package com.cleanroommc.retrosophisticatedbackpacks.config import com.cleanroommc.retrosophisticatedbackpacks.Tags +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem +import com.cleanroommc.retrosophisticatedbackpacks.item.UpgradeItem +import net.minecraft.block.Block +import net.minecraft.item.ItemStack import net.minecraftforge.common.config.Config +import net.minecraftforge.items.CapabilityItemHandler @Config(modid = Tags.MOD_ID, name = "${Tags.MOD_ID}_general") object Config { @JvmField - @Config.Comment("Items that cannot be stored in backpack") + @Config.Comment("List of items that are not allowed to be put in backpacks - e.g. \"minecraft:shulker_box\"") + var disallowedItems = arrayOf("minecraft:shulker_box") + + @JvmField + @Config.Comment("Determines if container items are able to fit in backpacks") + var containerItemsDisallowed = false + + @JvmField + @Config.Comment("List of blocks that inventory interaction upgrades can't interact with - e.g. \"minecraft:shulker_box\"") + var noInteractionBlocks = arrayOf("minecraft:shulker_box") + + @JvmField + @Config.Comment("List of blocks that are not allowed to connect to backpacks - e.g. \"refinedstorage:external_storage\"") + var noConnectionBlocks = arrayOf() + + @JvmField + @Config.Comment("If true, disallows all blocks from connecting to backpacks") + var allBlockConnectionsDisallowed = false + + @JvmField + @Config.Comment("Turns on/off item fluid handler of backpack in its item form") + var itemFluidHandlerEnabled = true + + @JvmField + @Config.Comment("Determines whether player can right click on backpack that another player is wearing to open it") + var allowOpeningOtherPlayerBackpacks = true + + @JvmField + @Config.Comment("Allows disabling item display settings") @Config.RequiresMcRestart - var blacklistedItems = arrayOf() + var itemDisplayDisabled = false + + @JvmField + @Config.Comment("Allows disabling logic that dedupes backpacks with the same UUID in players' inventory") + var tickDedupeLogicDisabled = false @JvmField val leatherBackpack = LeatherBackpackConfig() @@ -28,54 +65,167 @@ object Config { @JvmField val stackUpgrade = StackUpgradeConfig() + @JvmField + val compactingUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedCompactingUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val depositUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedDepositUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val feedingUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedFeedingUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val filterUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedFilterUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val magnetUpgrade = MagnetUpgradeConfig(9, 3, 3) + + @JvmField + val advancedMagnetUpgrade = MagnetUpgradeConfig(16, 4, 5) + + @JvmField + val pickupUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedPickupUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val refillUpgrade = FilteredUpgradeConfig(6, 3) + + @JvmField + val advancedRefillUpgrade = FilteredUpgradeConfig(12, 4) + + @JvmField + val restockUpgrade = FilteredUpgradeConfig(9, 3) + + @JvmField + val advancedRestockUpgrade = FilteredUpgradeConfig(16, 4) + + @JvmField + val voidUpgrade = VoidUpgradeConfig(9, 3) + + @JvmField + val advancedVoidUpgrade = VoidUpgradeConfig(16, 4) + + @JvmField + val toolSwapperUpgrade = FilteredUpgradeConfig(8, 4) + + @JvmField + val tankUpgrade = TankUpgradeConfig() + + @JvmField + val batteryUpgrade = BatteryUpgradeConfig() + + @JvmField + val pumpUpgrade = PumpUpgradeConfig() + + @JvmField + val advancedJukeboxUpgrade = JukeboxUpgradeConfig(12) + + @JvmField + val mobCatcherUpgrade = MobCatcherUpgradeConfig() + + @JvmField + val maxUpgradesPerStorage = MaxUpgradesPerStorageConfig() + + fun isItemDisallowed(stack: ItemStack): Boolean { + val registryName = stack.item.registryName?.toString() ?: return false + if (registryName in disallowedItems) { + return true + } + return containerItemsDisallowed && + stack.item !is BackpackItem && + stack.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null) + } + + fun canStackWithStackUpgrade(stack: ItemStack): Boolean { + val registryName = stack.item.registryName?.toString() ?: return true + return registryName !in stackUpgrade.nonStackableItems + } + + fun isInteractionBlockDisallowed(block: Block): Boolean = + block.registryName?.toString() in noInteractionBlocks + + fun isConnectionBlockDisallowed(block: Block): Boolean = + allBlockConnectionsDisallowed || block.registryName?.toString() in noConnectionBlocks + + fun getUpgradeLimit(upgradeItem: UpgradeItem): Pair? { + val limits = maxUpgradesPerStorage.maxUpgradesPerStorage.mapNotNull { + val parts = it.split("|", limit = 2) + val max = parts.getOrNull(1)?.toIntOrNull() ?: return@mapNotNull null + parts[0] to max + }.toMap() + val registryPath = upgradeItem.registryName?.path + if (registryPath != null && registryPath in limits) { + return registryPath to limits.getValue(registryPath) + } + val group = upgradeItem.upgradeGroup + return if (group != null && group in limits) group to limits.getValue(group) else null + } + + fun matchesUpgradeLimit(upgradeItem: UpgradeItem, limitKey: String): Boolean = + upgradeItem.registryName?.path == limitKey || upgradeItem.upgradeGroup == limitKey + class LeatherBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 27 + var inventorySlotCount = 27 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 1 + var upgradeSlotCount = 1 } class IronBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 54 + var inventorySlotCount = 54 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 2 + var upgradeSlotCount = 2 } class GoldBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 81 + var inventorySlotCount = 81 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 3 + var upgradeSlotCount = 3 } class DiamondBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 108 + var inventorySlotCount = 108 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 5 + var upgradeSlotCount = 5 } class ObsidianBackpackConfig { @JvmField @Config.RequiresMcRestart - var slots = 120 + var inventorySlotCount = 120 @JvmField @Config.RequiresMcRestart - var upgradeSlots = 7 + var upgradeSlotCount = 7 } class StackUpgradeConfig { @@ -98,5 +248,135 @@ object Config { @JvmField @Config.RequiresMcRestart var obsidianMultiplier = 32 + + @JvmField + var nonStackableItems = arrayOf( + "minecraft:shulker_box", + "minecraft:white_shulker_box", + "minecraft:orange_shulker_box", + "minecraft:magenta_shulker_box", + "minecraft:light_blue_shulker_box", + "minecraft:yellow_shulker_box", + "minecraft:lime_shulker_box", + "minecraft:pink_shulker_box", + "minecraft:gray_shulker_box", + "minecraft:silver_shulker_box", + "minecraft:cyan_shulker_box", + "minecraft:purple_shulker_box", + "minecraft:blue_shulker_box", + "minecraft:brown_shulker_box", + "minecraft:green_shulker_box", + "minecraft:red_shulker_box", + "minecraft:black_shulker_box" + ) + } + + open class FilteredUpgradeConfig(defaultFilterSlots: Int, defaultSlotsInRow: Int) { + @JvmField + var filterSlots = defaultFilterSlots + + @JvmField + var slotsInRow = defaultSlotsInRow + } + + class MagnetUpgradeConfig(defaultFilterSlots: Int, defaultSlotsInRow: Int, defaultMagnetRange: Int) { + @JvmField + var filterSlots = defaultFilterSlots + + @JvmField + var slotsInRow = defaultSlotsInRow + + @JvmField + var magnetRange = defaultMagnetRange + } + + class VoidUpgradeConfig(defaultFilterSlots: Int, defaultSlotsInRow: Int) { + @JvmField + var filterSlots = defaultFilterSlots + + @JvmField + var slotsInRow = defaultSlotsInRow + + @JvmField + var voidAlwaysEnabled = true + } + + class TankUpgradeConfig { + @JvmField + var capacityPerSlotRow = 4000 + + @JvmField + var stackMultiplierRatio = 1.0 + + @JvmField + var autoFillDrainContainerCooldown = 20 + + @JvmField + var maxInputOutput = 20 + } + + class BatteryUpgradeConfig { + @JvmField + var energyPerSlotRow = 10000 + + @JvmField + var stackMultiplierRatio = 1.0 + + @JvmField + var maxInputOutput = 20 + } + + class PumpUpgradeConfig { + @JvmField + var filterSlots = 4 + + @JvmField + var maxInputOutput = 20 + + @JvmField + var stackMultiplierRatio = 1.0 + } + + class JukeboxUpgradeConfig(defaultNumberOfSlots: Int) { + @JvmField + var numberOfSlots = defaultNumberOfSlots + + @JvmField + var slotsInRow = 4 + } + + class MobCatcherUpgradeConfig { + @JvmField + var basicMaxSlotCost = 18 + + @JvmField + var advancedMaxSlotCost = 72 + + @JvmField + var animalMultiplier = 1.0 + + @JvmField + var hostileMultiplier = 2.0 + + @JvmField + var disallowInventoryEntities = false + + @JvmField + var entityBlockList = arrayOf("minecraft:wither") + + @JvmField + var hostileOverrides = arrayOf("minecraft:enderman") + + @JvmField + var passiveOverrides = arrayOf("minecraft:villager") + } + + class MaxUpgradesPerStorageConfig { + @JvmField + var maxUpgradesPerStorage = arrayOf( + "stack|3", + "cooking|1", + "jukebox|1" + ) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/DyeingRecipeRegistry.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/DyeingRecipeRegistry.kt index 940fd7a..07eefcd 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/DyeingRecipeRegistry.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/DyeingRecipeRegistry.kt @@ -11,6 +11,25 @@ import net.minecraft.util.ResourceLocation import net.minecraftforge.common.crafting.CraftingHelper object DyeingRecipeRegistry { + private val DYES: Array = arrayOf( + "Black", + "Red", + "Green", + "Brown", + "Blue", + "Purple", + "Cyan", + "LightGray", + "Gray", + "Pink", + "Lime", + "Yellow", + "LightBlue", + "Magenta", + "Orange", + "White" + ) + fun constructRecipe( backpackItem: BackpackItem, mainColor: EnumDyeColor?, @@ -40,9 +59,9 @@ object DyeingRecipeRegistry { 'B', ItemStack(backpackItem, 1), 'D', - ItemStack(net.minecraft.init.Items.DYE, 1, mainColor.dyeDamage), + "dye${DYES[mainColor.dyeDamage]}", 'R', - ItemStack(net.minecraft.init.Items.DYE, 1, accentColor.dyeDamage) + "dye${DYES[accentColor.dyeDamage]}", ) } else if (mainColor != null) { constructRecipe( @@ -54,7 +73,7 @@ object DyeingRecipeRegistry { 'B', ItemStack(backpackItem, 1), 'D', - ItemStack(net.minecraft.init.Items.DYE, 1, mainColor.dyeDamage) + "dye${DYES[mainColor.dyeDamage]}", ) } else if (accentColor != null) { constructRecipe( @@ -66,7 +85,7 @@ object DyeingRecipeRegistry { 'B', ItemStack(backpackItem, 1), 'D', - ItemStack(net.minecraft.init.Items.DYE, 1, accentColor.dyeDamage) + "dye${DYES[accentColor.dyeDamage]}", ) } else null } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/RetroSophisticatedBackpacksJEIPlugin.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/RetroSophisticatedBackpacksJEIPlugin.kt deleted file mode 100644 index 93e8f93..0000000 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/crafting/RetroSophisticatedBackpacksJEIPlugin.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.cleanroommc.retrosophisticatedbackpacks.crafting - -import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer -import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackCraftingTransferInfo -import mezz.jei.api.IJeiHelpers -import mezz.jei.api.IModPlugin -import mezz.jei.api.IModRegistry -import mezz.jei.api.JEIPlugin -import mezz.jei.api.recipe.transfer.IRecipeTransferRegistry - -@JEIPlugin -class RetroSophisticatedBackpacksJEIPlugin : IModPlugin { - companion object { - lateinit var helpers: IJeiHelpers - } - - override fun register(registry: IModRegistry) { - helpers = registry.jeiHelpers - - // By hijacking vanilla recipe types - // We can utilize JEI's built-in recipe transfer handler - val recipeTransferRegistry: IRecipeTransferRegistry = registry.recipeTransferRegistry - recipeTransferRegistry.addRecipeTransferHandler(BackpackCraftingTransferInfo()) - } -} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt index 16149ad..82e5d7c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/CapabilityHandler.kt @@ -3,6 +3,8 @@ package com.cleanroommc.retrosophisticatedbackpacks.handler import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.* +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import it.unimi.dsi.fastutil.objects.Object2ObjectMap import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap import net.minecraft.nbt.NBTBase @@ -210,6 +212,11 @@ object CapabilityHandler { ::AnvilUpgradeWrapper ) + instance.register( + MobCatcherUpgradeWrapper::class.java, + CapabilityStorageProvider() + ) { MobCatcherUpgradeWrapper() } + // Interfaces instance.register( UpgradeWrapper::class.java, @@ -324,6 +331,9 @@ object CapabilityHandler { } fun cacheBackpackInventory(backpackWrapper: BackpackWrapper) { + if (Config.tickDedupeLogicDisabled) { + return + } if (BACKPACK_INVENTORY_CACHE.containsKey(backpackWrapper.uuid)) { backpackWrapper.isCached = true return diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientImeInputHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientImeInputHandler.kt new file mode 100644 index 0000000..871f7d4 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientImeInputHandler.kt @@ -0,0 +1,29 @@ +package com.cleanroommc.retrosophisticatedbackpacks.handler + +import com.cleanroommc.modularui.api.IMuiScreen +import com.cleanroommc.retrosophisticatedbackpacks.Tags +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.VanillaTextFieldWidget +import net.minecraftforge.client.event.GuiScreenEvent +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly +import org.lwjgl.input.Keyboard + +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(modid = Tags.MOD_ID, value = [Side.CLIENT]) +object ClientImeInputHandler { + @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = true) + @JvmStatic + fun onKeyboardInput(event: GuiScreenEvent.KeyboardInputEvent.Pre) { + if (event.gui !is IMuiScreen || Keyboard.getEventKey() != 0 || Keyboard.getEventKeyState()) { + return + } + + val character = Keyboard.getEventCharacter() + if (character >= ' ' && VanillaTextFieldWidget.handleCommittedCharacter(character)) { + event.isCanceled = true + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt index 5b76181..b736763 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt @@ -8,10 +8,12 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.EverlastingUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IToolSwapperUpgrade +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherHandler import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import com.cleanroommc.retrosophisticatedbackpacks.mixin.EntityItemAccessor import net.minecraft.block.material.Material import net.minecraft.entity.item.EntityItem +import net.minecraft.entity.EntityLivingBase import net.minecraft.init.SoundEvents import net.minecraft.item.ItemStack import net.minecraft.util.EnumActionResult @@ -185,6 +187,14 @@ object EntityEventHandler { if (stack.item is BackpackItem) { if (player.isSneaking) { + if (entity is EntityLivingBase) { + val captureResult = MobCatcherHandler.tryCapture(player, entity) + if (captureResult != EnumActionResult.PASS) { + event.isCanceled = true + event.cancellationResult = captureResult + return + } + } val wrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return var transferred = BackpackInventoryHelper.attemptDepositOnEntity(wrapper, entity) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt index 3251a0f..29af868 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt @@ -1,8 +1,10 @@ package com.cleanroommc.retrosophisticatedbackpacks.handler import com.cleanroommc.retrosophisticatedbackpacks.network.C2SOpenBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SMobCatcherReleasePacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SRefillBlockPickPacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SStashToBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.S2CMobCatcherContentsPacket import net.minecraftforge.fml.common.network.NetworkRegistry import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper import net.minecraftforge.fml.relauncher.Side @@ -37,5 +39,17 @@ object NetworkHandler { idGenerator.next(), Side.SERVER ) + INSTANCE.registerMessage( + C2SMobCatcherReleasePacket.Handler::class.java, + C2SMobCatcherReleasePacket::class.java, + idGenerator.next(), + Side.SERVER + ) + INSTANCE.registerMessage( + S2CMobCatcherContentsPacket.Handler::class.java, + S2CMobCatcherContentsPacket::class.java, + idGenerator.next(), + Side.CLIENT + ) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt index de14df0..8553034 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt @@ -14,13 +14,14 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) val sortLockedSlots: MutableList = MutableList(size) { false } override fun isItemValid(slot: Int, stack: ItemStack): Boolean = - if (Config.blacklistedItems.contains(stack.item.registryName?.toString())) false + if (wrapper.isSlotBlockedByMobCatcher(slot)) false + else if (Config.isItemDisallowed(stack)) false else if (memorizedSlotStack[slot].isEmpty) stack.item !is BackpackItem || wrapper.canNestBackpack() else if (memorizedSlotRespectNbtList[slot]) ItemStack.areItemStacksEqual(stack, memorizedSlotStack[slot]) else stack.isItemEqualIgnoreDurability(memorizedSlotStack[slot]) override fun getStackLimit(slotIndex: Int, stack: ItemStack): Int = - stacks[slotIndex].maxStackSize * wrapper.getTotalStackMultiplier() + wrapper.getStackLimit(stack) /** * Prioritize insertion by tries inserting on memorized slot first. @@ -55,6 +56,9 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) validateSlotIndex(slot) + if (wrapper.isSlotBlockedByMobCatcher(slot)) + return stack + if (!isItemValid(slot, stack)) return stack @@ -95,12 +99,15 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) validateSlotIndex(slotIndex) + if (wrapper.isSlotBlockedByMobCatcher(slotIndex)) + return ItemStack.EMPTY + val stack = stacks[slotIndex] if (stack.isEmpty) return ItemStack.EMPTY - val slotMaxStackSize = stack.maxStackSize * wrapper.getTotalStackMultiplier() + val slotMaxStackSize = wrapper.getStackLimit(stack) val toExtract = min(amount, slotMaxStackSize) if (stack.count <= toExtract) { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt index 2e9ef5d..8ef5321 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/UpgradeItemStackHandler.kt @@ -1,11 +1,12 @@ package com.cleanroommc.retrosophisticatedbackpacks.inventory import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import net.minecraft.item.ItemStack import net.minecraft.util.NonNullList import net.minecraftforge.items.ItemStackHandler -class UpgradeItemStackHandler(size: Int) : ItemStackHandler(size) { +class UpgradeItemStackHandler(size: Int, private val wrapper: BackpackWrapper? = null) : ItemStackHandler(size) { val inventory: NonNullList = stacks @@ -15,6 +16,7 @@ class UpgradeItemStackHandler(size: Int) : ItemStackHandler(size) { original.getCapability(Capabilities.UPGRADE_CAPABILITY, null)?.onBeforeRemoved() } super.setStackInSlot(slot, stack) + wrapper?.ensureCapturedMobLayoutCurrent() } override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack { @@ -24,6 +26,10 @@ class UpgradeItemStackHandler(size: Int) : ItemStackHandler(size) { original.getCapability(Capabilities.UPGRADE_CAPABILITY, null)?.onBeforeRemoved() } } - return super.extractItem(slot, amount, simulate) + return super.extractItem(slot, amount, simulate).also { + if (!simulate && !it.isEmpty) { + wrapper?.ensureCapturedMobLayoutCurrent() + } + } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt index 563827e..da092c3 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt @@ -12,6 +12,8 @@ import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHelper import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackTier import com.cleanroommc.retrosophisticatedbackpacks.block.BackpackBlock +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackEnergyStorage +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackFluidHandler import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackBipedModel @@ -20,6 +22,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackGuiHolder import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData.InventoryType import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiFactory +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.handler.CapabilityHandler import com.cleanroommc.retrosophisticatedbackpacks.handler.RegistryHandler import com.cleanroommc.retrosophisticatedbackpacks.mixin.EntityItemAccessor @@ -172,11 +175,17 @@ class BackpackItem( } override fun initCapabilities(stack: ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { - val wrapper = BackpackWrapper(numberOfSlots, numberOfUpgradeSlots) + val wrapper = BackpackWrapper(numberOfSlots, numberOfUpgradeSlots, containerStack = stack) nbt?.let(wrapper::deserializeNBT) return wrapper } + override fun shouldCauseReequipAnimation(oldStack: ItemStack, newStack: ItemStack, slotChanged: Boolean): Boolean = + slotChanged || oldStack.item !== newStack.item || oldStack.metadata != newStack.metadata + + override fun shouldCauseBlockBreakReset(oldStack: ItemStack, newStack: ItemStack): Boolean = + oldStack.item !== newStack.item || oldStack.metadata != newStack.metadata + override fun onUpdate(stack: ItemStack, worldIn: World, entityIn: Entity, itemSlot: Int, isSelected: Boolean) { // Only cache on server if (!worldIn.isRemote && entityIn is EntityPlayerMP) { @@ -188,7 +197,7 @@ class BackpackItem( if (entityIn.ticksExisted % 5 == 0) wrapper.tickUpgrades(entityIn, worldIn, entityIn.posX, entityIn.posY, entityIn.posZ) - if (!wrapper.isCached) + if (!Config.tickDedupeLogicDisabled && !wrapper.isCached) CapabilityHandler.cacheBackpackInventory(wrapper) } } @@ -270,37 +279,104 @@ class BackpackItem( tooltip: MutableList, flagIn: ITooltipFlag ) { + val wrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) + if (!Interactable.hasShiftDown()) { + tooltip.add(TextComponentTranslation("tooltip.shift_to_reveal".asTranslationKey()).formattedText) + return + } + + if (wrapper == null) { + tooltip.add(TextComponentTranslation("tooltip.backpack.inventory_size".asTranslationKey(), numberOfSlots()).formattedText) + tooltip.add( + TextComponentTranslation( + "tooltip.backpack.upgrade_slots_size".asTranslationKey(), + numberOfUpgradeSlots() + ).formattedText + ) + return + } + + val itemStacks = wrapper.backpackItemStackHandler.inventory.filter { !it.isEmpty } + val upgradeStacks = wrapper.upgradeItemStackHandler.inventory.filter { !it.isEmpty } + val itemCount = itemStacks.fold(0) { total, itemStack -> total + itemStack.count } + tooltip.add( TextComponentTranslation( - "tooltip.backpack.inventory_size".asTranslationKey(), - numberOfSlots() + "tooltip.backpack.items".asTranslationKey(), + itemStacks.size, + wrapper.backpackInventorySize(), + itemCount ).formattedText ) tooltip.add( TextComponentTranslation( - "tooltip.backpack.upgrade_slots_size".asTranslationKey(), - numberOfUpgradeSlots() + "tooltip.backpack.upgrades".asTranslationKey(), + upgradeStacks.size, + wrapper.upgradeSlotsSize() ).formattedText ) + addStackMultiplierTooltip(wrapper, tooltip) + addFluidTooltip(wrapper, tooltip) + addEnergyTooltip(wrapper, tooltip) + if (itemStacks.isEmpty() && upgradeStacks.isEmpty()) { + tooltip.add(TextComponentTranslation("tooltip.backpack.empty".asTranslationKey()).formattedText) + } + } - if (Interactable.hasShiftDown()) { - val wrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return - val stackHint = - if (wrapper.isStackedByMultiplication()) "(xM)" - else "(+M)" + private fun addStackMultiplierTooltip(wrapper: BackpackWrapper, tooltip: MutableList) { + val multiplier = wrapper.getTotalStackMultiplier() + if (multiplier <= 1) { + return + } + val stackHint = + if (wrapper.isStackedByMultiplication()) "(xM)" + else "(+M)" + tooltip.add( + TextComponentTranslation( + "tooltip.backpack.stack_multiplier".asTranslationKey(), + multiplier, + TextComponentString(stackHint).setStyle(Style().setColor(TextFormatting.RED)).formattedText + ).formattedText + ) + } + + private fun addFluidTooltip(wrapper: BackpackWrapper, tooltip: MutableList) { + if (!wrapper.hasTankUpgrade()) { + return + } + val tanks = BackpackFluidHandler(wrapper).tankProperties + for (tank in tanks) { + val contents = tank.contents tooltip.add( - TextComponentTranslation( - "tooltip.backpack.stack_multiplier".asTranslationKey(), - wrapper.getTotalStackMultiplier(), - TextComponentString(stackHint).setStyle(Style().setColor(TextFormatting.RED)).formattedText - ).formattedText + if (contents == null || contents.amount <= 0) { + TextComponentTranslation("tooltip.backpack.fluid_empty".asTranslationKey(), 0, tank.capacity).formattedText + } else { + TextComponentTranslation( + "tooltip.backpack.fluid".asTranslationKey(), + contents.amount, + tank.capacity, + contents.localizedName + ).formattedText + } ) - } else { - tooltip.add(TextComponentTranslation("tooltip.shift_to_reveal".asTranslationKey()).formattedText) } } + private fun addEnergyTooltip(wrapper: BackpackWrapper, tooltip: MutableList) { + if (!wrapper.hasBatteryUpgrade()) { + return + } + val energy = BackpackEnergyStorage(wrapper) + tooltip.add( + TextComponentTranslation( + "tooltip.backpack.energy".asTranslationKey(), + energy.energyStored, + energy.maxEnergyStored + ).formattedText + ) + } + override fun buildUI( data: PlayerInventoryGuiData, syncManager: PanelSyncManager, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt index 7e29c1a..327b924 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/Items.kt @@ -3,6 +3,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.item import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackTier import com.cleanroommc.retrosophisticatedbackpacks.block.Blocks import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.* +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.config.Config import net.minecraft.item.Item @@ -19,8 +20,8 @@ object Items { val backpackLeather = BackpackItem( "backpack_leather", Blocks.leatherBackpack, - Config.leatherBackpack::slots, - Config.leatherBackpack::upgradeSlots, + Config.leatherBackpack::inventorySlotCount, + Config.leatherBackpack::upgradeSlotCount, BackpackTier.LEATHER ) @@ -28,8 +29,8 @@ object Items { val backpackIron = BackpackItem( "backpack_iron", Blocks.ironBackpack, - Config.ironBackpack::slots, - Config.ironBackpack::upgradeSlots, + Config.ironBackpack::inventorySlotCount, + Config.ironBackpack::upgradeSlotCount, BackpackTier.IRON ) @@ -37,8 +38,8 @@ object Items { val backpackGold = BackpackItem( "backpack_gold", Blocks.goldBackpack, - Config.goldBackpack::slots, - Config.goldBackpack::upgradeSlots, + Config.goldBackpack::inventorySlotCount, + Config.goldBackpack::upgradeSlotCount, BackpackTier.GOLD ) @@ -46,8 +47,8 @@ object Items { val backpackDiamond = BackpackItem( "backpack_diamond", Blocks.diamondBackpack, - Config.diamondBackpack::slots, - Config.diamondBackpack::upgradeSlots, + Config.diamondBackpack::inventorySlotCount, + Config.diamondBackpack::upgradeSlotCount, BackpackTier.DIAMOND ) @@ -55,8 +56,8 @@ object Items { val backpackObsidian = BackpackItem( "backpack_obsidian", Blocks.obsidianBackpack, - Config.obsidianBackpack::slots, - Config.obsidianBackpack::upgradeSlots, + Config.obsidianBackpack::inventorySlotCount, + Config.obsidianBackpack::upgradeSlotCount, BackpackTier.OBSIDIAN ) @@ -171,4 +172,10 @@ object Items { @JvmField val anvilUpgrade = AnvilUpgradeItem("anvil_upgrade", ::AnvilUpgradeWrapper) + + @JvmField + val mobCatcherUpgrade = MobCatcherUpgradeItem("mob_catcher_upgrade", false, ::MobCatcherUpgradeWrapper) + + @JvmField + val advancedMobCatcherUpgrade = MobCatcherUpgradeItem("advanced_mob_catcher_upgrade", true, ::MobCatcherUpgradeWrapper) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt index 130b9fb..acdad3f 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/JukeboxUpgradeItem.kt @@ -7,7 +7,7 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider class JukeboxUpgradeItem( registryName: String, private val wrapperFactory: () -> IJukeboxUpgrade, -) : UpgradeItem(registryName, true) { +) : UpgradeItem(registryName, true, "jukebox") { override fun initCapabilities(stack: net.minecraft.item.ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { val capability = wrapperFactory.invoke() nbt?.let(capability::deserializeNBT) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt new file mode 100644 index 0000000..d4e8442 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/MobCatcherUpgradeItem.kt @@ -0,0 +1,18 @@ +package com.cleanroommc.retrosophisticatedbackpacks.item + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherUpgradeWrapper +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.capabilities.ICapabilityProvider + +class MobCatcherUpgradeItem( + registryName: String, + val advanced: Boolean, + private val wrapperFactory: (Boolean) -> MobCatcherUpgradeWrapper +) : UpgradeItem(registryName, false) { + override fun initCapabilities(stack: ItemStack, nbt: NBTTagCompound?): ICapabilityProvider { + val capability = wrapperFactory(advanced) + nbt?.let(capability::deserializeNBT) + return capability + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt index 7120b7b..542ec5a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt @@ -6,7 +6,7 @@ import net.minecraft.item.ItemStack import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World -class StackUpgradeItem(registryName: String, val multiplier: () -> Int) : UpgradeItem(registryName) { +class StackUpgradeItem(registryName: String, val multiplier: () -> Int) : UpgradeItem(registryName, upgradeGroup = "stack") { override fun addInformation( stack: ItemStack, worldIn: World?, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt index cfb736c..46568c9 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt @@ -10,7 +10,7 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World -abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false) : ItemBase() { +abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false, val upgradeGroup: String? = null) : ItemBase() { init { setCreativeTab(RetroSophisticatedBackpacks.CREATIVE_TAB) setRegistryName(registryName) @@ -43,4 +43,4 @@ abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false) : if (nbt.hasKey("Capability")) wrapper.deserializeNBT(nbt.getCompoundTag("Capability")) else wrapper.deserializeNBT(nbt) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt new file mode 100644 index 0000000..5365182 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SMobCatcherReleasePacket.kt @@ -0,0 +1,33 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherHandler +import io.netty.buffer.ByteBuf +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext +import java.util.UUID + +class C2SMobCatcherReleasePacket() : IRefinedMessage { + private var capturedMobId: UUID = UUID(0L, 0L) + + constructor(capturedMobId: UUID) : this() { + this.capturedMobId = capturedMobId + } + + override fun toBytes(buf: ByteBuf) { + buf.writeLong(capturedMobId.mostSignificantBits) + buf.writeLong(capturedMobId.leastSignificantBits) + } + + override fun fromBytes(buf: ByteBuf) { + capturedMobId = UUID(buf.readLong(), buf.readLong()) + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: C2SMobCatcherReleasePacket, ctx: MessageContext): IRefinedMessage? { + val player = ctx.serverHandler.player + player.serverWorld.addScheduledTask { + MobCatcherHandler.release(player, message.capturedMobId) + } + return null + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt new file mode 100644 index 0000000..a3303f3 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/S2CMobCatcherContentsPacket.kt @@ -0,0 +1,32 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import io.netty.buffer.ByteBuf +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.fml.common.network.ByteBufUtils +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext + +class S2CMobCatcherContentsPacket() : IRefinedMessage { + private var capturedMobsTag = NBTTagCompound() + + constructor(backpackWrapper: BackpackWrapper) : this() { + capturedMobsTag = MobCatcherStorage.getCapturedMobsTag(backpackWrapper) + } + + override fun toBytes(buf: ByteBuf) { + ByteBufUtils.writeTag(buf, capturedMobsTag) + } + + override fun fromBytes(buf: ByteBuf) { + capturedMobsTag = ByteBufUtils.readTag(buf) ?: NBTTagCompound() + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: S2CMobCatcherContentsPacket, ctx: MessageContext): IRefinedMessage? { + RetroSophisticatedBackpacks.proxy.applyMobCatcherContentsSync(message.capturedMobsTag) + return null + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt index ad7e73a..b306298 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt @@ -6,15 +6,19 @@ import com.cleanroommc.retrosophisticatedbackpacks.block.Blocks import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackBlockEntityRenderer import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackDynamicModel import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackItemStackRenderer +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherStorage +import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiFactory import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlot import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpackSlotWrapper import com.cleanroommc.retrosophisticatedbackpacks.item.Items import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.Minecraft import net.minecraft.client.renderer.block.model.ModelResourceLocation import net.minecraft.client.settings.KeyBinding import net.minecraft.item.Item +import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.client.model.ModelLoader import net.minecraftforge.client.model.ModelLoaderRegistry import net.minecraftforge.fml.client.registry.ClientRegistry @@ -50,6 +54,8 @@ abstract class RSBProxy { open fun registerItemRenderer(item: Item, meta: Int, id: String) {} + open fun applyMobCatcherContentsSync(nbt: NBTTagCompound) {} + class ServerProxy : RSBProxy() class ClientProxy : RSBProxy() { @@ -95,5 +101,13 @@ abstract class RSBProxy { ModelLoaderRegistry.registerLoader(BackpackDynamicModel.Loader()) } + + override fun applyMobCatcherContentsSync(nbt: NBTTagCompound) { + val mc = Minecraft.getMinecraft() + mc.addScheduledTask { + val container = mc.player?.openContainer as? BackpackContainer ?: return@addScheduledTask + MobCatcherStorage.applyCapturedMobsTag(container.backpackWrapper, nbt) + } + } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt index a1d9828..848e6c4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/BackpackSH.kt @@ -5,6 +5,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.backpack.DisplaySide import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHelper import com.cleanroommc.retrosophisticatedbackpacks.backpack.SortType import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.tileentity.BackpackTileEntity import net.minecraft.item.EnumDyeColor import net.minecraft.network.PacketBuffer @@ -29,6 +30,7 @@ class BackpackSH( const val UPDATE_ITEM_DISPLAY_ROTATION = 10 const val UPDATE_ITEM_DISPLAY_COLOR = 11 const val UPDATE_ITEM_DISPLAY_SIDE = 12 + const val UPDATE_SEARCH_PHRASE = 13 } override fun readOnClient(id: Int, buf: PacketBuffer) {} @@ -47,13 +49,23 @@ class BackpackSH( UPDATE_ITEM_DISPLAY_SLOT -> updateItemDisplaySlot(buf) UPDATE_ITEM_DISPLAY_ROTATION -> updateItemDisplayRotation(buf) UPDATE_ITEM_DISPLAY_COLOR -> { + if (Config.itemDisplayDisabled) { + return + } wrapper.itemDisplayColor = buf.readEnumValue(EnumDyeColor::class.java) syncRenderState() } UPDATE_ITEM_DISPLAY_SIDE -> { + if (Config.itemDisplayDisabled) { + return + } wrapper.itemDisplaySide = buf.readEnumValue(DisplaySide::class.java) syncRenderState() } + UPDATE_SEARCH_PHRASE -> { + val phrase = buf.readString(50) + wrapper.searchPhrase = phrase + } else -> {} } } @@ -98,6 +110,9 @@ class BackpackSH( } private fun updateItemDisplaySlot(buf: PacketBuffer) { + if (Config.itemDisplayDisabled) { + return + } val slotIndex = buf.readInt() val selected = buf.readBoolean() if (selected) { @@ -109,6 +124,9 @@ class BackpackSH( } private fun updateItemDisplayRotation(buf: PacketBuffer) { + if (Config.itemDisplayDisabled) { + return + } wrapper.rotateItemDisplaySlot(buf.readInt(), buf.readBoolean()) syncRenderState() } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/FoodFilterSlotSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/FoodFilterSlotSH.kt index e2f36b5..afbce0c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/FoodFilterSlotSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/FoodFilterSlotSH.kt @@ -1,10 +1,10 @@ package com.cleanroommc.retrosophisticatedbackpacks.sync import com.cleanroommc.modularui.widgets.slot.ModularSlot -import net.minecraft.item.ItemFood +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IFeedingUpgrade import net.minecraft.item.ItemStack class FoodFilterSlotSH(slot: ModularSlot) : FilterSlotSH(slot) { override fun isItemValid(itemStack: ItemStack): Boolean = - itemStack.item is ItemFood -} \ No newline at end of file + IFeedingUpgrade.isValidFood(itemStack) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt index 9dc8d18..a5ca418 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt @@ -20,8 +20,10 @@ import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.network.PacketBuffer +import net.minecraft.network.play.server.SPacketSetSlot import net.minecraftforge.fluids.FluidUtil import net.minecraftforge.items.IItemHandlerModifiable +import net.minecraftforge.items.ItemHandlerHelper /** * Used to synchronize upgrade item's capability, this is only fired from client to reflect client's action to server @@ -168,7 +170,7 @@ class UpgradeSlotSH( wrapper.hungerFeedingStrategy = buf.readEnumValue(AdvancedFeedingUpgradeWrapper.FeedingStrategy.Hunger::class.java) wrapper.healthFeedingStrategy = - buf.readEnumValue(AdvancedFeedingUpgradeWrapper.FeedingStrategy.HEALTH::class.java) + buf.readEnumValue(AdvancedFeedingUpgradeWrapper.FeedingStrategy.Health::class.java) } private fun updateFilterUpgrade(buf: PacketBuffer) { @@ -297,7 +299,28 @@ class UpgradeSlotSH( private fun updateAnvilTakeResult() { val wrapper = anvil() ?: return - val player = slot.getSyncHandler().syncManager.player - wrapper.takeResult(player, player.world) + val player = slot.getSyncHandler().syncManager.player as? EntityPlayerMP ?: return + val preview = wrapper.updateRepairOutput(player, player.world) + val carried = player.inventory.itemStack + if (preview.isEmpty || !wrapper.canTakeResult(player) || !canPlaceAnvilResultOnCursor(carried, preview)) { + return + } + + val taken = wrapper.takeResult(player, player.world) + if (taken.isEmpty) { + return + } + if (carried.isEmpty) { + player.inventory.itemStack = taken + } else { + carried.grow(taken.count) + player.inventory.itemStack = carried + } + player.connection.sendPacket(SPacketSetSlot(-1, -1, player.inventory.itemStack)) + player.openContainer.detectAndSendChanges() } + + private fun canPlaceAnvilResultOnCursor(carried: ItemStack, result: ItemStack): Boolean = + carried.isEmpty || ItemHandlerHelper.canItemStacksStack(carried, result) && + carried.count + result.count <= carried.maxStackSize } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt index 8044087..129ada8 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt @@ -14,18 +14,23 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackEnergyStor import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackGuiHolder +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.block.state.IBlockState import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.inventory.Container import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.network.NetworkManager import net.minecraft.network.play.server.SPacketUpdateTileEntity -import net.minecraft.tileentity.TileEntity import net.minecraft.util.ITickable +import net.minecraft.tileentity.TileEntityLockableLoot import net.minecraft.util.EnumFacing +import net.minecraft.util.NonNullList import net.minecraft.util.math.BlockPos import net.minecraft.util.text.ITextComponent +import net.minecraft.util.text.TextComponentString import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World import net.minecraftforge.common.capabilities.Capability @@ -35,7 +40,7 @@ import net.minecraftforge.energy.CapabilityEnergy import net.minecraftforge.items.IItemHandler class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : - TileEntity(), + TileEntityLockableLoot(), IItemHandler, ITickable, IGuiHolder { @@ -63,16 +68,28 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : @Suppress("UNCHECKED_CAST") override fun getCapability(capability: Capability, facing: EnumFacing?): T? = - if (capability == Capabilities.BACKPACK_CAPABILITY) wrapper as T - else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) this as T - else if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade()) BackpackFluidHandler(wrapper) as T - else if (capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade()) BackpackEnergyStorage(wrapper) as T - else null + when { + capability == Capabilities.BACKPACK_CAPABILITY -> wrapper as T + isExternalConnectionBlocked(facing) -> null + capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY -> this as T + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade() -> BackpackFluidHandler(wrapper) as T + capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade() -> BackpackEnergyStorage(wrapper) as T + else -> null + } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = - wrapper.hasCapability(capability, facing) || - capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade() || - capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade() + capability == Capabilities.BACKPACK_CAPABILITY || + !isExternalConnectionBlocked(facing) && + (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && wrapper.hasTankUpgrade() || + capability == CapabilityEnergy.ENERGY && wrapper.hasBatteryUpgrade()) + + private fun isExternalConnectionBlocked(facing: EnumFacing?): Boolean { + if (facing == null || !hasWorld()) { + return false + } + return Config.isConnectionBlockDisallowed(world.getBlockState(pos.offset(facing)).block) + } override fun writeToNBT(compound: NBTTagCompound): NBTTagCompound { compound.setTag(BACKPACK_INVENTORY_TAG, wrapper.serializeNBT()) @@ -109,8 +126,15 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : world.notifyBlockUpdate(pos, state, state, 3) } + override fun hasCustomName(): Boolean = + wrapper.customName != null + + override fun getName(): String = + if (hasCustomName()) wrapper.customName!! else "container.backpack" + override fun getDisplayName(): ITextComponent = - TextComponentTranslation("container.backpack".asTranslationKey()) + if (hasCustomName()) TextComponentString(name) + else TextComponentTranslation("container.backpack".asTranslationKey()) override fun update() { if (!world.isRemote && world.totalWorldTime % 5L == 0L) { @@ -123,9 +147,21 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : override fun getSlots(): Int = wrapper.slots + override fun getSizeInventory(): Int = + wrapper.backpackInventorySize() + + override fun isEmpty(): Boolean = + wrapper.backpackItemStackHandler.inventory.all(ItemStack::isEmpty) + override fun getStackInSlot(slot: Int): ItemStack = wrapper.getStackInSlot(slot) + override fun getInventoryStackLimit(): Int = + wrapper.getTotalStackMultiplier() * 64 + + override fun getItems(): NonNullList = + wrapper.backpackItemStackHandler.inventory + override fun insertItem( slot: Int, stack: ItemStack, @@ -179,4 +215,15 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : world.setBlockState(pos, state.withProperty(BackpackBlock.BATTERY, battery), 3) } } + + override fun createContainer( + playerInventory: InventoryPlayer, + playerIn: EntityPlayer + ): Container { + throw UnsupportedOperationException("Backpack tile entities do not have a vanilla GUI, if you're attempting to open a GUI, use BackpackTileEntity.openGui(EntityPlayer) instead") + } + + override fun getGuiID(): String { + throw UnsupportedOperationException("Backpack tile entities do not have a vanilla GUI, if you're attempting to open a GUI, use BackpackTileEntity.openGui(EntityPlayer) instead") + } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/BackpackItemStackHelper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/BackpackItemStackHelper.kt index a4fa5bd..63d1a60 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/BackpackItemStackHelper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/util/BackpackItemStackHelper.kt @@ -1,9 +1,13 @@ package com.cleanroommc.retrosophisticatedbackpacks.util +import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks +import net.minecraft.item.ItemFood import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagList import net.minecraft.util.NonNullList +import net.minecraftforge.items.IItemHandler +import squeek.applecore.api.AppleCoreAPI object BackpackItemStackHelper { fun saveAllSlotsExtended(nbt: NBTTagCompound, inventory: NonNullList): NBTTagCompound { @@ -46,4 +50,26 @@ object BackpackItemStackHelper { stack.count = nbt.getInteger("Count") return stack } -} \ No newline at end of file + + /** + * Returns the hunger value of the food in the slot, if it is a food item + * + * @return the hunger value of the food in the slot, or null if the slot is not a food item + */ + fun getHungerFromSlot(handler: IItemHandler, slot: Int, predicate: (ItemStack) -> Boolean): Int? { + val stack = handler.getStackInSlot(slot) + + if (!predicate(stack)) + return null + + return if (RetroSophisticatedBackpacks.appleCoreLoaded) { + val foodValues = AppleCoreAPI.accessor.getFoodValues(stack) + + foodValues.hunger + } else { + val item = stack.item as? ItemFood + + item?.getHealAmount(stack) + } + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang index 71808c3..023034b 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang @@ -36,7 +36,13 @@ retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpacks # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=Inventory size: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=Upgrade slots: %d +retro_sophisticated_backpacks.tooltip.backpack.items=Items: %d/%d slots, %d total +retro_sophisticated_backpacks.tooltip.backpack.upgrades=Upgrades: %d/%d retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> Stack multiplier: %d %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=Fluid: %d/%d mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Fluid: %d/%d mB +retro_sophisticated_backpacks.tooltip.backpack.energy=Energy: %d/%d FE +retro_sophisticated_backpacks.tooltip.backpack.empty=Empty retro_sophisticated_backpacks.tooltip.upgrade_base=It does nothing! Feel free to put it in your upgrade slots! @@ -95,27 +101,39 @@ retro_sophisticated_backpacks.gui.sorting_settings=No Sort retro_sophisticated_backpacks.gui.backpack_settings=Backpack Settings retro_sophisticated_backpacks.gui.item_display_settings=Item Display Settings retro_sophisticated_backpacks.gui.backpack_settings.tooltip=Backpack Settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Item Display Settings retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Allows selecting the backpack slot rendered on the backpack\nOpen tab to modify item display retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Allows selecting the backpack slot rendered on the backpack\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.search=Click to search +retro_sophisticated_backpacks.gui.search_detail=Use @modid for mod id and #text for tooltip search retro_sophisticated_backpacks.gui.settings_button.context_player=Player retro_sophisticated_backpacks.gui.settings_button.context_backpack=Backpack retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Player settings context +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=Settings are saved for your player and follow you between backpacks retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=Backpack settings context +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=Settings are saved on this backpack and apply to anyone using it retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift-click into open tab retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift-click normally +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.detail=Controls where shift-clicked stacks go while an upgrade tab is open retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Keep tab open retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Close tab after action +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.detail=Controls whether upgrade tabs stay expanded after interacting with slots retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep search phrase retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Clear search phrase +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.detail=Controls whether the search text is kept after closing the backpack retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=Other players can open retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=Only owner can open +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.detail=Controls whether other players may open this backpack retro_sophisticated_backpacks.gui.settings_button.rotate=Rotate display item retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Left click rotates clockwise\nRight click rotates counter-clockwise retro_sophisticated_backpacks.gui.settings_button.item_display_color=Display color +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=Left click selects next color\nRight click selects previous color retro_sophisticated_backpacks.gui.settings_button.display_side_front=Display on front retro_sophisticated_backpacks.gui.settings_button.display_side_left=Display on left retro_sophisticated_backpacks.gui.settings_button.display_side_right=Display on right +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag @@ -239,6 +257,8 @@ item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack @@ -249,6 +269,8 @@ retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the back retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.tooltip.mob_catcher_upgrade=Captures passive mobs into backpack storage slots with sneak right-click +retro_sophisticated_backpacks.tooltip.advanced_mob_catcher_upgrade=Captures passive and hostile mobs into backpack storage slots with sneak right-click retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox @@ -259,10 +281,23 @@ retro_sophisticated_backpacks.gui.pump_settings=Pump retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump retro_sophisticated_backpacks.gui.battery_settings=Battery retro_sophisticated_backpacks.gui.anvil_settings=Anvil -retro_sophisticated_backpacks.gui.pump_input=Pump In -retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers -retro_sophisticated_backpacks.gui.pump_world=World -retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.pump_input=Pump into backpack +retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank +retro_sophisticated_backpacks.gui.pump_output=Pump out of backpack +retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interact with tanks and pipes +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Do not interact with tanks and pipes +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_world=Interact with world +retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_no_world=Do not interact with world +retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_hand=Interact with held containers +retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_no_hand=Do not interact with held containers +retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it retro_sophisticated_backpacks.gui.anvil_no_result=No Result retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage retro_sophisticated_backpacks.gui.jukebox_play=Play @@ -279,3 +314,22 @@ retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=Only one Mob Catcher Upgrade is allowed per backpack +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=Captured %s +retro_sophisticated_backpacks.gui.status.mob_catcher_released=Released %s +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=Backpack has no Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=That mob cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=Players cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=Bosses cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=Mobs with passengers or vehicles cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=That mob is blocked from capture +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=Only the owner can capture that mob +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=Mobs with inventories cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=Hostile mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slots, more than this upgrade allows (%s) +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang index 68b49ab..f1cdfba 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang @@ -36,7 +36,13 @@ retro_sophisticated_backpacks.key.category=复古精妙背包 # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=背包容量:%d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=升级插槽:%d +retro_sophisticated_backpacks.tooltip.backpack.items=物品:%d/%d 槽,合计 %d 个 +retro_sophisticated_backpacks.tooltip.backpack.upgrades=升级:%d/%d retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> 堆叠倍数:%d %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=流体:%d/%d mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=流体:%d/%d mB +retro_sophisticated_backpacks.tooltip.backpack.energy=能量:%d/%d FE +retro_sophisticated_backpacks.tooltip.backpack.empty=空 retro_sophisticated_backpacks.tooltip.upgrade_base=没有任何效果!大可放进升级插槽里! @@ -88,32 +94,45 @@ retro_sophisticated_backpacks.gui.advanced_restock_settings=高级取货 retro_sophisticated_backpacks.gui.filter_settings=过滤 retro_sophisticated_backpacks.gui.advanced_filter_settings=高级过滤 +retro_sophisticated_backpacks.gui.crafting_settings=合成 retro_sophisticated_backpacks.gui.memory_settings=记忆 retro_sophisticated_backpacks.gui.sorting_settings=禁止整理 retro_sophisticated_backpacks.gui.backpack_settings=背包设置 retro_sophisticated_backpacks.gui.item_display_settings=物品显示设置 retro_sophisticated_backpacks.gui.backpack_settings.tooltip=背包设置 +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=配置背包行为\n打开标签页以修改背包设置 +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=配置背包行为\n上下文=选择修改玩家设置或背包设置\n按钮用于切换 Shift 点击、标签页、搜索和访问行为 retro_sophisticated_backpacks.gui.item_display_settings.tooltip=物品显示设置 retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=选择渲染在背包上的背包槽位\n打开标签页以修改物品显示 retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=选择渲染在背包上的背包槽位\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 +retro_sophisticated_backpacks.gui.search=点击以搜索 +retro_sophisticated_backpacks.gui.search_detail=使用 @modid 搜索模组,使用 #文本 搜索 tooltip retro_sophisticated_backpacks.gui.settings_button.context_player=玩家 retro_sophisticated_backpacks.gui.settings_button.context_backpack=背包 retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=玩家设置上下文 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=设置保存在玩家身上,并会跟随你使用不同背包 retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=背包设置上下文 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=设置保存在该背包上,并对使用它的玩家生效 retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift点击优先进入打开的标签页 retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift点击使用普通行为 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.detail=控制升级标签页打开时 Shift 点击物品的转移目标 retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=保持标签页打开 retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=操作后关闭标签页 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.detail=控制与槽位交互后升级标签页是否保持展开 retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=保留搜索文本 retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=清空搜索文本 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.detail=控制关闭背包后是否保留搜索文本 retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=其他玩家可打开 retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=仅所有者可打开 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.detail=控制其他玩家是否能打开该背包 retro_sophisticated_backpacks.gui.settings_button.rotate=旋转显示物品 retro_sophisticated_backpacks.gui.settings_button.rotate_detail=左键顺时针旋转\n右键逆时针旋转 retro_sophisticated_backpacks.gui.settings_button.item_display_color=显示颜色 +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=左键选择下一个颜色\n右键选择上一个颜色 retro_sophisticated_backpacks.gui.settings_button.display_side_front=显示在正面 retro_sophisticated_backpacks.gui.settings_button.display_side_left=显示在左侧 retro_sophisticated_backpacks.gui.settings_button.display_side_right=显示在右侧 +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=左键选择下一个侧面\n右键选择上一个侧面 retro_sophisticated_backpacks.gui.memory_settings.tooltip=槽位记忆设置 retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=选择会记住当前物品的槽位,该槽位只接收匹配物品\n打开标签页以修改槽位设置 retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=选择会记住当前物品的槽位,该槽位只接收匹配物品\n全选/取消全选槽位=按钮\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 @@ -140,7 +159,10 @@ retro_sophisticated_backpacks.gui.ignore_nbt=忽略NBT retro_sophisticated_backpacks.gui.add_ore_dict_entry=添加矿物词典 retro_sophisticated_backpacks.gui.remove_ore_dict_entry=移除矿物词典 -retro_sophisticated_backpacks.gui.ore_dict_input_help=可在此输入矿物词典,支持正则表达式 +retro_sophisticated_backpacks.gui.ore_dict_input_help=可在此输入矿物词典,\n支持正则表达式。 +retro_sophisticated_backpacks.gui.ore_dict_input_help.pro_tip=提示:你可以将物品悬停在词典条目上\n以确认其是否符合条目,\n或将其悬停在输入栏上以查看可用的矿物词典。 +retro_sophisticated_backpacks.gui.ore_dict_list_entries=可用的矿物词典: +retro_sophisticated_backpacks.gui.none=(无) retro_sophisticated_backpacks.gui.complete_hunger=仅在玩家足够饥饿时喂食\n不会浪费食物提供的任何饥饿值 retro_sophisticated_backpacks.gui.half_hunger=仅在玩家足够饥饿时喂食\n最多浪费食物提供的一半饥饿值 @@ -159,6 +181,9 @@ retro_sophisticated_backpacks.gui.sort_by_mod_id=按模组ID整理 retro_sophisticated_backpacks.gui.sort_by_count=按数量整理 retro_sophisticated_backpacks.gui.sort_by_ore_dict=按矿物词典整理 +retro_sophisticated_backpacks.gui.craft_into_backpack=Shift点击合成产物转移至背包 +retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift点击合成产物转移至玩家物品栏 + retro_sophisticated_backpacks.gui.transfer_to_player_inv=转移所有物品至玩家物品栏 retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=转移匹配物品至玩家物品栏 retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=按住Shift以转移所有物品 @@ -251,10 +276,23 @@ retro_sophisticated_backpacks.gui.pump_settings=泵 retro_sophisticated_backpacks.gui.advanced_pump_settings=高级泵 retro_sophisticated_backpacks.gui.battery_settings=电池 retro_sophisticated_backpacks.gui.anvil_settings=铁砧 -retro_sophisticated_backpacks.gui.pump_input=输入 -retro_sophisticated_backpacks.gui.pump_fluid_handlers=流体处理器 -retro_sophisticated_backpacks.gui.pump_world=世界 -retro_sophisticated_backpacks.gui.pump_hand=手持容器 +retro_sophisticated_backpacks.gui.pump_input=泵入背包 +retro_sophisticated_backpacks.gui.pump_input_detail=将流体抽入背包储罐 +retro_sophisticated_backpacks.gui.pump_output=泵出背包 +retro_sophisticated_backpacks.gui.pump_output_detail=将流体从背包储罐泵出 +retro_sophisticated_backpacks.gui.pump_fluid_handlers=与储罐和管道交互 +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=允许通过相邻流体处理器移动流体 +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=不与储罐和管道交互 +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=禁止通过相邻流体处理器移动流体 +retro_sophisticated_backpacks.gui.pump_world=与世界交互 +retro_sophisticated_backpacks.gui.pump_world_detail=允许在世界中放置或抽取流体 +retro_sophisticated_backpacks.gui.pump_no_world=不与世界交互 +retro_sophisticated_backpacks.gui.pump_no_world_detail=禁止在世界中放置或抽取流体 +retro_sophisticated_backpacks.gui.pump_hand=与手持容器交互 +retro_sophisticated_backpacks.gui.pump_hand_detail=允许填充或抽取玩家手持容器 +retro_sophisticated_backpacks.gui.pump_no_hand=不与手持容器交互 +retro_sophisticated_backpacks.gui.pump_no_hand_detail=禁止填充或抽取玩家手持容器 +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=手持流体容器点击可设置该过滤\n空手点击可清除 retro_sophisticated_backpacks.gui.anvil_no_result=无结果 retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift 点击背包存储 retro_sophisticated_backpacks.gui.jukebox_play=播放 @@ -271,3 +309,26 @@ retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=切换武器 retro_sophisticated_backpacks.gui.tool_swapper_any=切换任意物品 retro_sophisticated_backpacks.gui.tool_swapper_only_tools=仅切换工具 retro_sophisticated_backpacks.gui.tool_swapper_no_swap=不自动切换工具 +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=生物捕捉升级 +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=高级生物捕捉升级 +retro_sophisticated_backpacks.tooltip.mob_catcher_upgrade=潜行右击将被动生物捕捉进背包存储槽 +retro_sophisticated_backpacks.tooltip.advanced_mob_catcher_upgrade=潜行右击将被动和敌对生物捕捉进背包存储槽 +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=点击释放 +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=先释放已捕获生物再移除生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=已捕获生物需要高级生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=每个背包只能安装一个生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=已捕获 %s +retro_sophisticated_backpacks.gui.status.mob_catcher_released=已释放 %s +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=背包没有生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=该生物无法捕捉 +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=无法捕捉玩家 +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=无法捕捉Boss +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=无法捕捉有乘客或载具的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=该生物被禁止捕捉 +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=只有主人能捕捉该生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=无法捕捉带物品栏的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=敌对生物需要高级生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=该生物需要 %s 个槽,超过此升级允许的 %s 个 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=没有可用的 %sx%s 空槽区域 +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=无法在这里释放生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=这里没有有效释放空间 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json new file mode 100644 index 0000000..c94212e --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/advanced_mob_catcher_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/advanced_mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json new file mode 100644 index 0000000..80c407e --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/models/item/mob_catcher_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "retro_sophisticated_backpacks:item/mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_deposit_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_deposit_upgrade.json index a061f4e..1e3b4e6 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_deposit_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_deposit_upgrade.json @@ -2,13 +2,16 @@ "type": "retro_sophisticated_backpacks:upgrade_shaped", "key": { "G": { - "item": "minecraft:gold_ingot" + "type": "forge:ore_dict", + "ore": "ingotGold" }, "D": { - "item": "minecraft:diamond" + "type": "forge:ore_dict", + "ore": "gemDiamond" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:deposit_upgrade" @@ -22,4 +25,4 @@ "result": { "item": "retro_sophisticated_backpacks:advanced_deposit_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_feeding_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_feeding_upgrade.json index fb02a25..f62de05 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_feeding_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_feeding_upgrade.json @@ -2,13 +2,16 @@ "type": "retro_sophisticated_backpacks:upgrade_shaped", "key": { "G": { - "item": "minecraft:gold_ingot" + "type": "forge:ore_dict", + "ore": "ingotGold" }, "D": { - "item": "minecraft:diamond" + "type": "forge:ore_dict", + "ore": "gemDiamond" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:feeding_upgrade" @@ -22,4 +25,4 @@ "result": { "item": "retro_sophisticated_backpacks:advanced_feeding_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_filter_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_filter_upgrade.json index 7d67117..0490041 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_filter_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_filter_upgrade.json @@ -2,13 +2,16 @@ "type": "retro_sophisticated_backpacks:upgrade_shaped", "key": { "G": { - "item": "minecraft:gold_ingot" + "type": "forge:ore_dict", + "ore": "ingotGold" }, "D": { - "item": "minecraft:diamond" + "type": "forge:ore_dict", + "ore": "gemDiamond" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:filter_upgrade" @@ -22,4 +25,4 @@ "result": { "item": "retro_sophisticated_backpacks:advanced_filter_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json new file mode 100644 index 0000000..b8428e8 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_mob_catcher_upgrade.json @@ -0,0 +1,34 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "H": { + "item": "minecraft:skull", + "data": 1 + }, + "D": { + "type": "forge:ore_dict", + "ore": "gemDiamond" + }, + "E": { + "item": "minecraft:ender_eye" + }, + "G": { + "type": "forge:ore_dict", + "ore": "ingotGold" + }, + "B": { + "item": "retro_sophisticated_backpacks:mob_catcher_upgrade" + }, + "S": { + "item": "minecraft:soul_sand" + } + }, + "pattern": [ + "HDE", + "GBG", + "SSS" + ], + "result": { + "item": "retro_sophisticated_backpacks:advanced_mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_pickup_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_pickup_upgrade.json index 8d18f10..d2a46e0 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_pickup_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_pickup_upgrade.json @@ -2,13 +2,16 @@ "type": "retro_sophisticated_backpacks:upgrade_shaped", "key": { "G": { - "item": "minecraft:gold_ingot" + "type": "forge:ore_dict", + "ore": "ingotGold" }, "D": { - "item": "minecraft:diamond" + "type": "forge:ore_dict", + "ore": "gemDiamond" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:pickup_upgrade" @@ -22,4 +25,4 @@ "result": { "item": "retro_sophisticated_backpacks:advanced_pickup_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_restock_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_restock_upgrade.json index 0561343..b232152 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_restock_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/advanced_restock_upgrade.json @@ -2,13 +2,16 @@ "type": "retro_sophisticated_backpacks:upgrade_shaped", "key": { "G": { - "item": "minecraft:gold_ingot" + "type": "forge:ore_dict", + "ore": "ingotGold" }, "D": { - "item": "minecraft:diamond" + "type": "forge:ore_dict", + "ore": "gemDiamond" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:restock_upgrade" @@ -22,4 +25,4 @@ "result": { "item": "retro_sophisticated_backpacks:advanced_restock_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_diamond.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_diamond.json index a52f4b0..ed4636f 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_diamond.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_diamond.json @@ -2,7 +2,8 @@ "type": "retro_sophisticated_backpacks:backpack_upgrade_shaped", "key": { "U": { - "item": "minecraft:diamond" + "type": "forge:ore_dict", + "ore": "gemDiamond" }, "B": { "item": "retro_sophisticated_backpacks:backpack_gold" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:backpack_diamond" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_gold.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_gold.json index 991d311..dc05b39 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_gold.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_gold.json @@ -2,7 +2,8 @@ "type": "retro_sophisticated_backpacks:backpack_upgrade_shaped", "key": { "U": { - "item": "minecraft:gold_ingot" + "type": "forge:ore_dict", + "ore": "ingotGold" }, "B": { "item": "retro_sophisticated_backpacks:backpack_iron" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:backpack_gold" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_iron.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_iron.json index 1757729..a0301bc 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_iron.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_iron.json @@ -2,7 +2,8 @@ "type": "retro_sophisticated_backpacks:backpack_upgrade_shaped", "key": { "U": { - "item": "minecraft:iron_ingot" + "type": "forge:ore_dict", + "ore": "ingotIron" }, "B": { "item": "retro_sophisticated_backpacks:backpack_leather" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:backpack_iron" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_leather.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_leather.json index 0817e5e..76fa6f5 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_leather.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_leather.json @@ -2,13 +2,16 @@ "type": "minecraft:crafting_shaped", "key": { "L": { - "item": "minecraft:leather" + "type": "forge:ore_dict", + "ore": "leather" }, "C": { - "item": "minecraft:chest" + "type": "forge:ore_dict", + "ore": "chestWood" }, "S": { - "item": "minecraft:string" + "type": "forge:ore_dict", + "ore": "string" } }, "pattern": [ @@ -19,4 +22,4 @@ "result": { "item": "retro_sophisticated_backpacks:backpack_leather" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_obsidian.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_obsidian.json index 24e8956..2f665ec 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_obsidian.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/backpack_obsidian.json @@ -2,10 +2,12 @@ "type": "retro_sophisticated_backpacks:backpack_upgrade_shaped", "key": { "U": { - "item": "minecraft:obsidian" + "type": "forge:ore_dict", + "ore": "obsidian" }, "N": { - "item": "minecraft:nether_star" + "type": "forge:ore_dict", + "ore": "netherStar" }, "B": { "item": "retro_sophisticated_backpacks:backpack_diamond" @@ -19,4 +21,4 @@ "result": { "item": "retro_sophisticated_backpacks:backpack_obsidian" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/crafting_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/crafting_upgrade.json index c57dfd9..4b4a707 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/crafting_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/crafting_upgrade.json @@ -6,7 +6,7 @@ }, "C": { "type": "forge:ore_dict", - "ore": "chest" + "ore": "chestWood" }, "I": { "type": "forge:ore_dict", @@ -24,4 +24,4 @@ "result": { "item": "retro_sophisticated_backpacks:crafting_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/deposit_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/deposit_upgrade.json index bf9afd9..f570270 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/deposit_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/deposit_upgrade.json @@ -5,13 +5,16 @@ "item": "minecraft:piston" }, "C": { - "item": "minecraft:chest" + "type": "forge:ore_dict", + "ore": "chestWood" }, "I": { - "item": "minecraft:iron_ingot" + "type": "forge:ore_dict", + "ore": "ingotIron" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -25,4 +28,4 @@ "result": { "item": "retro_sophisticated_backpacks:deposit_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/exponential_stack_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/exponential_stack_upgrade.json index 78e89a4..15d58dd 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/exponential_stack_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/exponential_stack_upgrade.json @@ -2,7 +2,8 @@ "type": "minecraft:crafting_shaped", "key": { "N": { - "item": "minecraft:nether_star" + "type": "forge:ore_dict", + "ore": "netherStar" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -14,7 +15,8 @@ "item": "minecraft:end_crystal" }, "E": { - "item": "minecraft:emerald_block" + "type": "forge:ore_dict", + "ore": "blockEmerald" } }, "pattern": [ @@ -25,4 +27,4 @@ "result": { "item": "retro_sophisticated_backpacks:exponential_stack_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/feeding_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/feeding_upgrade.json index e8ec6b8..f43c1bf 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/feeding_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/feeding_upgrade.json @@ -12,7 +12,8 @@ "item": "minecraft:speckled_melon" }, "E": { - "item": "minecraft:ender_pearl" + "type": "forge:ore_dict", + "ore": "enderpearl" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -26,4 +27,4 @@ "result": { "item": "retro_sophisticated_backpacks:feeding_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/filter_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/filter_upgrade.json index 57782cb..230541a 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/filter_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/filter_upgrade.json @@ -2,10 +2,12 @@ "type": "minecraft:crafting_shaped", "key": { "S": { - "item": "minecraft:string" + "type": "forge:ore_dict", + "ore": "string" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -19,4 +21,4 @@ "result": { "item": "retro_sophisticated_backpacks:filter_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/inception_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/inception_upgrade.json index ca135a3..919823f 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/inception_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/inception_upgrade.json @@ -5,10 +5,12 @@ "item": "minecraft:ender_eye" }, "D": { - "item": "minecraft:diamond" + "type": "forge:ore_dict", + "ore": "gemDiamond" }, "N": { - "item": "minecraft:nether_star" + "type": "forge:ore_dict", + "ore": "netherStar" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -22,4 +24,4 @@ "result": { "item": "retro_sophisticated_backpacks:inception_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json new file mode 100644 index 0000000..ee85522 --- /dev/null +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/mob_catcher_upgrade.json @@ -0,0 +1,26 @@ +{ + "type": "retro_sophisticated_backpacks:upgrade_shaped", + "key": { + "E": { + "item": "minecraft:ender_pearl" + }, + "I": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "B": { + "item": "retro_sophisticated_backpacks:upgrade_base" + }, + "L": { + "item": "minecraft:lead" + } + }, + "pattern": [ + " E ", + "IBI", + "L L" + ], + "result": { + "item": "retro_sophisticated_backpacks:mob_catcher_upgrade" + } +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/pickup_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/pickup_upgrade.json index f43c531..b386d52 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/pickup_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/pickup_upgrade.json @@ -5,10 +5,12 @@ "item": "minecraft:sticky_piston" }, "S": { - "item": "minecraft:string" + "type": "forge:ore_dict", + "ore": "string" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -22,4 +24,4 @@ "result": { "item": "retro_sophisticated_backpacks:pickup_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/restock_upgrade.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/restock_upgrade.json index e2d38b8..8f76fc9 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/restock_upgrade.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/restock_upgrade.json @@ -5,13 +5,16 @@ "item": "minecraft:sticky_piston" }, "C": { - "item": "minecraft:chest" + "type": "forge:ore_dict", + "ore": "chestWood" }, "I": { - "item": "minecraft:iron_ingot" + "type": "forge:ore_dict", + "ore": "ingotIron" }, "R": { - "item": "minecraft:redstone" + "type": "forge:ore_dict", + "ore": "dustRedstone" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -25,4 +28,4 @@ "result": { "item": "retro_sophisticated_backpacks:restock_upgrade" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_starter_tier.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_starter_tier.json index 91eaf06..716643a 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_starter_tier.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_starter_tier.json @@ -2,7 +2,8 @@ "type": "minecraft:crafting_shaped", "key": { "U": { - "item": "minecraft:coal_block" + "type": "forge:ore_dict", + "ore": "blockCoal" }, "B": { "item": "retro_sophisticated_backpacks:upgrade_base" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:stack_upgrade_starter_tier" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_1.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_1.json index 80c9ae5..42338aa 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_1.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_1.json @@ -2,7 +2,8 @@ "type": "minecraft:crafting_shaped", "key": { "U": { - "item": "minecraft:iron_block" + "type": "forge:ore_dict", + "ore": "blockIron" }, "B": { "item": "retro_sophisticated_backpacks:stack_upgrade_starter_tier" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:stack_upgrade_tier_1" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_2.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_2.json index d5156e5..65bb15d 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_2.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_2.json @@ -2,7 +2,8 @@ "type": "minecraft:crafting_shaped", "key": { "U": { - "item": "minecraft:gold_block" + "type": "forge:ore_dict", + "ore": "blockGold" }, "B": { "item": "retro_sophisticated_backpacks:stack_upgrade_tier_1" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:stack_upgrade_tier_2" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_3.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_3.json index 4e08534..3653ed3 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_3.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_3.json @@ -2,7 +2,8 @@ "type": "minecraft:crafting_shaped", "key": { "U": { - "item": "minecraft:diamond_block" + "type": "forge:ore_dict", + "ore": "blockDiamond" }, "B": { "item": "retro_sophisticated_backpacks:stack_upgrade_tier_2" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:stack_upgrade_tier_3" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_4.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_4.json index 094bcb9..b2b5ec9 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_4.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/stack_upgrade_tier_4.json @@ -2,7 +2,8 @@ "type": "minecraft:crafting_shaped", "key": { "U": { - "item": "minecraft:nether_star" + "type": "forge:ore_dict", + "ore": "netherStar" }, "B": { "item": "retro_sophisticated_backpacks:stack_upgrade_tier_3" @@ -16,4 +17,4 @@ "result": { "item": "retro_sophisticated_backpacks:stack_upgrade_tier_4" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/upgrade_base.json b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/upgrade_base.json index fcacc4f..0e66cf5 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/recipes/upgrade_base.json +++ b/src/main/resources/assets/retro_sophisticated_backpacks/recipes/upgrade_base.json @@ -2,13 +2,16 @@ "type": "minecraft:crafting_shaped", "key": { "I": { - "item": "minecraft:iron_ingot" + "type": "forge:ore_dict", + "ore": "ingotIron" }, "L": { - "item": "minecraft:leather" + "type": "forge:ore_dict", + "ore": "leather" }, "S": { - "item": "minecraft:string" + "type": "forge:ore_dict", + "ore": "string" } }, "pattern": [ @@ -19,4 +22,4 @@ "result": { "item": "retro_sophisticated_backpacks:upgrade_base" } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/advanced_mob_catcher_upgrade.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/advanced_mob_catcher_upgrade.png new file mode 100644 index 0000000000000000000000000000000000000000..b0abe62b10e54c3c532f754b11bb3d780886923e GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKU}W=jaSX9Iot&^hz`)4Bz~ImR z#P9NI0~z43d}O)Gd#pQBmPI5%534^t`ZVJ{w4+PERJH~ zr9Y3|USD9wedcDImr{hNxyn#c9J69vucCdW!sx-i2+P zVjeq8_W$_N>)15E`{B{!`5K=LY<+lmcs>ZYv7eZw`eUbr#Z3W6w#&`exlhbGf2Zb1 z!XiEQIpWXm{62Hw_}P;MKR(&E-R_S&V5(fryc{h2;pOM>w(0NfjZ3Un7_B(vxuAvB zQC}fDEg>PnBk)mc_BX+_V{@lG7vHC-shH^7c|x-%Z)WGEJ7*Xew!1gE)h}X>1_lg+ Mr>mdKI;Vst04INixc~qF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/mob_catcher_upgrade.png b/src/main/resources/assets/retro_sophisticated_backpacks/textures/item/mob_catcher_upgrade.png new file mode 100644 index 0000000000000000000000000000000000000000..e123b1b526ab13057dbd7bf98e45dc4901ccd9a1 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVC3<1aSX9Iot&_MjU!O}xBMc# zZ~q@0Z2s?=Xlwukhj=~&2`Qeul>7aj!J3^vyCzO-Y;1f8Qt-Yk#VCWLSa|8rW4G7y zoD#h(`R46g$-tO~vkh&@-vx8DU3V}Vh#NfIyz=3VS~lTQOEyVPK@i>ciFv!>6$3+{ z=}*o@^#*_L?!Pag@?)n&T+N?0CH~8Yj~qB~z`#;hWHt8$Q|}MO3r`&U^584ere}wz zzc;+`N=xv0tL1k);}3mdKI;Vst01>~Bh5!Hn literal 0 HcmV?d00001 From 77e36049b8aefc445c61ae4df646ad921572f86d Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Mon, 8 Jun 2026 22:52:42 +0800 Subject: [PATCH 06/10] align backpack gui layout and matched transfers - resize backpack slot rows from scaled screen height - anchor player inventory and side tabs to corrected gui positions - restrict matched transfers to existing matching stacks or memory slots --- .../backpack/BackpackInventoryHelper.kt | 82 ++++++++++++++++--- .../client/gui/BackpackPanel.kt | 30 +++++-- .../gui/widgets/BackToBackpackTabWidget.kt | 4 +- .../client/gui/widgets/SettingTabWidget.kt | 4 +- .../client/gui/widgets/TabWidget.kt | 9 +- 5 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt index d6d53ab..6b54038 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/backpack/BackpackInventoryHelper.kt @@ -140,12 +140,8 @@ object BackpackInventoryHelper { continue } - stack = wrapper.backpackItemStackHandler.insertItemToMemorySlots(stack, false) - for (j in 0 until wrapper.backpackInventorySize()) { - stack = wrapper.insertItem(j, stack, false) - if (stack.isEmpty) - break - } + stack = if (transferMatched) insertIntoMatchingBackpackSlots(wrapper, stack) + else insertIntoBackpackMatchingFirst(wrapper, stack) playerInventory.setStackInSlot(i, stack) } @@ -164,20 +160,72 @@ object BackpackInventoryHelper { if (transferMatched && !handlerContains(playerInventory, stack, 0)) continue - val firstSlot = if (transferMatched) 0 else 9 - for (j in firstSlot until playerInventory.slots) { - stack = playerInventory.insertItem(j, stack, false) - if (stack.isEmpty) - break - } + stack = if (transferMatched) insertIntoMatchingHandlerSlots(playerInventory, stack, 0) + else insertIntoHandlerMatchingFirst(playerInventory, stack, 9) wrapper.backpackItemStackHandler.setStackInSlot(i, stack) } } + private fun insertIntoBackpackMatchingFirst(wrapper: BackpackWrapper, stack: ItemStack): ItemStack { + var stack = insertIntoMatchingBackpackSlots(wrapper, stack) + for (slot in 0 until wrapper.backpackInventorySize()) { + stack = wrapper.insertItem(slot, stack, false) + if (stack.isEmpty) + break + } + return stack + } + + private fun insertIntoMatchingBackpackSlots(wrapper: BackpackWrapper, stack: ItemStack): ItemStack { + var stack = stack + for (slot in 0 until wrapper.backpackInventorySize()) { + if (!matchesStackKey(wrapper.getStackInSlot(slot), stack)) + continue + + stack = wrapper.insertItem(slot, stack, false) + if (stack.isEmpty) + return stack + } + + for (slot in 0 until wrapper.backpackInventorySize()) { + if (!matchesMemorySlot(wrapper, slot, stack)) + continue + + stack = wrapper.insertItem(slot, stack, false) + if (stack.isEmpty) + return stack + } + + return stack + } + + private fun insertIntoHandlerMatchingFirst(handler: IItemHandlerModifiable, stack: ItemStack, firstSlot: Int): ItemStack { + var stack = insertIntoMatchingHandlerSlots(handler, stack, firstSlot) + for (slot in firstSlot until handler.slots) { + stack = handler.insertItem(slot, stack, false) + if (stack.isEmpty) + break + } + return stack + } + + private fun insertIntoMatchingHandlerSlots(handler: IItemHandlerModifiable, stack: ItemStack, firstSlot: Int): ItemStack { + var stack = stack + for (slot in firstSlot until handler.slots) { + if (!matchesStackKey(handler.getStackInSlot(slot), stack)) + continue + + stack = handler.insertItem(slot, stack, false) + if (stack.isEmpty) + break + } + return stack + } + private fun backpackContainsOrMemory(wrapper: BackpackWrapper, stack: ItemStack): Boolean = handlerContains(wrapper.backpackItemStackHandler, stack, 0) || - wrapper.backpackItemStackHandler.memorizedSlotStack.any { matchesStackKey(it, stack) } + wrapper.backpackItemStackHandler.memorizedSlotStack.indices.any { matchesMemorySlot(wrapper, it, stack) } private fun handlerContains(handler: IItemHandler, stack: ItemStack, firstSlot: Int): Boolean { for (slot in firstSlot until handler.slots) { @@ -193,6 +241,14 @@ object BackpackInventoryHelper { ItemStack.areItemsEqual(first, second) && ItemStack.areItemStackTagsEqual(first, second) + private fun matchesMemorySlot(wrapper: BackpackWrapper, slot: Int, stack: ItemStack): Boolean { + val memoryStack = wrapper.backpackItemStackHandler.memorizedSlotStack[slot] + return !memoryStack.isEmpty && !stack.isEmpty && + if (wrapper.backpackItemStackHandler.memorizedSlotRespectNbtList[slot]) + ItemStack.areItemStacksEqual(stack, memoryStack) + else stack.isItemEqualIgnoreDurability(memoryStack) + } + fun attemptDepositOnTileEntity(wrapper: BackpackWrapper, destination: TileEntity, facing: EnumFacing): Boolean { if (Config.isInteractionBlockDisallowed(destination.blockType)) { return false diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt index 8d4d33b..bd51eea 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt @@ -43,9 +43,10 @@ import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.ceilDiv import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.setEnabledIfAndEnabled import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.client.gui.ScaledResolution import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack -import net.minecraft.client.gui.Gui import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.util.ITooltipFlag import net.minecraft.util.text.TextFormatting @@ -73,7 +74,6 @@ class BackpackPanel( private const val SEARCH_BOX_ANIMATION_MS = 200L internal const val DISABLED_SLOT_X_POS = -2000 internal const val VISIBLE_BACKPACK_ROWS = 5 - internal const val PLAYER_INVENTORY_BOTTOM = 8 internal const val INVENTORY_CONTROL_COLUMNS = 2 private val SORT_TYPE_VARIANTS = listOf( CyclicVariantButtonWidget.Variant( @@ -145,7 +145,9 @@ class BackpackPanel( val playerInventoryLabelX: Int get() = 8 + playerInventoryXOffset val playerInventoryLabelY: Int - get() = area.height - 94 + get() = panelHeight - 94 + private val playerInventorySlotsY: Int + get() = playerInventoryLabelY + 11 val panelWidth: Int get() = 14 + backgroundRowSize * SLOT_SIZE + inventoryScrollbarWidth val panelHeight: Int @@ -170,6 +172,7 @@ class BackpackPanel( private var rebuildWidgetsQueued = false private var lastUpgradeStructureSignature = emptyList() private var reopenBackpackQueued = false + private var lastScaledHeight = 0 private val searchSlotDisplayIndices = IntArray(backpackWrapper.backpackInventorySize()) { it } private var searchVisibleSlots = backpackWrapper.backpackInventorySize() private var lastSearchLayoutKey = "" @@ -201,6 +204,7 @@ class BackpackPanel( override fun onUpdate() { super.onUpdate() + refreshLayoutIfScreenHeightChanged() updateSearchLayout() if (!rebuildWidgetsQueued) queueRebuildIfUpgradeStructureChanged() @@ -283,7 +287,7 @@ class BackpackPanel( backgroundRowSize = if (backpackWrapper.backpackInventorySize() > 81) 12 else 9 rowSize = (backgroundRowSize - inventoryColumnsTaken).coerceAtLeast(1) colSize = backpackWrapper.backpackInventorySize().ceilDiv(rowSize) - visibleColSize = min(colSize, VISIBLE_BACKPACK_ROWS) + visibleColSize = min(colSize, maxVisibleBackpackRows()) backpackSlotsWidth = rowSize * SLOT_SIZE inventoryScrollbarWidth = if (colSize > visibleColSize) BackpackInventoryScrollWidget.SCROLLBAR_WIDTH else 0 inventoryAreaWidth = backgroundRowSize * SLOT_SIZE + inventoryScrollbarWidth @@ -304,8 +308,22 @@ class BackpackPanel( } } + private fun refreshLayoutIfScreenHeightChanged() { + val scaledHeight = ScaledResolution(Minecraft.getMinecraft()).scaledHeight + if (scaledHeight == lastScaledHeight) + return + + lastScaledHeight = scaledHeight + rebuildWidgetsQueued = true + } + + private fun maxVisibleBackpackRows(): Int = + ((ScaledResolution(Minecraft.getMinecraft()).scaledHeight - HEIGHT_WITHOUT_STORAGE_SLOTS) / SLOT_SIZE) + .coerceAtLeast(1) + init { recalculateLayout() + lastScaledHeight = ScaledResolution(Minecraft.getMinecraft()).scaledHeight syncManager.syncValue("backpack_wrapper", backpackSyncHandler) // Backpack slots @@ -519,11 +537,11 @@ class BackpackPanel( internal fun addPlayerInventoryWidgets() { child( - SlotGroupWidget.playerInventory(PLAYER_INVENTORY_BOTTOM - 1, false) { _, _ -> + SlotGroupWidget.playerInventory(0, false) { _, _ -> NoBackgroundItemSlot() } .disableSortButtons() - .left(playerInventoryLabelX - 1) + .pos(playerInventoryLabelX - 1, playerInventorySlotsY) ) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt index b4ccd67..5704a8e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackToBackpackTabWidget.kt @@ -20,8 +20,8 @@ class BackToBackpackTabWidget : Widget(), Interactable init { size(TAB_TEXTURE.width, TAB_TEXTURE.height) - .right(-TAB_TEXTURE.width + 2) - .top(0) + .right(-TAB_TEXTURE.width + 4) + .top(TabWidget.TAB_TOP_OFFSET) .background(TAB_TEXTURE.get(-1, false)) .tooltipStatic { it.addLine(IKey.lang("gui.back_to_backpack.tooltip".asTranslationKey())) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt index 524e611..1a5aabf 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SettingTabWidget.kt @@ -20,8 +20,8 @@ class SettingTabWidget : Widget(), Interactable { init { size(TAB_TEXTURE.width, TAB_TEXTURE.height) - .right(-TAB_TEXTURE.width + 2) - .top(0) + .right(-TAB_TEXTURE.width + 4) + .top(TabWidget.TAB_TOP_OFFSET) .background(TAB_TEXTURE.get(-1, false)) .tooltipStatic { it.addLine(IKey.lang("gui.settings".asTranslationKey())) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt index fa3e53d..8fbca00 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt @@ -20,6 +20,8 @@ class TabWidget( SingleChildWidget(), Interactable { companion object { val TAB_TEXTURE: TabTexture = GuiTextures.TAB_RIGHT + const val TAB_TOP_OFFSET = 4 + const val TAB_VERTICAL_SPACE = 1 } var showExpanded = false @@ -48,11 +50,14 @@ class TabWidget( var onToggle: ((Boolean) -> Unit)? = null init { - size(TAB_TEXTURE.width, TAB_TEXTURE.height).top({ tabOrder * 30.0 }, Unit.Measure.PIXEL) + size(TAB_TEXTURE.width, TAB_TEXTURE.height) + .top({ + (TAB_TOP_OFFSET + (tabOrder - 1).coerceAtLeast(0) * (TAB_TEXTURE.height + TAB_VERTICAL_SPACE)).toDouble() + }, Unit.Measure.PIXEL) when (expandDirection) { ExpandDirection.LEFT -> left(-TAB_TEXTURE.width - 2) - ExpandDirection.RIGHT -> right(-TAB_TEXTURE.width + 2) + ExpandDirection.RIGHT -> right(-TAB_TEXTURE.width + 4) } } From 723c78b4789ff86da5aa739f6d550bca8e772a6f Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Tue, 9 Jun 2026 22:34:56 +0800 Subject: [PATCH 07/10] Improve backpack tooltip visuals and storage handling - Add visual backpack tooltip sections for inventory contents, upgrades, fluids, and energy - Rework tank upgrade container filling and draining to follow bucket-style transfer behavior - Fix battery gauge texture layering and charge rendering - Render quick stash +/- overlays in container foreground so survival inventory shows them --- .../capability/upgrade/TankUpgradeWrapper.kt | 144 +++++- .../client/gui/RSBTextures.kt | 10 + .../widgets/BatteryInventoryControlWidget.kt | 36 +- .../handler/BackpackTooltipHandler.kt | 421 ++++++++++++++++++ .../handler/ClientGuiStashHandler.kt | 35 +- .../item/BackpackItem.kt | 103 +---- .../lang/en_us.lang | 18 +- .../lang/es_es.lang | 12 +- .../lang/ja_jp.lang | 12 +- .../lang/ko_kr.lang | 12 +- .../lang/pl_pl.lang | 12 +- .../lang/ru_ru.lang | 12 +- .../lang/zh_cn.lang | 18 +- .../lang/zh_tw.lang | 12 +- 14 files changed, 698 insertions(+), 159 deletions(-) create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/BackpackTooltipHandler.kt diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt index a867129..613d09e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt @@ -14,6 +14,7 @@ import net.minecraft.world.World import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.fluids.FluidStack import net.minecraftforge.fluids.FluidUtil +import net.minecraftforge.fluids.capability.IFluidHandlerItem import net.minecraftforge.fluids.capability.IFluidTankProperties import net.minecraftforge.fluids.capability.FluidTankProperties import net.minecraftforge.items.IItemHandler @@ -33,6 +34,7 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { override val settingsLangKey = "gui.tank_settings".asTranslationKey() override val tankCapacity = Config.tankUpgrade.capacityPerSlotRow * 3 private var fluid: FluidStack? = null + private var nextContainerActionTime = 0L private val inventory = object : ExposedItemStackHandler(4) { override fun isItemValid(slot: Int, stack: ItemStack): Boolean = slot == INPUT_RESULT_SLOT || slot == OUTPUT_RESULT_SLOT || stack.isEmpty || FluidUtil.getFluidHandler(stack) != null @@ -97,11 +99,15 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { } override fun tick(wrapper: BackpackWrapper, world: World) { - if (world.totalWorldTime % Config.tankUpgrade.autoFillDrainContainerCooldown.coerceAtLeast(1).toLong() != 0L) { + if (world.totalWorldTime < nextContainerActionTime) { return } - tryDrainInput(wrapper) - tryFillOutput(wrapper) + var didSomething = tryDrainInput(wrapper) + didSomething = tryFillOutput(wrapper) || didSomething + if (didSomething) { + nextContainerActionTime = + world.totalWorldTime + Config.tankUpgrade.autoFillDrainContainerCooldown.coerceAtLeast(1) + } } override fun getInventory(): IItemHandler = @@ -127,16 +133,19 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { return false } val single = ItemHandlerHelper.copyStackWithSize(stack, 1) - val handler = FluidUtil.getFluidHandler(single) ?: return false - if (!drainHandler(wrapper, handler, true)) { + if (stack.count > 1 && !drainStack(wrapper, single, true, true, {})) { return false } - stack.shrink(1) - if (stack.isEmpty) { - inventory.setStackInSlot(INPUT_SLOT, ItemStack.EMPTY) + return drainStack(wrapper, single, true, false) { container -> + if (stack.count > 1) { + stack.shrink(1) + if (stack.isEmpty) { + inventory.setStackInSlot(INPUT_SLOT, ItemStack.EMPTY) + } + } else { + inventory.setStackInSlot(INPUT_SLOT, container) + } } - inventory.insertItem(INPUT_RESULT_SLOT, handler.container, false) - return true } private fun tryFillOutput(wrapper: BackpackWrapper): Boolean { @@ -145,55 +154,144 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { return false } val single = ItemHandlerHelper.copyStackWithSize(stack, 1) - val handler = FluidUtil.getFluidHandler(single) ?: return false - if (!fillHandler(wrapper, handler, true)) { + if (stack.count > 1 && !fillStack(wrapper, single, true, true, {})) { return false } - stack.shrink(1) - if (stack.isEmpty) { - inventory.setStackInSlot(OUTPUT_SLOT, ItemStack.EMPTY) + return fillStack(wrapper, single, true, false) { container -> + if (stack.count > 1) { + stack.shrink(1) + if (stack.isEmpty) { + inventory.setStackInSlot(OUTPUT_SLOT, ItemStack.EMPTY) + } + } else { + inventory.setStackInSlot(OUTPUT_SLOT, container) + } } - inventory.insertItem(OUTPUT_RESULT_SLOT, handler.container, false) - return true } - private fun drainHandler(wrapper: BackpackWrapper, handler: net.minecraftforge.fluids.capability.IFluidHandlerItem, moveResult: Boolean): Boolean { - val extracted = if (fluid == null) handler.drain(getMaxInOut(wrapper), false) else handler.drain(FluidStack(fluid!!.fluid, getTankCapacity(wrapper) - fluid!!.amount), false) + private fun drainStack( + wrapper: BackpackWrapper, + stack: ItemStack, + moveResult: Boolean, + requireFullDrain: Boolean, + updateContainerStack: (ItemStack) -> Unit + ): Boolean = + FluidUtil.getFluidHandler(stack)?.let { drainHandler(wrapper, it, moveResult, requireFullDrain, updateContainerStack) } ?: false + + private fun fillStack( + wrapper: BackpackWrapper, + stack: ItemStack, + moveResult: Boolean, + requireFullFill: Boolean, + updateContainerStack: (ItemStack) -> Unit + ): Boolean = + FluidUtil.getFluidHandler(stack)?.let { fillHandler(wrapper, it, moveResult, requireFullFill, updateContainerStack) } ?: false + + private fun drainHandler( + wrapper: BackpackWrapper, + handler: IFluidHandlerItem, + moveResult: Boolean, + requireFullDrain: Boolean = false, + updateContainerStack: (ItemStack) -> Unit = {} + ): Boolean { + val current = fluid + val toDrain = if (current == null) BUCKET else minOf(BUCKET, getTankCapacity(wrapper) - current.amount) + val extracted = if (current == null) handler.drain(toDrain, false) else handler.drain(FluidStack(current.fluid, toDrain, current.tag?.copy()), false) if (extracted == null || extracted.amount <= 0 || fill(wrapper, extracted, false) <= 0) { return false } + if (requireFullDrain && fill(wrapper, extracted, false) != firstTankCapacity(handler)) { + return false + } if (moveResult) { val preview = FluidUtil.getFluidHandler(handler.container.copy()) ?: return false val filled = fill(wrapper, extracted, false) preview.drain(FluidStack(extracted.fluid, filled, extracted.tag?.copy()), true) - if (!inventory.insertItem(INPUT_RESULT_SLOT, preview.container, true).isEmpty) { + val movesToResult = hasNoMatchingFluid(preview) + if (requireFullDrain && !movesToResult) { return false } + if (movesToResult && !inventory.insertItem(INPUT_RESULT_SLOT, preview.container, true).isEmpty) { + return false + } + } + if (requireFullDrain) { + return true } val filled = fill(wrapper, extracted, true) handler.drain(FluidStack(extracted.fluid, filled, extracted.tag?.copy()), true) + val resultHandler = FluidUtil.getFluidHandler(handler.container.copy()) + if (moveResult && (resultHandler?.let(::hasNoMatchingFluid) ?: true)) { + updateContainerStack(ItemStack.EMPTY) + inventory.insertItem(INPUT_RESULT_SLOT, handler.container, false) + } else { + updateContainerStack(handler.container) + } return true } - private fun fillHandler(wrapper: BackpackWrapper, handler: net.minecraftforge.fluids.capability.IFluidHandlerItem, moveResult: Boolean): Boolean { + private fun fillHandler( + wrapper: BackpackWrapper, + handler: IFluidHandlerItem, + moveResult: Boolean, + requireFullFill: Boolean = false, + updateContainerStack: (ItemStack) -> Unit = {} + ): Boolean { val current = fluid ?: return false - val filled = handler.fill(FluidStack(current.fluid, minOf(getMaxInOut(wrapper), current.amount), current.tag?.copy()), false) + val filled = handler.fill(FluidStack(current.fluid, minOf(BUCKET, current.amount), current.tag?.copy()), false) if (filled <= 0 || drain(wrapper, filled, false) == null) { return false } + if (requireFullFill && drain(wrapper, filled, false)?.amount != firstTankCapacity(handler)) { + return false + } if (moveResult) { val preview = FluidUtil.getFluidHandler(handler.container.copy()) ?: return false val drained = drain(wrapper, filled, false) ?: return false preview.fill(drained, true) - if (!inventory.insertItem(OUTPUT_RESULT_SLOT, preview.container, true).isEmpty) { + val movesToResult = matchingTankIsFull(preview) + if (requireFullFill && !movesToResult) { + return false + } + if (movesToResult && !inventory.insertItem(OUTPUT_RESULT_SLOT, preview.container, true).isEmpty) { return false } } + if (requireFullFill) { + return true + } val drained = drain(wrapper, filled, true) ?: return false handler.fill(drained, true) + val resultHandler = FluidUtil.getFluidHandler(handler.container.copy()) + if (moveResult && resultHandler?.let(::matchingTankIsFull) == true) { + updateContainerStack(ItemStack.EMPTY) + inventory.insertItem(OUTPUT_RESULT_SLOT, handler.container, false) + } else { + updateContainerStack(handler.container) + } return true } + private fun hasNoMatchingFluid(handler: IFluidHandlerItem): Boolean = + handler.tankProperties.all { it.contents?.amount ?: 0 <= 0 } + + private fun firstTankCapacity(handler: IFluidHandlerItem): Int = + handler.tankProperties.firstOrNull()?.capacity ?: 0 + + private fun matchingTankIsFull(handler: IFluidHandlerItem): Boolean { + val current = fluid + if (current == null) { + return handler.tankProperties.all { property -> + val contents = property.contents + contents != null && contents.amount >= property.capacity + } + } + return handler.tankProperties.all { property -> + val contents = property.contents + contents == null || !contents.isFluidEqual(current) || contents.amount >= property.capacity + } + } + override fun serializeNBT(): NBTTagCompound { val nbt = super.serializeNBT() fluid?.let { nbt.setTag(FLUID_TAG, it.writeToNBT(NBTTagCompound())) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt index 1f7e6f8..e5915b2 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt @@ -162,6 +162,16 @@ object RSBTextures { .imageSize(256, 256) .xy(47, 56, 16, 18) .build() + val BATTERY_CONNECTION_TOP = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(47, 48, 16, 4) + .build() + val BATTERY_CONNECTION_BOTTOM = UITexture.builder() + .location(Tags.MOD_ID, "gui/gui_controls.png") + .imageSize(256, 256) + .xy(47, 52, 16, 4) + .build() val BATTERY_CHARGE = UITexture.builder() .location(Tags.MOD_ID, "gui/gui_controls.png") .imageSize(256, 256) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt index 0c43dc7..d4c6643 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BatteryInventoryControlWidget.kt @@ -22,6 +22,9 @@ class BatteryInventoryControlWidget( private const val BATTERY_WIDTH = 18 private const val OVERLAY_LEFT = BATTERY_LEFT + 1 private const val OVERLAY_WIDTH = 16 + private const val CHARGE_SEGMENT_HEIGHT = 6 + private const val TOP_BAR_COLOR = 0xFF1A1A + private const val BOTTOM_BAR_COLOR = 0xFFFF40 } init { @@ -51,12 +54,14 @@ class BatteryInventoryControlWidget( if (height < 36) height / 2 else 18, theme ) - renderCharge(context, currentWrapper(), height, theme) yOffset = 0 repeat(height / 18) { RSBTextures.BATTERY_OVERLAY.draw(context, OVERLAY_LEFT, yOffset, OVERLAY_WIDTH, 18, theme) yOffset += 18 } + renderCharge(context, currentWrapper(), height, theme) + RSBTextures.BATTERY_CONNECTION_TOP.draw(context, OVERLAY_LEFT, 0, OVERLAY_WIDTH, 4, theme) + RSBTextures.BATTERY_CONNECTION_BOTTOM.draw(context, OVERLAY_LEFT, height - 4, OVERLAY_WIDTH, 4, theme) } private fun currentWrapper(): BatteryUpgradeWrapper? = @@ -73,19 +78,32 @@ class BatteryInventoryControlWidget( if (wrapper == null || max <= 0 || wrapper.energyStored <= 0) { return } - val displayLevel = ((height - 2) * (wrapper.energyStored.toFloat() / max)).toInt().coerceIn(1, height - 2) - var drawn = 0 - while (drawn < displayLevel) { - val segment = minOf(6, displayLevel - drawn) - RSBTextures.BATTERY_CHARGE.draw( + val numberOfSegments = height / CHARGE_SEGMENT_HEIGHT + val displayLevel = (numberOfSegments * (wrapper.energyStored.toFloat() / max)).toInt() + if (displayLevel <= 0) { + return + } + + val topRed = TOP_BAR_COLOR shr 16 and 255 + val topGreen = TOP_BAR_COLOR shr 8 and 255 + val topBlue = TOP_BAR_COLOR and 255 + val bottomRed = BOTTOM_BAR_COLOR shr 16 and 255 + val bottomGreen = BOTTOM_BAR_COLOR shr 8 and 255 + val bottomBlue = BOTTOM_BAR_COLOR and 255 + + for (segmentIndex in 0 until displayLevel) { + val percentage = if (numberOfSegments <= 1) 0f else segmentIndex.toFloat() / (numberOfSegments - 1) + val red = (bottomRed * (1 - percentage) + topRed * percentage).toInt() + val green = (bottomGreen * (1 - percentage) + topGreen * percentage).toInt() + val blue = (bottomBlue * (1 - percentage) + topBlue * percentage).toInt() + RSBTextures.BATTERY_CHARGE.withColorOverride((255 shl 24) or (red shl 16) or (green shl 8) or blue).draw( context, OVERLAY_LEFT, - height - 1 - drawn - segment, + height - (segmentIndex + 1) * CHARGE_SEGMENT_HEIGHT, OVERLAY_WIDTH, - segment, + CHARGE_SEGMENT_HEIGHT, theme ) - drawn += segment } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/BackpackTooltipHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/BackpackTooltipHandler.kt new file mode 100644 index 0000000..aa9f47c --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/BackpackTooltipHandler.kt @@ -0,0 +1,421 @@ +package com.cleanroommc.retrosophisticatedbackpacks.handler + +import com.cleanroommc.modularui.drawable.GuiDraw +import com.cleanroommc.retrosophisticatedbackpacks.Tags +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackEnergyStorage +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackFluidHandler +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiScreen +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.client.renderer.Tessellator +import net.minecraft.client.renderer.vertex.DefaultVertexFormats +import net.minecraft.client.resources.I18n +import net.minecraft.item.ItemStack +import net.minecraft.util.ResourceLocation +import net.minecraft.util.text.TextComponentTranslation +import net.minecraft.util.text.TextFormatting +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.client.event.RenderTooltipEvent +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.util.Locale + +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(modid = Tags.MOD_ID, value = [Side.CLIENT]) +object BackpackTooltipHandler { + private const val MAX_STACKS_ON_LINE = 9 + private const val STACK_WIDTH = 18 + private const val GAUGE_SCALE = 0.65f + private const val GAUGE_RENDER_HEIGHT = 10 + private const val GAUGE_TEXTURE_WIDTH = 54 + private const val GAUGE_TEXTURE_HEIGHT = 18 + private const val GAUGE_TEXT_LEFT = 41 + private const val ROW_HEIGHT = 20 + private const val TITLE_HEIGHT = 10 + private const val COUNT_PADDING = 2 + private const val CHARGE_SEGMENT_HEIGHT = 6 + private const val GUI_CONTROLS_SIZE = 256f + private const val GUI_CONTROLS = Tags.MOD_ID + ":textures/gui/gui_controls.png" + private const val TANK_MARKER = "\u00A70\u00A71\u00A72\u00A73" + private const val BATTERY_MARKER = "\u00A70\u00A71\u00A72\u00A74" + private const val UPGRADES_MARKER = "\u00A70\u00A71\u00A72\u00A75" + private const val ITEMS_MARKER = "\u00A70\u00A71\u00A72\u00A76" + private const val TOP_BAR_COLOR = 0xFF1A1A + private const val BOTTOM_BAR_COLOR = 0xFFFF40 + private val GUI_CONTROLS_LOCATION = ResourceLocation(GUI_CONTROLS) + private val TWO_DIGIT_FORMAT = DecimalFormat("#.00", DecimalFormatSymbols(Locale.ROOT)) + private val ONE_DIGIT_FORMAT = DecimalFormat("##.0", DecimalFormatSymbols(Locale.ROOT)) + private val SUFFIXES = arrayOf("k", "m", "b") + + fun shouldShowContentsTooltip(): Boolean { + val player = Minecraft.getMinecraft().player + return GuiScreen.isShiftKeyDown() || player != null && !player.inventory.itemStack.isEmpty + } + + fun addTooltipLines(wrapper: BackpackWrapper, tooltip: MutableList) { + val data = TooltipData.of(wrapper) + data.summaryLines().forEach(tooltip::add) + data.blocks.forEach { block -> + repeat(block.placeholderRows) { row -> + tooltip.add(if (row == 0) block.marker else block.placeholderLine(data.width)) + } + } + } + + @SubscribeEvent + @JvmStatic + fun onTooltipPostText(event: RenderTooltipEvent.PostText) { + if (event.stack.item !is BackpackItem || !shouldShowContentsTooltip()) { + return + } + val wrapper = event.stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: return + val data = TooltipData.of(wrapper) + data.blocks.forEach { block -> + val lineIndex = event.lines.indexOfFirst { it.contains(block.marker) } + if (lineIndex >= 0) { + block.render(data, event.x, lineTop(event.y, lineIndex)) + } + } + } + + private fun lineTop(tooltipY: Int, lineIndex: Int): Int = + tooltipY + if (lineIndex == 0) 0 else 12 + (lineIndex - 1) * 10 + + private fun renderGaugeTitle(title: String, leftX: Int, topY: Int) { + Minecraft.getMinecraft().fontRenderer.drawStringWithShadow( + TextFormatting.YELLOW.toString() + title, + leftX.toFloat(), + topY.toFloat(), + -1 + ) + } + + private inline fun renderRotatedGauge(leftX: Int, topY: Int, render: () -> Unit) { + GlStateManager.pushMatrix() + GlStateManager.translate(leftX.toFloat(), topY + GAUGE_TEXTURE_HEIGHT * GAUGE_SCALE, 0f) + GlStateManager.scale(GAUGE_SCALE, GAUGE_SCALE, 1f) + GlStateManager.rotate(-90f, 0f, 0f, 1f) + render() + GlStateManager.popMatrix() + } + + private fun renderVerticalGaugeBackground() { + val mc = Minecraft.getMinecraft() + mc.textureManager.bindTexture(GUI_CONTROLS_LOCATION) + GlStateManager.color(1f, 1f, 1f, 1f) + drawTexturedRect(0, 0, 29, 30, 18, 18) + drawTexturedRect(0, 18, 29, 48, 18, 18) + drawTexturedRect(0, 36, 29, 66, 18, 18) + } + + private fun renderVerticalGaugeOverlay(overlayU: Int, overlayV: Int) { + val mc = Minecraft.getMinecraft() + mc.textureManager.bindTexture(GUI_CONTROLS_LOCATION) + GlStateManager.color(1f, 1f, 1f, 1f) + repeat(GAUGE_TEXTURE_WIDTH / 18) { + drawTexturedRect(1, it * 18, overlayU, overlayV, 16, 18) + } + } + + private fun renderTank(data: TooltipData, leftX: Int, topY: Int) { + val mc = Minecraft.getMinecraft() + val title = I18n.format("tooltip.backpack.fluid_title".asTranslationKey()) + renderGaugeTitle(title, leftX, topY) + data.tanks.forEachIndexed { index, tank -> + val gaugeY = topY + TITLE_HEIGHT + index * (GAUGE_RENDER_HEIGHT + 2) + val fluid = tank.fluid + renderRotatedGauge(leftX, gaugeY) { + renderVerticalGaugeBackground() + if (fluid != null && fluid.amount > 0) { + val displayLevel = ((GAUGE_TEXTURE_WIDTH - 2) * (fluid.amount.toFloat() / tank.capacity.coerceAtLeast(1))).toInt() + .coerceIn(1, GAUGE_TEXTURE_WIDTH - 2) + GuiDraw.drawFluidTexture( + fluid, + 1f, + 1f, + 16f, + displayLevel.toFloat(), + 300f + ) + } + renderVerticalGaugeOverlay(47, 30) + } + mc.fontRenderer.drawStringWithShadow( + if (fluid == null || fluid.amount <= 0) { + TextFormatting.BLUE.toString() + I18n.format("tooltip.backpack.fluid_empty".asTranslationKey()) + } else { + TextFormatting.BLUE.toString() + TextComponentTranslation( + "tooltip.backpack.fluid".asTranslationKey(), + TextFormatting.WHITE.toString() + abbreviate(fluid.amount), + TextFormatting.BLUE.toString() + fluid.localizedName + ).formattedText + }, + (leftX + GAUGE_TEXT_LEFT).toFloat(), + (gaugeY + 2).toFloat(), + -1 + ) + } + } + + private fun renderBattery(data: TooltipData, leftX: Int, topY: Int) { + val mc = Minecraft.getMinecraft() + renderGaugeTitle(I18n.format("tooltip.backpack.energy_title".asTranslationKey()), leftX, topY) + val gaugeY = topY + TITLE_HEIGHT + renderRotatedGauge(leftX, gaugeY) { + renderVerticalGaugeBackground() + renderVerticalGaugeOverlay(47, 56) + renderVerticalBatteryCharge(data.energyStored, data.energyCapacity) + mc.textureManager.bindTexture(GUI_CONTROLS_LOCATION) + GlStateManager.color(1f, 1f, 1f, 1f) + drawTexturedRect(1, 0, 47, 48, 16, 4) + drawTexturedRect(1, GAUGE_TEXTURE_WIDTH - 4, 47, 52, 16, 4) + } + mc.fontRenderer.drawStringWithShadow( + TextFormatting.RED.toString() + TextComponentTranslation( + "tooltip.backpack.energy".asTranslationKey(), + TextFormatting.WHITE.toString() + abbreviate(data.energyStored) + ).formattedText, + (leftX + GAUGE_TEXT_LEFT).toFloat(), + (gaugeY + 2).toFloat(), + -1 + ) + } + + private fun renderContentsTitle(title: String, leftX: Int, topY: Int) { + val mc = Minecraft.getMinecraft() + mc.fontRenderer.drawStringWithShadow(TextFormatting.YELLOW.toString() + title, leftX.toFloat(), topY.toFloat(), -1) + } + + private fun renderUpgradesBlock(data: TooltipData, leftX: Int, topY: Int) { + renderContentsTitle(I18n.format("tooltip.backpack.upgrades_title".asTranslationKey()), leftX, topY) + renderUpgrades(data.upgrades, leftX, topY + TITLE_HEIGHT) + } + + private fun renderItemsBlock(data: TooltipData, leftX: Int, topY: Int) { + renderContentsTitle(I18n.format("tooltip.backpack.inventory_title".asTranslationKey()), leftX, topY) + renderItems(data.items, leftX, topY + TITLE_HEIGHT) + } + + private fun renderUpgrades(stacks: List, leftX: Int, topY: Int) { + val mc = Minecraft.getMinecraft() + withItemLighting { + stacks.forEachIndexed { index, stack -> + val x = leftX + index * STACK_WIDTH + mc.renderItem.renderItemAndEffectIntoGUI(stack, x, topY) + } + } + } + + private fun renderItems(stacks: List, leftX: Int, topY: Int) { + val mc = Minecraft.getMinecraft() + withItemLighting { + var x = leftX + stacks.forEachIndexed { index, stack -> + if (index % MAX_STACKS_ON_LINE == 0) { + x = leftX + } + val y = topY + index / MAX_STACKS_ON_LINE * ROW_HEIGHT + val count = abbreviate(stack.count) + val width = maxOf(mc.fontRenderer.getStringWidth(count) + COUNT_PADDING, STACK_WIDTH) + val offset = width - STACK_WIDTH + mc.renderItem.renderItemAndEffectIntoGUI(stack, x + offset, y) + mc.renderItem.renderItemOverlayIntoGUI(mc.fontRenderer, stack, x + offset, y, count) + x += width + } + } + } + + private inline fun withItemLighting(render: () -> Unit) { + val mc = Minecraft.getMinecraft() + RenderHelper.enableGUIStandardItemLighting() + GlStateManager.enableDepth() + GlStateManager.enableRescaleNormal() + mc.renderItem.zLevel = 300f + render() + mc.renderItem.zLevel = 0f + GlStateManager.disableLighting() + GlStateManager.disableDepth() + } + + private fun renderVerticalBatteryCharge(energyStored: Int, maxEnergyStored: Int) { + if (maxEnergyStored <= 0 || energyStored <= 0) { + return + } + val mc = Minecraft.getMinecraft() + mc.textureManager.bindTexture(GUI_CONTROLS_LOCATION) + GlStateManager.enableTexture2D() + GlStateManager.enableBlend() + val numberOfSegments = GAUGE_TEXTURE_WIDTH / CHARGE_SEGMENT_HEIGHT + val displayLevel = (numberOfSegments * (energyStored.toFloat() / maxEnergyStored)).toInt() + for (segmentIndex in 0 until displayLevel) { + val percentage = if (numberOfSegments <= 1) 0f else segmentIndex.toFloat() / (numberOfSegments - 1) + GlStateManager.color( + colorChannel(BOTTOM_BAR_COLOR, 16, percentage, TOP_BAR_COLOR) / 255f, + colorChannel(BOTTOM_BAR_COLOR, 8, percentage, TOP_BAR_COLOR) / 255f, + colorChannel(BOTTOM_BAR_COLOR, 0, percentage, TOP_BAR_COLOR) / 255f, + 1f + ) + drawTexturedRect(1, GAUGE_TEXTURE_WIDTH - (segmentIndex + 1) * CHARGE_SEGMENT_HEIGHT, 47, 74, 16, CHARGE_SEGMENT_HEIGHT) + } + GlStateManager.color(1f, 1f, 1f, 1f) + } + + private fun colorChannel(bottom: Int, shift: Int, percentage: Float, top: Int): Int { + val bottomChannel = bottom shr shift and 255 + val topChannel = top shr shift and 255 + return (bottomChannel * (1 - percentage) + topChannel * percentage).toInt() + } + + private fun drawTexturedRect(x: Int, y: Int, u: Int, v: Int, width: Int, height: Int) { + val minU = u / GUI_CONTROLS_SIZE + val maxU = (u + width) / GUI_CONTROLS_SIZE + val minV = v / GUI_CONTROLS_SIZE + val maxV = (v + height) / GUI_CONTROLS_SIZE + drawSprite(x, y, width, height, minU, maxU, minV, maxV) + } + + private fun drawSprite(x: Int, y: Int, width: Int, height: Int, minU: Float, maxU: Float, minV: Float, maxV: Float) { + val tessellator = Tessellator.getInstance() + val buffer = tessellator.buffer + buffer.begin(7, DefaultVertexFormats.POSITION_TEX) + buffer.pos(x.toDouble(), (y + height).toDouble(), 300.0).tex(minU.toDouble(), maxV.toDouble()).endVertex() + buffer.pos((x + width).toDouble(), (y + height).toDouble(), 300.0).tex(maxU.toDouble(), maxV.toDouble()).endVertex() + buffer.pos((x + width).toDouble(), y.toDouble(), 300.0).tex(maxU.toDouble(), minV.toDouble()).endVertex() + buffer.pos(x.toDouble(), y.toDouble(), 300.0).tex(minU.toDouble(), minV.toDouble()).endVertex() + tessellator.draw() + } + + private data class TooltipData( + val items: List, + val upgrades: List, + val summary: List, + val tanks: List, + val energyStored: Int, + val energyCapacity: Int + ) { + val blocks: List = + buildList { + if (tanks.isNotEmpty()) add(TooltipBlock.Tank(tanks.size)) + if (energyCapacity > 0) add(TooltipBlock.Battery) + if (upgrades.isNotEmpty()) add(TooltipBlock.Upgrades) + if (items.isNotEmpty()) add(TooltipBlock.Items(items.size)) + } + + fun summaryLines(): List = + if (summary.isEmpty() && blocks.isEmpty()) { + listOf(TextFormatting.YELLOW.toString() + I18n.format("tooltip.backpack.empty".asTranslationKey())) + } else summary + + val width: Int by lazy { + val mc = Minecraft.getMinecraft() + val lineWidth = summaryLines().maxOfOrNull(mc.fontRenderer::getStringWidth) ?: 0 + maxOf(lineWidth, stackWidth(upgrades), stackWidth(items), gaugeWidth()) + } + + private fun stackWidth(stacks: List): Int = + stacks.take(MAX_STACKS_ON_LINE).sumOf { stack -> + maxOf(Minecraft.getMinecraft().fontRenderer.getStringWidth(abbreviate(stack.count)) + COUNT_PADDING, STACK_WIDTH) + } + + private fun gaugeWidth(): Int { + val mc = Minecraft.getMinecraft() + val tankTextWidth = tanks.maxOfOrNull { + val fluid = it.fluid + if (fluid == null || fluid.amount <= 0) mc.fontRenderer.getStringWidth(I18n.format("tooltip.backpack.fluid_empty".asTranslationKey())) + else mc.fontRenderer.getStringWidth(I18n.format("tooltip.backpack.fluid".asTranslationKey(), abbreviate(fluid.amount), fluid.localizedName)) + } ?: 0 + val energyTextWidth = if (energyCapacity > 0) mc.fontRenderer.getStringWidth(I18n.format("tooltip.backpack.energy".asTranslationKey(), abbreviate(energyStored))) else 0 + return GAUGE_TEXT_LEFT + maxOf(tankTextWidth, energyTextWidth, 0) + } + + companion object { + fun of(wrapper: BackpackWrapper): TooltipData { + val items = compactItems(wrapper.backpackItemStackHandler.inventory.filterNot(ItemStack::isEmpty)) + val upgrades = wrapper.upgradeItemStackHandler.inventory.filterNot(ItemStack::isEmpty).map(ItemStack::copy) + val summary = mutableListOf() + addMultiplierTooltip(wrapper, summary) + val tanks = tanks(wrapper) + val energy = BackpackEnergyStorage(wrapper) + val energyCapacity = if (wrapper.hasBatteryUpgrade()) energy.maxEnergyStored else 0 + return TooltipData(items, upgrades, summary, tanks, energy.energyStored, energyCapacity) + } + + private fun compactItems(stacks: List): List = + stacks.fold(mutableListOf()) { compacted, stack -> + val matching = compacted.firstOrNull { ItemStack.areItemsEqual(it, stack) && ItemStack.areItemStackTagsEqual(it, stack) } + if (matching == null) { + compacted.add(stack.copy()) + } else { + matching.count += stack.count + } + compacted + }.sortedByDescending(ItemStack::getCount) + + private fun addMultiplierTooltip(wrapper: BackpackWrapper, tooltip: MutableList) { + val multiplier = wrapper.getTotalStackMultiplier() + if (multiplier > 1) { + tooltip.add( + TextFormatting.GREEN.toString() + TextComponentTranslation( + "tooltip.backpack.stack_multiplier".asTranslationKey(), + TextFormatting.WHITE.toString() + multiplier + ).formattedText + ) + } + } + + private fun tanks(wrapper: BackpackWrapper): List = + if (!wrapper.hasTankUpgrade()) emptyList() + else BackpackFluidHandler(wrapper).tankProperties.map { TankTooltipInfo(it.contents?.copy(), it.capacity) } + } + } + + private data class TankTooltipInfo(val fluid: FluidStack?, val capacity: Int) + + private sealed class TooltipBlock( + val marker: String, + private val height: Int, + private val renderer: (TooltipData, Int, Int) -> Unit + ) { + val placeholderRows: Int = (height + 9) / 10 + + fun placeholderLine(width: Int): String = + " ".repeat((width + 3) / 4) + + fun render(data: TooltipData, x: Int, y: Int) { + renderer(data, x, y) + } + + class Tank(tankCount: Int) : TooltipBlock(TANK_MARKER, TITLE_HEIGHT + tankCount * (GAUGE_RENDER_HEIGHT + 2) + 2, ::renderTank) + object Battery : TooltipBlock(BATTERY_MARKER, TITLE_HEIGHT + GAUGE_RENDER_HEIGHT + 2, ::renderBattery) + object Upgrades : TooltipBlock(UPGRADES_MARKER, TITLE_HEIGHT + ROW_HEIGHT + 2, ::renderUpgradesBlock) + class Items(itemCount: Int) : TooltipBlock(ITEMS_MARKER, TITLE_HEIGHT + ((itemCount + MAX_STACKS_ON_LINE - 1) / MAX_STACKS_ON_LINE) * ROW_HEIGHT + 2, ::renderItemsBlock) + } + + private fun abbreviate(count: Int, maxCharacters: Int = 4): String { + val digits = count.toString().length + if (digits <= maxCharacters) { + return String.format(Locale.ROOT, "%,d", count) + } + val thousandsExponent = (digits - maxCharacters) / 3 + 1 + val suffix = SUFFIXES.getOrElse(thousandsExponent - 1) { "b" } + val divisionResult = count / Math.pow(1000.0, thousandsExponent.toDouble()) + val wholeDigits = digits - thousandsExponent * 3 + val precisionDigits = maxCharacters - 1 - wholeDigits + val numberPart = when { + wholeDigits > 3 || precisionDigits == 0 -> String.format(Locale.ROOT, "%,d", divisionResult.toInt()) + precisionDigits == 2 -> TWO_DIGIT_FORMAT.format(divisionResult) + precisionDigits == 1 -> ONE_DIGIT_FORMAT.format(divisionResult) + else -> divisionResult.toInt().toString() + } + return numberPart + suffix + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt index 1b0de98..3de569e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/ClientGuiStashHandler.kt @@ -8,12 +8,14 @@ import com.cleanroommc.retrosophisticatedbackpacks.common.gui.slot.ModularBackpa import com.cleanroommc.retrosophisticatedbackpacks.mixin.GuiContainerAccessor import com.cleanroommc.retrosophisticatedbackpacks.network.C2SStashToBackpackPacket import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.RenderHelper import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.gui.inventory.GuiContainerCreative import net.minecraft.entity.player.EntityPlayer import net.minecraft.inventory.Slot import net.minecraft.item.ItemStack -import net.minecraftforge.client.event.GuiScreenEvent +import net.minecraftforge.client.event.GuiContainerEvent import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.relauncher.Side @@ -27,8 +29,8 @@ object ClientGuiStashHandler { @SubscribeEvent @JvmStatic - fun onDrawScreenPost(event: GuiScreenEvent.DrawScreenEvent.Post) { - val screen = event.gui as? GuiContainer ?: return + fun onDrawForeground(event: GuiContainerEvent.DrawForeground) { + val screen = event.guiContainer if (screen is GuiContainerCreative) { return } @@ -39,12 +41,11 @@ object ClientGuiStashHandler { return } - val accessor = screen as GuiContainerAccessor - for (slot in player.openContainer.inventorySlots) { + for (slot in screen.inventorySlots.inventorySlots) { if (slot is ModularBackpackSlot || !slot.isEnabled || slot.xPos < -100 || slot.yPos < -100) { continue } - drawStashSign(screen, accessor, player, slot, carried) + drawStashSign(player, slot, carried) } } @@ -93,8 +94,6 @@ object ClientGuiStashHandler { } private fun drawStashSign( - screen: GuiContainer, - accessor: GuiContainerAccessor, player: EntityPlayer, slot: Slot, carried: ItemStack @@ -107,10 +106,10 @@ object ClientGuiStashHandler { } if (plusResult != Result.NO_SPACE) { - Minecraft.getMinecraft().fontRenderer.drawStringWithShadow( + drawStashText( "+", - (accessor.guiLeft + slot.xPos + 10).toFloat(), - (accessor.guiTop + slot.yPos + 8).toFloat(), + (slot.xPos + 10).toFloat(), + (slot.yPos + 8).toFloat(), color(plusResult) ) return @@ -127,14 +126,22 @@ object ClientGuiStashHandler { return } - Minecraft.getMinecraft().fontRenderer.drawStringWithShadow( + drawStashText( "-", - (accessor.guiLeft + slot.xPos + 1).toFloat(), - (accessor.guiTop + slot.yPos).toFloat(), + (slot.xPos + 1).toFloat(), + slot.yPos.toFloat(), color(minusResult) ) } + private fun drawStashText(text: String, x: Float, y: Float, color: Int) { + GlStateManager.disableLighting() + GlStateManager.disableDepth() + Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(text, x, y, color) + GlStateManager.enableDepth() + RenderHelper.enableGUIStandardItemLighting() + } + private fun getStashAction( player: EntityPlayer, slot: Slot, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt index 512e855..2ee7a69 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt @@ -4,7 +4,6 @@ import baubles.api.BaubleType import baubles.api.IBauble import baubles.api.render.IRenderBauble import com.cleanroommc.modularui.api.IGuiHolder -import com.cleanroommc.modularui.api.widget.Interactable import com.cleanroommc.modularui.screen.ModularPanel import com.cleanroommc.modularui.screen.UISettings import com.cleanroommc.modularui.value.sync.PanelSyncManager @@ -12,10 +11,9 @@ import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHelper import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackTier import com.cleanroommc.retrosophisticatedbackpacks.block.BackpackBlock -import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackEnergyStorage -import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackFluidHandler import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.handler.BackpackTooltipHandler import com.cleanroommc.retrosophisticatedbackpacks.client.BackpackBipedModel import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackContainer import com.cleanroommc.retrosophisticatedbackpacks.common.gui.BackpackGuiHolder @@ -43,8 +41,6 @@ import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.* import net.minecraft.util.math.BlockPos -import net.minecraft.util.text.Style -import net.minecraft.util.text.TextComponentString import net.minecraft.util.text.TextComponentTranslation import net.minecraft.util.text.TextFormatting import net.minecraft.world.World @@ -278,101 +274,22 @@ class BackpackItem( flagIn: ITooltipFlag ) { val wrapper = stack.getCapability(Capabilities.BACKPACK_CAPABILITY, null) - if (!Interactable.hasShiftDown()) { - tooltip.add(TextComponentTranslation("tooltip.shift_to_reveal".asTranslationKey()).formattedText) - return + if (flagIn.isAdvanced && wrapper != null) { + tooltip.add(TextFormatting.DARK_GRAY.toString() + "UUID: ${wrapper.uuid}") } - - if (wrapper == null) { - tooltip.add(TextComponentTranslation("tooltip.backpack.inventory_size".asTranslationKey(), numberOfSlots()).formattedText) + if (!BackpackTooltipHandler.shouldShowContentsTooltip()) { tooltip.add( TextComponentTranslation( - "tooltip.backpack.upgrade_slots_size".asTranslationKey(), - numberOfUpgradeSlots() - ).formattedText + "tooltip.backpack.press_for_contents".asTranslationKey(), + TextComponentTranslation("tooltip.backpack.shift".asTranslationKey()) + .setStyle(net.minecraft.util.text.Style().setColor(TextFormatting.AQUA)) + .formattedText + ).setStyle(net.minecraft.util.text.Style().setColor(TextFormatting.GRAY)).formattedText ) return } - val itemStacks = wrapper.backpackItemStackHandler.inventory.filter { !it.isEmpty } - val upgradeStacks = wrapper.upgradeItemStackHandler.inventory.filter { !it.isEmpty } - val itemCount = itemStacks.fold(0) { total, itemStack -> total + itemStack.count } - - tooltip.add( - TextComponentTranslation( - "tooltip.backpack.items".asTranslationKey(), - itemStacks.size, - wrapper.backpackInventorySize(), - itemCount - ).formattedText - ) - tooltip.add( - TextComponentTranslation( - "tooltip.backpack.upgrades".asTranslationKey(), - upgradeStacks.size, - wrapper.upgradeSlotsSize() - ).formattedText - ) - addStackMultiplierTooltip(wrapper, tooltip) - addFluidTooltip(wrapper, tooltip) - addEnergyTooltip(wrapper, tooltip) - if (itemStacks.isEmpty() && upgradeStacks.isEmpty()) { - tooltip.add(TextComponentTranslation("tooltip.backpack.empty".asTranslationKey()).formattedText) - } - } - - private fun addStackMultiplierTooltip(wrapper: BackpackWrapper, tooltip: MutableList) { - val multiplier = wrapper.getTotalStackMultiplier() - if (multiplier <= 1) { - return - } - val stackHint = - if (wrapper.isStackedByMultiplication()) "(xM)" - else "(+M)" - - tooltip.add( - TextComponentTranslation( - "tooltip.backpack.stack_multiplier".asTranslationKey(), - multiplier, - TextComponentString(stackHint).setStyle(Style().setColor(TextFormatting.RED)).formattedText - ).formattedText - ) - } - - private fun addFluidTooltip(wrapper: BackpackWrapper, tooltip: MutableList) { - if (!wrapper.hasTankUpgrade()) { - return - } - val tanks = BackpackFluidHandler(wrapper).tankProperties - for (tank in tanks) { - val contents = tank.contents - tooltip.add( - if (contents == null || contents.amount <= 0) { - TextComponentTranslation("tooltip.backpack.fluid_empty".asTranslationKey(), 0, tank.capacity).formattedText - } else { - TextComponentTranslation( - "tooltip.backpack.fluid".asTranslationKey(), - contents.amount, - tank.capacity, - contents.localizedName - ).formattedText - } - ) - } - } - - private fun addEnergyTooltip(wrapper: BackpackWrapper, tooltip: MutableList) { - if (!wrapper.hasBatteryUpgrade()) { - return - } - val energy = BackpackEnergyStorage(wrapper) - tooltip.add( - TextComponentTranslation( - "tooltip.backpack.energy".asTranslationKey(), - energy.energyStored, - energy.maxEnergyStored - ).formattedText - ) + wrapper?.let { BackpackTooltipHandler.addTooltipLines(it, tooltip) } } override fun buildUI( diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang index 023034b..47b6ae3 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang @@ -36,13 +36,17 @@ retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpacks # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=Inventory size: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=Upgrade slots: %d -retro_sophisticated_backpacks.tooltip.backpack.items=Items: %d/%d slots, %d total -retro_sophisticated_backpacks.tooltip.backpack.upgrades=Upgrades: %d/%d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> Stack multiplier: %d %s -retro_sophisticated_backpacks.tooltip.backpack.fluid=Fluid: %d/%d mB %s -retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Fluid: %d/%d mB -retro_sophisticated_backpacks.tooltip.backpack.energy=Energy: %d/%d FE -retro_sophisticated_backpacks.tooltip.backpack.empty=Empty +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids +retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory +retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents +retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift retro_sophisticated_backpacks.tooltip.upgrade_base=It does nothing! Feel free to put it in your upgrade slots! diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang index c771c8d..0f44b1d 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang @@ -21,7 +21,17 @@ itemGroup.retro_sophisticated_backpacks.creative_tab=Mochila Sofisticada Retro #Descripciones emergentes (Tooltips) retro_sophisticated_backpacks.tooltip.backpack.inventory_size=Tamaño de inventario: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=Tamaño de ranuras de mejora: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> Multiplicador de apilado: %d %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids +retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory +retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents +retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift retro_sophisticated_backpacks.tooltip.upgrade_base=¡No hace nada! Siéntete libre de ponerlo en tus ranuras de mejora. diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang index 952d930..13b9e42 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang @@ -36,7 +36,17 @@ retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpacks # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=インベントリスロット数: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=アップグレードスロット数: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> スタック上限倍率: %d倍 %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids +retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory +retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents +retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift retro_sophisticated_backpacks.tooltip.upgrade_base=何もしません! ご自由にアップグレードスロットに入れてください! diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang index 6094eeb..b16e124 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang @@ -36,7 +36,17 @@ retro_sophisticated_backpacks.key.category=레트로 복잡한 배낭 # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=인벤토리 크기: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=업그레이드 슬롯: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> 묶음 배율: %d %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids +retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory +retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents +retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift retro_sophisticated_backpacks.tooltip.upgrade_base=아무 기능도 없습니다! 업그레이드 슬롯에 마음껏 넣으세요! diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang index 0b64b51..51c206b 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang @@ -29,7 +29,17 @@ retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpack # Podpowiedzi retro_sophisticated_backpacks.tooltip.backpack.inventory_size=Rozmiar ekwipunku: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=Sloty ulepszeń: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> Mnożnik stosu: %d %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids +retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory +retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents +retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift retro_sophisticated_backpacks.tooltip.upgrade_base=Nic nie robi! Możesz umieścić ją w miejscu na ulepszenia! diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang index ef23049..985e566 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang @@ -21,7 +21,17 @@ itemGroup.retro_sophisticated_backpacks.creative_tab=Ретро Современ #Всплывающие подсказки (Tooltips) retro_sophisticated_backpacks.tooltip.backpack.inventory_size=Размер инвентаря: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=Размер слотов для улучшений: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> Множитель стаков: %d %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids +retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory +retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents +retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift retro_sophisticated_backpacks.tooltip.upgrade_base=Ничего не делает! Можете положить в слоты для улучшений! diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang index f1cdfba..71358da 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang @@ -36,13 +36,17 @@ retro_sophisticated_backpacks.key.category=复古精妙背包 # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=背包容量:%d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=升级插槽:%d -retro_sophisticated_backpacks.tooltip.backpack.items=物品:%d/%d 槽,合计 %d 个 -retro_sophisticated_backpacks.tooltip.backpack.upgrades=升级:%d/%d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> 堆叠倍数:%d %s -retro_sophisticated_backpacks.tooltip.backpack.fluid=流体:%d/%d mB %s -retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=流体:%d/%d mB -retro_sophisticated_backpacks.tooltip.backpack.energy=能量:%d/%d FE -retro_sophisticated_backpacks.tooltip.backpack.empty=空 +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=堆叠倍数:%s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=空罐 +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=流体 +retro_sophisticated_backpacks.tooltip.backpack.energy_title=能量 +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=升级 +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=物品 +retro_sophisticated_backpacks.tooltip.backpack.empty=未加装升级或物品存储 +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=按<%s>查看内容 +retro_sophisticated_backpacks.tooltip.backpack.shift=左Shift retro_sophisticated_backpacks.tooltip.upgrade_base=没有任何效果!大可放进升级插槽里! diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang index f751a2a..d3b1a5c 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang @@ -36,7 +36,17 @@ retro_sophisticated_backpacks.key.category=復古精緻背包 # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=背包容量: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=升級插槽: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=-> 當前堆疊倍率: %d %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=堆疊倍數:%s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=空罐 +retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_title=流體 +retro_sophisticated_backpacks.tooltip.backpack.energy_title=能量 +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=升級 +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=物品 +retro_sophisticated_backpacks.tooltip.backpack.empty=未加裝升級或物品存儲 +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=按<%s>查看內容 +retro_sophisticated_backpacks.tooltip.backpack.shift=左 Shift retro_sophisticated_backpacks.tooltip.upgrade_base=沒有效果!你大可放在升級插槽! From 8777257396be530b810b7767fecb14f37ce830ab Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Wed, 10 Jun 2026 22:46:46 +0800 Subject: [PATCH 08/10] Fix some upgrades behavior and GUIs --- .../capability/BackpackWrapper.kt | 37 +- .../upgrade/AdvancedFilterUpgradeWrapper.kt | 3 +- .../upgrade/AdvancedUpgradeWrapper.kt | 21 +- .../capability/upgrade/AnvilUpgradeWrapper.kt | 20 +- .../capability/upgrade/BasicUpgradeWrapper.kt | 9 +- .../upgrade/BatteryUpgradeWrapper.kt | 6 +- .../upgrade/CompactingUpgradeWrapper.kt | 12 +- .../upgrade/CraftingUpgradeWrapper.kt | 6 +- .../capability/upgrade/DiscHandlerRegistry.kt | 91 ++++ .../upgrade/FilterUpgradeWrapper.kt | 3 +- .../capability/upgrade/IAdvancedFilterable.kt | 12 +- .../capability/upgrade/IContentsFilterable.kt | 18 + .../capability/upgrade/IMagnetUpgrade.kt | 4 +- .../upgrade/JukeboxUpgradeWrapper.kt | 96 ++-- .../upgrade/MagnetUpgradeWrapper.kt | 120 ++++- .../capability/upgrade/PumpUpgradeWrapper.kt | 6 +- .../upgrade/RefillUpgradeWrapper.kt | 46 +- .../capability/upgrade/TankUpgradeWrapper.kt | 8 +- .../capability/upgrade/VoidUpgradeWrapper.kt | 12 +- .../client/gui/BackpackPanel.kt | 32 +- .../client/gui/RSBTextures.kt | 19 + .../gui/widgets/BackpackMainSettingsWidget.kt | 7 +- .../gui/widgets/CyclicVariantButtonWidget.kt | 10 +- .../upgrade/AdvancedExpandedTabWidget.kt | 16 +- .../widgets/upgrade/AdvancedFilterWidget.kt | 121 ++++- .../widgets/upgrade/BasicExpandedTabWidget.kt | 22 +- .../gui/widgets/upgrade/BasicFilterWidget.kt | 65 ++- .../upgrade/CompactingUpgradeWidget.kt | 56 ++- .../widgets/upgrade/JukeboxUpgradeWidget.kt | 176 +++++-- .../widgets/upgrade/MagnetUpgradeWidget.kt | 67 +++ .../widgets/upgrade/RefillUpgradeWidget.kt | 131 ++++-- .../gui/widgets/upgrade/VoidUpgradeWidget.kt | 106 ++++- .../item/BackpackItem.kt | 3 +- .../item/CraftingUpgradeItem.kt | 10 +- .../item/StackUpgradeItem.kt | 4 +- .../item/UpgradeItem.kt | 17 +- .../sync/UpgradeSlotSH.kt | 15 + .../tileentity/BackpackTileEntity.kt | 2 +- .../lang/en_us.lang | 249 +++++----- .../lang/es_es.lang | 402 +++++++++++----- .../lang/ja_jp.lang | 439 +++++++++++------- .../lang/ko_kr.lang | 427 ++++++++++------- .../lang/pl_pl.lang | 358 +++++++++----- .../lang/ru_ru.lang | 400 +++++++++++----- .../lang/zh_cn.lang | 297 ++++++------ .../lang/zh_tw.lang | 407 +++++++++------- 46 files changed, 3006 insertions(+), 1382 deletions(-) create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DiscHandlerRegistry.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IContentsFilterable.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt index 4fe37d0..ba246f6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt @@ -105,6 +105,7 @@ class BackpackWrapper( private val itemDisplaySlots = linkedSetOf() private val itemDisplayRotations = mutableMapOf() private val slotsToCompact = mutableSetOf() + private var compactingSlotsInitialized = false private val slotsToVoid = mutableSetOf() val capturedMobs: MutableList = mutableListOf() var capturedMobsColumns = 0 @@ -328,7 +329,7 @@ class BackpackWrapper( if (player != null) { gatherCapabilityUpgrades(Capabilities.IREFILL_UPGRADE_CAPABILITY).forEach { it.refill(player, this) } } else if (gatherCapabilityUpgrades(Capabilities.IREFILL_UPGRADE_CAPABILITY).isNotEmpty()) { - val players = world.getEntitiesWithinAABB(EntityPlayer::class.java, AxisAlignedBB(x - 3, y - 3, z - 3, x + 3, y + 3, z + 3)) + val players = world.getEntitiesWithinAABB(EntityPlayer::class.java, AxisAlignedBB(pos).grow(3.0)) players.forEach { nearbyPlayer -> gatherCapabilityUpgrades(Capabilities.IREFILL_UPGRADE_CAPABILITY).forEach { it.refill(nearbyPlayer, this) } } @@ -336,7 +337,7 @@ class BackpackWrapper( } if (world.totalWorldTime % 10L == 0L) { - magnetItems(player, world, x, y, z) + magnetItems(player, world, pos) } gatherCapabilityUpgrades(Capabilities.ITANK_UPGRADE_CAPABILITY).forEach { it.tick(this, world) } @@ -347,7 +348,16 @@ class BackpackWrapper( val compactingUpgrades = gatherCapabilityUpgrades(Capabilities.ICOMPACTING_UPGRADE_CAPABILITY) if (compactingUpgrades.isNotEmpty()) { - compactingUpgrades.forEach { it.compact(this, world) } + if (!compactingSlotsInitialized) { + slotsToCompact.addAll(0 until slots) + compactingSlotsInitialized = true + } + if (world.totalWorldTime % 5L == 0L && slotsToCompact.isNotEmpty()) { + compactingUpgrades.forEach { it.compact(this, world) } + slotsToCompact.clear() + } + } else { + compactingSlotsInitialized = false slotsToCompact.clear() } @@ -375,17 +385,17 @@ class BackpackWrapper( } } - private fun magnetItems(player: EntityPlayer?, world: World, x: Double, y: Double, z: Double) { + private fun magnetItems(player: EntityPlayer?, world: World, pos: BlockPos) { val magnetUpgrades = gatherCapabilityUpgrades(Capabilities.IMAGNET_UPGRADE_CAPABILITY) if (magnetUpgrades.isEmpty()) { return } val range = magnetUpgrades.map(IMagnetUpgrade::range).max() - val items = world.getEntitiesWithinAABB(EntityItem::class.java, AxisAlignedBB(x - range, y - range, z - range, x + range, y + range, z + range)) + val items = world.getEntitiesWithinAABB(EntityItem::class.java, AxisAlignedBB(pos).grow(range)) for (entityItem in items) { - if (entityItem.isDead || (entityItem as EntityItemAccessor).`rsb$getPickupDelay`() == 32767 || magnetUpgrades.none { it.canPickup(entityItem.item) }) { + if (entityItem.isDead || (entityItem as EntityItemAccessor).`rsb$getPickupDelay`() == 32767 || magnetUpgrades.none { it.canPickup(entityItem.item, this) }) { continue } @@ -549,6 +559,21 @@ class BackpackWrapper( private fun hasMatchingStack(stack: ItemStack): Boolean = backpackItemStackHandler.inventory.any { !it.isEmpty && ItemHandlerHelper.canItemStacksStack(it, stack) } + fun matchesStorageContents(stack: ItemStack, matcher: (ItemStack, ItemStack) -> Boolean): Boolean = + (0 until slots).any { + val storedStack = getStackInSlot(it) + (!storedStack.isEmpty && matcher(stack, storedStack)) || matchesMemoryStack(it, stack, matcher) + } + + private fun matchesMemoryStack(slotIndex: Int, stack: ItemStack, matcher: (ItemStack, ItemStack) -> Boolean): Boolean { + val memoryStack = getMemorizedStack(slotIndex) + return !memoryStack.isEmpty && if (isMemoryStackRespectNBT(slotIndex)) { + stack.isItemEqual(memoryStack) && stack.tagCompound == memoryStack.tagCompound + } else { + matcher(stack, memoryStack) + } + } + private fun isFull(): Boolean = (0 until slots).all { val stack = getStackInSlot(it) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt index 7f61aca..76c5213 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedFilterUpgradeWrapper.kt @@ -42,6 +42,7 @@ class AdvancedFilterUpgradeWrapper : override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - filterWay = IFilterUpgrade.FilterWayType.entries[nbt.getByte(IFilterUpgrade.FILTER_WAY_TAG).toInt()] + if (nbt.hasKey(IFilterUpgrade.FILTER_WAY_TAG)) + filterWay = IFilterUpgrade.FilterWayType.entries.getOrElse(nbt.getByte(IFilterUpgrade.FILTER_WAY_TAG).toInt()) { filterWay } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt index 67fdaa0..5e59b91 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AdvancedUpgradeWrapper.kt @@ -48,15 +48,24 @@ abstract class AdvancedUpgradeWrapper(filterSlots: Int = 16, override val slo override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - enabled = nbt.getBoolean(IToggleable.ENABLED_TAG) - filterItems.deserializeNBT(nbt.getCompoundTag(IBasicFilterable.FILTER_ITEMS_TAG)) - filterType = IBasicFilterable.FilterType.entries[nbt.getByte(IBasicFilterable.FILTER_TYPE_TAG).toInt()] - matchType = IAdvancedFilterable.MatchType.entries[nbt.getByte(IAdvancedFilterable.MATCH_TYPE_TAG).toInt()] - ignoreDurability = nbt.getBoolean(IAdvancedFilterable.IGNORE_DURABILITY_TAG) - ignoreNBT = nbt.getBoolean(IAdvancedFilterable.IGNORE_NBT_TAG) + if (nbt.hasKey(IToggleable.ENABLED_TAG)) + enabled = nbt.getBoolean(IToggleable.ENABLED_TAG) + if (nbt.hasKey(IBasicFilterable.FILTER_ITEMS_TAG)) + filterItems.deserializeNBT(nbt.getCompoundTag(IBasicFilterable.FILTER_ITEMS_TAG)) + if (nbt.hasKey(IBasicFilterable.FILTER_TYPE_TAG)) + filterType = IBasicFilterable.FilterType.entries.getOrElse(nbt.getByte(IBasicFilterable.FILTER_TYPE_TAG).toInt()) { filterType } + if (nbt.hasKey(IAdvancedFilterable.MATCH_TYPE_TAG)) + matchType = IAdvancedFilterable.MatchType.entries.getOrElse(nbt.getByte(IAdvancedFilterable.MATCH_TYPE_TAG).toInt()) { matchType } + if (nbt.hasKey(IAdvancedFilterable.IGNORE_DURABILITY_TAG)) + ignoreDurability = nbt.getBoolean(IAdvancedFilterable.IGNORE_DURABILITY_TAG) + if (nbt.hasKey(IAdvancedFilterable.IGNORE_NBT_TAG)) + ignoreNBT = nbt.getBoolean(IAdvancedFilterable.IGNORE_NBT_TAG) + if (!nbt.hasKey(IAdvancedFilterable.ORE_DICT_LIST_TAG)) + return val oreDictList = nbt.getTagList(IAdvancedFilterable.ORE_DICT_LIST_TAG, Constants.NBT.TAG_STRING) + oreDictEntries.clear() for (stringNBT in oreDictList) oreDictEntries.add((stringNBT as NBTTagString).string) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt index e88ebd2..6c8a441 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/AnvilUpgradeWrapper.kt @@ -95,12 +95,20 @@ class AnvilUpgradeWrapper : UpgradeWrapper(), IAnvilUpgrade { override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) - shouldShiftClickIntoStorage = if (nbt.hasKey(SHIFT_CLICK_TAG)) nbt.getBoolean(SHIFT_CLICK_TAG) else true - itemName = nbt.getString(ITEM_NAME_TAG) - maximumCost = nbt.getInteger(MAXIMUM_COST_TAG) - materialCost = nbt.getInteger(MATERIAL_COST_TAG) - result = if (nbt.hasKey(RESULT_TAG)) ItemStack(nbt.getCompoundTag(RESULT_TAG)) else ItemStack.EMPTY + if (nbt.hasKey(INVENTORY_TAG)) + inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) + if (nbt.hasKey(SHIFT_CLICK_TAG)) + shouldShiftClickIntoStorage = nbt.getBoolean(SHIFT_CLICK_TAG) + if (nbt.hasKey(ITEM_NAME_TAG)) + itemName = nbt.getString(ITEM_NAME_TAG) + if (nbt.hasKey(MAXIMUM_COST_TAG)) + maximumCost = nbt.getInteger(MAXIMUM_COST_TAG) + if (nbt.hasKey(MATERIAL_COST_TAG)) + materialCost = nbt.getInteger(MATERIAL_COST_TAG) + if (nbt.hasKey(RESULT_TAG)) + result = ItemStack(nbt.getCompoundTag(RESULT_TAG)) + else if (nbt.hasKey(INVENTORY_TAG)) + result = ItemStack.EMPTY } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt index d70882c..f42f32f 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BasicUpgradeWrapper.kt @@ -31,8 +31,11 @@ abstract class BasicUpgradeWrapper(filterSlots: Int = 9, override val slotsIn override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - enabled = nbt.getBoolean(IToggleable.ENABLED_TAG) - filterItems.deserializeNBT(nbt.getCompoundTag(IBasicFilterable.FILTER_ITEMS_TAG)) - filterType = IBasicFilterable.FilterType.entries[nbt.getByte(IBasicFilterable.FILTER_TYPE_TAG).toInt()] + if (nbt.hasKey(IToggleable.ENABLED_TAG)) + enabled = nbt.getBoolean(IToggleable.ENABLED_TAG) + if (nbt.hasKey(IBasicFilterable.FILTER_ITEMS_TAG)) + filterItems.deserializeNBT(nbt.getCompoundTag(IBasicFilterable.FILTER_ITEMS_TAG)) + if (nbt.hasKey(IBasicFilterable.FILTER_TYPE_TAG)) + filterType = IBasicFilterable.FilterType.entries.getOrElse(nbt.getByte(IBasicFilterable.FILTER_TYPE_TAG).toInt()) { filterType } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt index b273dc2..ab15c7d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/BatteryUpgradeWrapper.kt @@ -125,8 +125,10 @@ class BatteryUpgradeWrapper : UpgradeWrapper(), IBatteryUpgr override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - energyStored = nbt.getInteger(ENERGY_TAG) - inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) + if (nbt.hasKey(ENERGY_TAG)) + energyStored = nbt.getInteger(ENERGY_TAG) + if (nbt.hasKey(INVENTORY_TAG)) + inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt index 562e338..bdc278c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CompactingUpgradeWrapper.kt @@ -47,8 +47,10 @@ open class CompactingUpgradeWrapper : override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - compactNonUncraftable = nbt.getBoolean(COMPACT_NON_UNCRAFTABLE_TAG) - shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + if (nbt.hasKey(COMPACT_NON_UNCRAFTABLE_TAG)) + compactNonUncraftable = nbt.getBoolean(COMPACT_NON_UNCRAFTABLE_TAG) + if (nbt.hasKey(SHOULD_WORK_IN_GUI_TAG)) + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = @@ -92,8 +94,10 @@ class AdvancedCompactingUpgradeWrapper : override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - compactNonUncraftable = nbt.getBoolean(COMPACT_NON_UNCRAFTABLE_TAG) - shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + if (nbt.hasKey(COMPACT_NON_UNCRAFTABLE_TAG)) + compactNonUncraftable = nbt.getBoolean(COMPACT_NON_UNCRAFTABLE_TAG) + if (nbt.hasKey(SHOULD_WORK_IN_GUI_TAG)) + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CraftingUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CraftingUpgradeWrapper.kt index 59e0973..444c413 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CraftingUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/CraftingUpgradeWrapper.kt @@ -32,8 +32,10 @@ class CraftingUpgradeWrapper() : UpgradeWrapper() { override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - craftingDestination = CraftingDestination.entries[nbt.getByte(CRAFTING_DEST_TAG).toInt()] - craftMatrix.deserializeNBT(nbt.getCompoundTag(MATRIX_TAG)) + if (nbt.hasKey(CRAFTING_DEST_TAG)) + craftingDestination = CraftingDestination.entries.getOrElse(nbt.getByte(CRAFTING_DEST_TAG).toInt()) { craftingDestination } + if (nbt.hasKey(MATRIX_TAG)) + craftMatrix.deserializeNBT(nbt.getCompoundTag(MATRIX_TAG)) } enum class CraftingDestination { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DiscHandlerRegistry.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DiscHandlerRegistry.kt new file mode 100644 index 0000000..e333059 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/DiscHandlerRegistry.kt @@ -0,0 +1,91 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +import net.minecraft.init.Items +import net.minecraft.item.Item +import net.minecraft.item.ItemRecord +import net.minecraft.item.ItemStack +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import java.util.Collections + +interface IDiscHandler { + fun supports(stack: ItemStack): Boolean + fun playDisc(world: World, pos: BlockPos, stack: ItemStack): Boolean + fun stopDisc(world: World, pos: BlockPos) { + world.playEvent(null, DiscHandlerRegistry.RECORD_PLAY_EVENT, pos, 0) + } + + fun getMusicLengthInTicks(stack: ItemStack, world: World): Long? +} + +object DiscHandlerRegistry { + const val RECORD_PLAY_EVENT = 1010 + + private val handlers = mutableListOf(VanillaDiscHandler) + + @JvmStatic + fun getHandlers(): List = Collections.unmodifiableList(handlers) + + @JvmStatic + fun registerHandler(handler: IDiscHandler) { + handlers.add(handler) + } + + @JvmStatic + fun findHandler(stack: ItemStack): IDiscHandler? = + if (stack.isEmpty) null else handlers.firstOrNull { it.supports(stack) } + + @JvmStatic + fun isSupported(stack: ItemStack): Boolean = findHandler(stack) != null + + @JvmStatic + fun playDisc(world: World, pos: BlockPos, stack: ItemStack): Boolean = + findHandler(stack)?.playDisc(world, pos, stack) == true + + @JvmStatic + fun stopDisc(world: World, pos: BlockPos) { + handlers.firstOrNull()?.stopDisc(world, pos) + ?: world.playEvent(null, RECORD_PLAY_EVENT, pos, 0) + } + + @JvmStatic + fun stopDisc(world: World, pos: BlockPos, stack: ItemStack) { + findHandler(stack)?.stopDisc(world, pos) ?: stopDisc(world, pos) + } + + @JvmStatic + fun getMusicLengthInTicks(stack: ItemStack, world: World): Long? = + findHandler(stack)?.getMusicLengthInTicks(stack, world) +} + +object VanillaDiscHandler : IDiscHandler { + private const val DEFAULT_DISC_LENGTH = 3600L + + private val vanillaDiscLengths = mapOf( + Items.RECORD_13 to 1780L, + Items.RECORD_CAT to 3700L, + Items.RECORD_BLOCKS to 6900L, + Items.RECORD_CHIRP to 3700L, + Items.RECORD_FAR to 3480L, + Items.RECORD_MALL to 3940L, + Items.RECORD_MELLOHI to 1920L, + Items.RECORD_STAL to 3000L, + Items.RECORD_STRAD to 3760L, + Items.RECORD_WARD to 5020L, + Items.RECORD_11 to 1420L, + Items.RECORD_WAIT to 4760L + ) + + override fun supports(stack: ItemStack): Boolean = stack.item is ItemRecord + + override fun playDisc(world: World, pos: BlockPos, stack: ItemStack): Boolean { + if (stack.item !is ItemRecord) { + return false + } + world.playEvent(null, DiscHandlerRegistry.RECORD_PLAY_EVENT, pos, Item.getIdFromItem(stack.item)) + return true + } + + override fun getMusicLengthInTicks(stack: ItemStack, world: World): Long? = + if (supports(stack)) vanillaDiscLengths[stack.item] ?: DEFAULT_DISC_LENGTH else null +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt index fa653a8..1e62893 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/FilterUpgradeWrapper.kt @@ -42,6 +42,7 @@ class FilterUpgradeWrapper : override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - filterWay = IFilterUpgrade.FilterWayType.entries[nbt.getByte(IFilterUpgrade.FILTER_WAY_TAG).toInt()] + if (nbt.hasKey(IFilterUpgrade.FILTER_WAY_TAG)) + filterWay = IFilterUpgrade.FilterWayType.entries.getOrElse(nbt.getByte(IFilterUpgrade.FILTER_WAY_TAG).toInt()) { filterWay } } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt index fbc30da..c809bc5 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IAdvancedFilterable.kt @@ -27,7 +27,7 @@ interface IAdvancedFilterable : IBasicFilterable { } private fun matchItem(stack: ItemStack): Boolean { - val filterResult = BooleanArray(16) + val filterResult = BooleanArray(filterItems.slots) for ((i, filterStack) in filterItems.inventory.withIndex()) { if (filterStack.item != stack.item) @@ -43,10 +43,16 @@ interface IAdvancedFilterable : IBasicFilterable { } private fun matchMod(stack: ItemStack): Boolean { - val filterResult = BooleanArray(16) + val filterResult = BooleanArray(filterItems.slots) for ((i, filterStack) in filterItems.inventory.withIndex()) { - filterResult[i] = stack.item.registryName?.namespace == filterStack.item.registryName?.namespace + if (filterStack.isEmpty) + continue + + val modMatches = stack.item.registryName?.namespace == filterStack.item.registryName?.namespace + val damageMatches = ignoreDurability || stack.itemDamage == filterStack.itemDamage + val nbtMatches = ignoreNBT || stack.tagCompound == filterStack.tagCompound + filterResult[i] = modMatches && damageMatches && nbtMatches } return when (filterType) { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IContentsFilterable.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IContentsFilterable.kt new file mode 100644 index 0000000..9bf993f --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IContentsFilterable.kt @@ -0,0 +1,18 @@ +package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade + +interface IContentsFilterable : IBasicFilterable { + companion object { + const val FILTER_BY_STORAGE_TAG = "FilterByStorage" + } + + var contentsFilterType: ContentsFilterType + + enum class ContentsFilterType { + ALLOW, + BLOCK, + STORAGE; + + fun next(): ContentsFilterType = + entries[(ordinal + 1) % entries.size] + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt index e309294..f558f81 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IMagnetUpgrade.kt @@ -1,6 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.ISidelessCapabilityProvider import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing @@ -10,8 +11,9 @@ import net.minecraft.nbt.NBTTagCompound sealed interface IMagnetUpgrade : ISidelessCapabilityProvider, INBTSerializable { val range: Double + var pickupItems: Boolean - fun canPickup(stack: ItemStack): Boolean + fun canPickup(stack: ItemStack, backpackWrapper: BackpackWrapper): Boolean override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.IMAGNET_UPGRADE_CAPABILITY diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt index 20c239d..0a2448e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/JukeboxUpgradeWrapper.kt @@ -6,9 +6,6 @@ import com.cleanroommc.retrosophisticatedbackpacks.inventory.ExposedItemStackHan import com.cleanroommc.retrosophisticatedbackpacks.item.JukeboxUpgradeItem import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.entity.Entity -import net.minecraft.init.Items -import net.minecraft.item.Item -import net.minecraft.item.ItemRecord import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumFacing @@ -28,23 +25,7 @@ open class JukeboxUpgradeWrapper(private val slots: Int = 1) : UpgradeWrapper= 0) { @@ -137,13 +122,26 @@ open class JukeboxUpgradeWrapper(private val slots: Int = 1) : UpgradeWrapper posPlaying?.let { pos -> stop(world, pos) } - } ?: setPlaying(false) + } ?: run { + setPlaying(false) + playlist.clear() + history.clear() + } } override fun onBeforeRemoved() { @@ -177,19 +175,26 @@ open class JukeboxUpgradeWrapper(private val slots: Int = 1) : UpgradeWrapper(filterSlots, slotsInRow), IMagnetUpgrade { + BasicUpgradeWrapper(filterSlots, slotsInRow), IMagnetUpgrade, IContentsFilterable { + companion object { + private const val PICKUP_ITEMS_TAG = "PickupItems" + } + override val settingsLangKey = "gui.magnet_settings".asTranslationKey() + override var pickupItems = true + private var filterByStorage = false + override var contentsFilterType: IContentsFilterable.ContentsFilterType + get() = when { + filterByStorage -> IContentsFilterable.ContentsFilterType.STORAGE + filterType == IBasicFilterable.FilterType.WHITELIST -> IContentsFilterable.ContentsFilterType.ALLOW + else -> IContentsFilterable.ContentsFilterType.BLOCK + } + set(value) { + filterByStorage = value == IContentsFilterable.ContentsFilterType.STORAGE + when (value) { + IContentsFilterable.ContentsFilterType.ALLOW -> filterType = IBasicFilterable.FilterType.WHITELIST + IContentsFilterable.ContentsFilterType.BLOCK -> filterType = IBasicFilterable.FilterType.BLACKLIST + IContentsFilterable.ContentsFilterType.STORAGE -> {} + } + } init { filterType = IBasicFilterable.FilterType.BLACKLIST } - override fun canPickup(stack: ItemStack): Boolean = - enabled && matchesAllowEmpty(stack) + override fun canPickup(stack: ItemStack, backpackWrapper: BackpackWrapper): Boolean = + enabled && pickupItems && when (contentsFilterType) { + IContentsFilterable.ContentsFilterType.STORAGE -> + backpackWrapper.matchesStorageContents(stack) { candidate, stored -> + ItemStack.areItemsEqualIgnoreDurability(candidate, stored) + } + else -> matchesAllowEmpty(stack) + } + + fun togglePickupItems() { + pickupItems = !pickupItems + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setBoolean(PICKUP_ITEMS_TAG, pickupItems) + nbt.setBoolean(IContentsFilterable.FILTER_BY_STORAGE_TAG, filterByStorage) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + pickupItems = !nbt.hasKey(PICKUP_ITEMS_TAG) || nbt.getBoolean(PICKUP_ITEMS_TAG) + if (nbt.hasKey(IContentsFilterable.FILTER_BY_STORAGE_TAG)) + filterByStorage = nbt.getBoolean(IContentsFilterable.FILTER_BY_STORAGE_TAG) + } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.MAGNET_UPGRADE_CAPABILITY || @@ -32,16 +78,78 @@ open class MagnetUpgradeWrapper( class AdvancedMagnetUpgradeWrapper : AdvancedUpgradeWrapper(Config.advancedMagnetUpgrade.filterSlots, Config.advancedMagnetUpgrade.slotsInRow), - IMagnetUpgrade { + IMagnetUpgrade, IContentsFilterable { + companion object { + private const val PICKUP_ITEMS_TAG = "PickupItems" + } + override val settingsLangKey = "gui.advanced_magnet_settings".asTranslationKey() override val range = Config.advancedMagnetUpgrade.magnetRange.toDouble() + override var pickupItems = true + private var filterByStorage = false + override var contentsFilterType: IContentsFilterable.ContentsFilterType + get() = when { + filterByStorage -> IContentsFilterable.ContentsFilterType.STORAGE + filterType == IBasicFilterable.FilterType.WHITELIST -> IContentsFilterable.ContentsFilterType.ALLOW + else -> IContentsFilterable.ContentsFilterType.BLOCK + } + set(value) { + val normalized = if (value == IContentsFilterable.ContentsFilterType.STORAGE && + matchType == IAdvancedFilterable.MatchType.ORE_DICT + ) IContentsFilterable.ContentsFilterType.ALLOW else value + filterByStorage = normalized == IContentsFilterable.ContentsFilterType.STORAGE + when (normalized) { + IContentsFilterable.ContentsFilterType.ALLOW -> filterType = IBasicFilterable.FilterType.WHITELIST + IContentsFilterable.ContentsFilterType.BLOCK -> filterType = IBasicFilterable.FilterType.BLACKLIST + IContentsFilterable.ContentsFilterType.STORAGE -> {} + } + } init { filterType = IBasicFilterable.FilterType.BLACKLIST } - override fun canPickup(stack: ItemStack): Boolean = - enabled && matchesAllowEmpty(stack) + override fun canPickup(stack: ItemStack, backpackWrapper: BackpackWrapper): Boolean = + enabled && pickupItems && when (contentsFilterType) { + IContentsFilterable.ContentsFilterType.STORAGE -> + backpackWrapper.matchesStorageContents(stack, ::matchesStorageStack) + else -> matchesAllowEmpty(stack) + } + + private fun matchesStorageStack(candidate: ItemStack, stored: ItemStack): Boolean = + when (matchType) { + IAdvancedFilterable.MatchType.ITEM -> { + val itemMatches = if (ignoreDurability) ItemStack.areItemsEqualIgnoreDurability(candidate, stored) + else candidate.isItemEqual(stored) + itemMatches && (ignoreNBT || candidate.tagCompound == stored.tagCompound) + } + IAdvancedFilterable.MatchType.MOD -> + candidate.item.registryName?.namespace == stored.item.registryName?.namespace && + (ignoreDurability || candidate.itemDamage == stored.itemDamage) && + (ignoreNBT || candidate.tagCompound == stored.tagCompound) + IAdvancedFilterable.MatchType.ORE_DICT -> false + } + + fun togglePickupItems() { + pickupItems = !pickupItems + } + + override fun serializeNBT(): NBTTagCompound { + val nbt = super.serializeNBT() + nbt.setBoolean(PICKUP_ITEMS_TAG, pickupItems) + nbt.setBoolean(IContentsFilterable.FILTER_BY_STORAGE_TAG, filterByStorage) + return nbt + } + + override fun deserializeNBT(nbt: NBTTagCompound) { + super.deserializeNBT(nbt) + pickupItems = !nbt.hasKey(PICKUP_ITEMS_TAG) || nbt.getBoolean(PICKUP_ITEMS_TAG) + if (nbt.hasKey(IContentsFilterable.FILTER_BY_STORAGE_TAG)) + filterByStorage = nbt.getBoolean(IContentsFilterable.FILTER_BY_STORAGE_TAG) + if (matchType == IAdvancedFilterable.MatchType.ORE_DICT && filterByStorage) { + contentsFilterType = IContentsFilterable.ContentsFilterType.ALLOW + } + } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.ADVANCED_MAGNET_UPGRADE_CAPABILITY || diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt index b0695ab..5003312 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/PumpUpgradeWrapper.kt @@ -254,8 +254,10 @@ open class PumpUpgradeWrapper( interactWithHand = if (nbt.hasKey(HAND_TAG)) nbt.getBoolean(HAND_TAG) else interactWithHand interactWithWorld = if (nbt.hasKey(WORLD_TAG)) nbt.getBoolean(WORLD_TAG) else interactWithWorld interactWithFluidHandlers = if (nbt.hasKey(FLUID_HANDLERS_TAG)) nbt.getBoolean(FLUID_HANDLERS_TAG) else interactWithFluidHandlers - cooldownUntil = nbt.getLong(COOLDOWN_UNTIL_TAG) - lastHandAction = nbt.getLong(LAST_HAND_ACTION_TAG) + if (nbt.hasKey(COOLDOWN_UNTIL_TAG)) + cooldownUntil = nbt.getLong(COOLDOWN_UNTIL_TAG) + if (nbt.hasKey(LAST_HAND_ACTION_TAG)) + lastHandAction = nbt.getLong(LAST_HAND_ACTION_TAG) for (slot in fluidFilters.indices) { fluidFilters[slot] = if (nbt.hasKey("$FILTER_TAG$slot")) { FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag("$FILTER_TAG$slot")) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt index 0922cb6..25f082a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/RefillUpgradeWrapper.kt @@ -11,6 +11,7 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagList import net.minecraft.util.EnumFacing import net.minecraft.util.EnumHand +import net.minecraft.util.text.TextFormatting import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.Constants import net.minecraftforge.items.ItemHandlerHelper @@ -72,13 +73,14 @@ open class RefillUpgradeWrapper( enum class TargetSlot { ANY { override fun getMissingCount(player: EntityPlayer, filter: ItemStack): Int { - var count = 0 + var count = filter.maxStackSize for (slot in 0 until player.inventory.mainInventory.size) { val stack = player.inventory.getStackInSlot(slot) - if (stack.isEmpty) { - count += filter.maxStackSize - } else if (ItemHandlerHelper.canItemStacksStack(stack, filter)) { - count += stack.maxStackSize - stack.count + if (ItemHandlerHelper.canItemStacksStack(stack, filter)) { + count -= minOf(stack.count, count) + if (count <= 0) { + return 0 + } } } return count @@ -104,8 +106,12 @@ open class RefillUpgradeWrapper( if (!player.inventory.getStackInSlot(slot).isEmpty) { continue } - player.inventory.setInventorySlotContents(slot, remaining.copy()) - return ItemStack.EMPTY + val moved = minOf(remaining.count, remaining.maxStackSize) + player.inventory.setInventorySlotContents(slot, ItemHandlerHelper.copyStackWithSize(remaining, moved)) + remaining.shrink(moved) + if (remaining.isEmpty) { + return ItemStack.EMPTY + } } return remaining } @@ -126,6 +132,32 @@ open class RefillUpgradeWrapper( }, HOTBAR_1, HOTBAR_2, HOTBAR_3, HOTBAR_4, HOTBAR_5, HOTBAR_6, HOTBAR_7, HOTBAR_8, HOTBAR_9; + fun next(): TargetSlot = + entries[(ordinal + 1) % entries.size] + + fun previous(): TargetSlot = + entries[Math.floorMod(ordinal - 1, entries.size)] + + fun acronym(): String = when (this) { + ANY -> "A" + MAIN_HAND -> "M" + OFF_HAND -> "O" + else -> (ordinal - HOTBAR_1.ordinal + 1).toString() + } + + fun descriptionKey(): String = when (this) { + ANY -> "gui.refill_target_any".asTranslationKey() + MAIN_HAND -> "gui.refill_target_main_hand".asTranslationKey() + OFF_HAND -> "gui.refill_target_off_hand".asTranslationKey() + else -> "gui.refill_target_hotbar_${descriptionArg()}".asTranslationKey() + } + + fun descriptionArg(): String = + (ordinal - HOTBAR_1.ordinal + 1).toString() + + fun descriptionColor(): TextFormatting = + TextFormatting.DARK_GREEN + open fun getMissingCount(player: EntityPlayer, filter: ItemStack): Int { val slot = ordinal - HOTBAR_1.ordinal return getSlotMissingCount(player.inventory.getStackInSlot(slot), filter) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt index 613d09e..c79f3f9 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/TankUpgradeWrapper.kt @@ -301,8 +301,12 @@ class TankUpgradeWrapper : UpgradeWrapper(), ITankUpgrade { override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - fluid = if (nbt.hasKey(FLUID_TAG)) FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag(FLUID_TAG)) else null - inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) + if (nbt.hasKey(FLUID_TAG)) + fluid = FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag(FLUID_TAG)) + else if (nbt.hasKey(INVENTORY_TAG)) + fluid = null + if (nbt.hasKey(INVENTORY_TAG)) + inventory.deserializeNBT(nbt.getCompoundTag(INVENTORY_TAG)) } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt index 90a97db..1081ee6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/VoidUpgradeWrapper.kt @@ -52,8 +52,10 @@ class VoidUpgradeWrapper : override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - voidType = VoidType.entries.getOrElse(nbt.getByte(VOID_TYPE_TAG).toInt()) { VoidType.ALWAYS } - shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + if (nbt.hasKey(VOID_TYPE_TAG)) + voidType = VoidType.entries.getOrElse(nbt.getByte(VOID_TYPE_TAG).toInt()) { voidType } + if (nbt.hasKey(SHOULD_WORK_IN_GUI_TAG)) + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } private fun normalizeVoidType(type: VoidType): VoidType = @@ -107,8 +109,10 @@ class AdvancedVoidUpgradeWrapper : override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) - voidType = VoidType.entries.getOrElse(nbt.getByte(VOID_TYPE_TAG).toInt()) { VoidType.ALWAYS } - shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) + if (nbt.hasKey(VOID_TYPE_TAG)) + voidType = VoidType.entries.getOrElse(nbt.getByte(VOID_TYPE_TAG).toInt()) { voidType } + if (nbt.hasKey(SHOULD_WORK_IN_GUI_TAG)) + shouldWorkInGui = nbt.getBoolean(SHOULD_WORK_IN_GUI_TAG) } private fun normalizeVoidType(type: VoidType): VoidType = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt index f3c8ab1..71a18b1 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt @@ -962,7 +962,7 @@ class BackpackPanel( internal fun addUpgradeTabs() { for (i in 0 until backpackWrapper.upgradeSlotsSize()) { - val tab = TabWidget(i + 1).name("upgrade_tab_${i}") + val tab = TabWidget(i + 2).name("upgrade_tab_${i}") tab.isEnabled = false tabWidgets.add(tab) @@ -1180,7 +1180,7 @@ class BackpackPanel( } } // Shifted forward to account for settings tab. - var tabDisplayIndex = 1 + var tabDisplayIndex = 2 // Sync all tabs to their corresponding upgrade for (slotIndex in 0 until backpackWrapper.upgradeSlotsSize()) { @@ -1263,6 +1263,26 @@ class BackpackPanel( tabWidget.expandedWidget = FilterUpgradeWidget(slotIndex, wrapper) } + is AdvancedMagnetUpgradeWrapper -> { + upgradeSlotGroup.updateAdvancedFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = AdvancedMagnetUpgradeWidget(slotIndex, wrapper, stack) + } + + is MagnetUpgradeWrapper -> { + upgradeSlotGroup.updateFilterDelegate(wrapper) + if (updateAndCheckRecreation( + tabWidget.expandedWidget, + wrapper + ) + ) + tabWidget.expandedWidget = MagnetUpgradeWidget(slotIndex, wrapper, stack) + } + is AdvancedVoidUpgradeWrapper -> { upgradeSlotGroup.updateAdvancedFilterDelegate(wrapper) if (updateAndCheckRecreation( @@ -1284,7 +1304,7 @@ class BackpackPanel( } is AdvancedRefillUpgradeWrapper -> { - upgradeSlotGroup.updateFilterDelegate(wrapper) + upgradeSlotGroup.updateLargeBasicFilterDelegate(wrapper) if (updateAndCheckRecreation( tabWidget.expandedWidget, wrapper @@ -1325,12 +1345,12 @@ class BackpackPanel( is AdvancedJukeboxUpgradeWrapper -> { upgradeSlotGroup.updateJukeboxDelegate(wrapper) - if (updateAndCheckRecreation( + if (updateAndCheckRecreation( tabWidget.expandedWidget, wrapper ) ) - tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, wrapper.discInventory.slots) + tabWidget.expandedWidget = AdvancedJukeboxUpgradeWidget(slotIndex, wrapper, stack) } is JukeboxUpgradeWrapper -> { @@ -1340,7 +1360,7 @@ class BackpackPanel( wrapper ) ) - tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack, wrapper.discInventory.slots) + tabWidget.expandedWidget = JukeboxUpgradeWidget(slotIndex, wrapper, stack) } is AdvancedToolSwapperUpgradeWrapper -> { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt index e5915b2..6afcc51 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt @@ -22,6 +22,7 @@ object RSBTextures { val MATCH_DURABILITY_ICON = icon("consider_duration", 0, 16) val IGNORE_DURABILITY_ICON = icon("ignore_duration", 16, 16) + val MATCH_BACKPACK_CONTENTS_ICON = icon("match_backpack_contents", 80, 16) val HALF_HEART_ICON = icon("half_heart", 96, 16) val IGNORE_HALF_HEART_ICON = icon("ignore_half_heart", 112, 16) @@ -44,6 +45,24 @@ object RSBTextures { val ADD_ICON = icon("add", 96, 32) val REMOVE_ICON = icon("remove", 112, 32) val BRAIN_ICON = icon("brain", 128, 32) + val WORK_IN_GUI_ON_ICON = icon("works_in_gui", 0, 48) + val WORK_IN_GUI_OFF_ICON = icon("only_automatic", 16, 48) + val COMPACT_ANYTHING_ICON = icon("compact_anything", 80, 32) + val COMPACT_ONLY_UNCRAFTABLE_ICON = icon("compact_only_uncraftable", 80, 48) + val MAGNET_PICKUP_ITEMS_ICON = icon("pickup_items", 128, 48) + val MAGNET_NO_PICKUP_ITEMS_ICON = icon("do_not_pickup_items", 144, 48) + val VOID_ALWAYS_ICON = icon("void_always", 208, 16) + val VOID_SLOT_OVERFLOW_ICON = icon("void_slot_overflow", 224, 16) + val VOID_STORAGE_OVERFLOW_ICON = icon("void_storage_overflow", 112, 96) + val JUKEBOX_STOP_ICON = icon("jukebox_stop", 0, 64) + val JUKEBOX_PLAY_ICON = icon("jukebox_play", 16, 64) + val JUKEBOX_SHUFFLE_ON_ICON = icon("jukebox_shuffle_on", 96, 80) + val JUKEBOX_SHUFFLE_OFF_ICON = icon("jukebox_shuffle_off", 112, 80) + val JUKEBOX_REPEAT_ALL_ICON = icon("jukebox_repeat_all", 128, 80) + val JUKEBOX_REPEAT_ONE_ICON = icon("jukebox_repeat_one", 144, 80) + val JUKEBOX_NO_REPEAT_ICON = icon("jukebox_no_repeat", 160, 80) + val JUKEBOX_NEXT_ICON = icon("jukebox_next", 32, 96) + val JUKEBOX_PREVIOUS_ICON = icon("jukebox_previous", 48, 96) val ANVIL_NAME_BACKGROUND = controlIcon(28, 99, 100, 16) val ANVIL_NAME_BACKGROUND_DISABLED = controlIcon(28, 115, 100, 16) val ANVIL_PLUS_SIGN = controlIcon(113, 203, 13, 13) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt index 7fdf45c..f91e112 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt @@ -126,12 +126,11 @@ class BackpackMainSettingsWidget( } .tooltipAutoUpdate(true) .tooltipDynamic { + val stateName = if (state()) "on" else "off" it.addLine( - IKey.lang( - "gui.settings_button.$tooltipName.${if (state()) "on" else "off"}".asTranslationKey() - ) + IKey.lang("gui.settings_button.$tooltipName.$stateName".asTranslationKey()) ).addLine( - IKey.lang("gui.settings_button.$tooltipName.detail".asTranslationKey()).style(IKey.GRAY) + IKey.lang("gui.settings_button.$tooltipName.$stateName.tooltip".asTranslationKey()).style(IKey.GRAY) ).pos(RichTooltip.Pos.NEXT_TO_MOUSE) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt index eb68f5a..401cd10 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/CyclicVariantButtonWidget.kt @@ -27,6 +27,11 @@ class CyclicVariantButtonWidget( private set var inEffect: Boolean = true + fun selectIndex(index: Int) { + this.index = index.coerceIn(0, variants.lastIndex) + markTooltipDirty() + } + init { size(buttonWidth, buttonHeight) .onMousePressed { @@ -39,6 +44,9 @@ class CyclicVariantButtonWidget( }.tooltipAutoUpdate(true) .tooltipDynamic { it.addLine(variants[this.index].name) + for (detailLine in variants[this.index].detailLines) { + it.addLine(detailLine) + } if (!inEffect) { it.addLine(IKey.lang("gui.not_in_effect".asTranslationKey()).style(IKey.RED)) @@ -73,5 +81,5 @@ class CyclicVariantButtonWidget( } } - data class Variant(val name: IKey, val drawable: IDrawable) + data class Variant(val name: IKey, val drawable: IDrawable, val detailLines: List = emptyList()) } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt index 4e28eb0..a433460 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt @@ -14,13 +14,19 @@ open class AdvancedExpandedTabWidget( filterSyncKey: String = "adv_common_filter", coveredTabSize: Int = 5, width: Int = 100, + upstreamLayout: Boolean = false, + contentX: Int = 8, + contentY: Int = 28, + contentWidth: Int = 88, + contentPadding: Int = 2, + filterWidth: Int = 88, ) : ExpandedUpgradeTabWidget(slotIndex, wrap, coveredTabSize, delegatedIconStack, titleKey, width) where T : IAdvancedFilterable, T : UpgradeWrapper<*> { protected val startingRow: Row = Row() .height(0) .name("starting_row") as Row - protected val filterWidget: AdvancedFilterWidget = AdvancedFilterWidget(slotIndex, wrap, filterSyncKey) - .width(88) + protected val filterWidget: AdvancedFilterWidget = AdvancedFilterWidget(slotIndex, wrap, filterSyncKey, upstreamLayout) + .width(filterWidth) .coverChildrenHeight() .name("adv_filter_widget") @@ -31,9 +37,9 @@ open class AdvancedExpandedTabWidget( init { val column = Column() - .pos(8, 28) - .width(88) - .childPadding(2) + .pos(contentX, contentY) + .width(contentWidth) + .childPadding(contentPadding) .child(startingRow) .child(filterWidget) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt index f160ff7..aa2b3ff 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt @@ -21,6 +21,7 @@ import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget import com.cleanroommc.retrosophisticatedbackpacks.Tags import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IAdvancedFilterable import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IBasicFilterable +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IContentsFilterable import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.drawable.Outline import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget @@ -34,12 +35,18 @@ class AdvancedFilterWidget( slotIndex: Int, var filterableWrapper: IAdvancedFilterable, syncKey: String = "adv_common_filter", + private val upstreamLayout: Boolean = false, ) : ParentWidget() { companion object { private val FILTER_TYPE_VARIANTS = listOf( CyclicVariantButtonWidget.Variant(IKey.lang("gui.whitelist".asTranslationKey()), RSBTextures.CHECK_ICON), CyclicVariantButtonWidget.Variant(IKey.lang("gui.blacklist".asTranslationKey()), RSBTextures.CROSS_ICON), ) + private val CONTENTS_FILTER_TYPE_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.allow".asTranslationKey()), RSBTextures.CHECK_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.block".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.match_backpack_contents".asTranslationKey()), RSBTextures.MATCH_BACKPACK_CONTENTS_ICON), + ) private val MATCH_TYPE_VARIANTS = listOf( CyclicVariantButtonWidget.Variant( @@ -99,18 +106,34 @@ class AdvancedFilterWidget( syncHandler("upgrades", slotIndex) filterTypeButton = CyclicVariantButtonWidget( - FILTER_TYPE_VARIANTS, - filterableWrapper.filterType.ordinal + if (filterableWrapper is IContentsFilterable) CONTENTS_FILTER_TYPE_VARIANTS else FILTER_TYPE_VARIANTS, + filterButtonIndex(), + iconOffset = if (upstreamLayout) 1 else 2, + buttonWidth = if (upstreamLayout) 18 else 20, + buttonHeight = if (upstreamLayout) 18 else 20, + hasCustomTexture = upstreamLayout ) { index -> - filterableWrapper.filterType = IBasicFilterable.FilterType.entries[index] - updateWrapper() + updateFilterType(index) } matchTypeButton = CyclicVariantButtonWidget( MATCH_TYPE_VARIANTS, - filterableWrapper.matchType.ordinal + filterableWrapper.matchType.ordinal, + iconOffset = if (upstreamLayout) 1 else 2, + buttonWidth = if (upstreamLayout) 18 else 20, + buttonHeight = if (upstreamLayout) 18 else 20, + hasCustomTexture = upstreamLayout ) { filterableWrapper.matchType = IAdvancedFilterable.MatchType.entries[it] + if (filterableWrapper.matchType == IAdvancedFilterable.MatchType.ORE_DICT) { + (filterableWrapper as? IContentsFilterable)?.let { contentsFilterable -> + if (contentsFilterable.contentsFilterType == IContentsFilterable.ContentsFilterType.STORAGE) { + contentsFilterable.contentsFilterType = IContentsFilterable.ContentsFilterType.ALLOW + filterTypeButton.selectIndex(contentsFilterable.contentsFilterType.ordinal) + syncContentsFilterType(contentsFilterable.contentsFilterType) + } + } + } updateWrapper() } @@ -118,7 +141,11 @@ class AdvancedFilterWidget( ignoreDurabilityButton = CyclicVariantButtonWidget( IGNORE_DURABILITY_VARIANTS, - if (filterableWrapper.ignoreDurability) 1 else 0 + if (filterableWrapper.ignoreDurability) 1 else 0, + iconOffset = if (upstreamLayout) 1 else 2, + buttonWidth = if (upstreamLayout) 18 else 20, + buttonHeight = if (upstreamLayout) 18 else 20, + hasCustomTexture = upstreamLayout ) { filterableWrapper.ignoreDurability = it == 1 updateWrapper() @@ -127,30 +154,36 @@ class AdvancedFilterWidget( ignoreNBTButton = CyclicVariantButtonWidget( IGNORE_NBT_VARIANTS, - if (filterableWrapper.ignoreNBT) 1 else 0 + if (filterableWrapper.ignoreNBT) 1 else 0, + iconOffset = if (upstreamLayout) 1 else 2, + buttonWidth = if (upstreamLayout) 18 else 20, + buttonHeight = if (upstreamLayout) 18 else 20, + hasCustomTexture = upstreamLayout ) { filterableWrapper.ignoreNBT = it == 1 updateWrapper() } - ignoreDurabilityButton.inEffect = inEffect + ignoreNBTButton.inEffect = inEffect // Buttons val buttonRow = Row() - .leftRel(0.5f) - .size(88, 20) - .childPadding(2) + .size(if (upstreamLayout) 72 else 88, if (upstreamLayout) 18 else 20) + .childPadding(if (upstreamLayout) 0 else 2) + if (!upstreamLayout) { + buttonRow.leftRel(0.5f) + } val itemBasedConfigButtonRow = Row() - .childPadding(2) - .size(44, 20) - .left(44) + .childPadding(if (upstreamLayout) 0 else 2) + .size(if (upstreamLayout) 36 else 44, if (upstreamLayout) 18 else 20) + .left(if (upstreamLayout) 36 else 44) .child(ignoreDurabilityButton) .child(ignoreNBTButton) .setEnabledIfAndEnabled { filterableWrapper.matchType == IAdvancedFilterable.MatchType.ITEM } .name("item_based_button_list") val addOreDictEntryButton = ButtonWidget() - .size(20, 20) + .size(if (upstreamLayout) 18 else 20, if (upstreamLayout) 18 else 20) .overlay(RSBTextures.ADD_ICON) .onMousePressed { val oreName = oreDictTextField.text @@ -173,7 +206,7 @@ class AdvancedFilterWidget( .name("add_ore_dict_button") val removeOreDictEntryButton = ButtonWidget() - .size(20, 20) + .size(if (upstreamLayout) 18 else 20, if (upstreamLayout) 18 else 20) .overlay(RSBTextures.REMOVE_ICON) .onMousePressed { val focusedOreDictEntry = focusedOreDictEntry @@ -193,9 +226,9 @@ class AdvancedFilterWidget( } val oreDictBasedConfigButtonRow = Row() - .size(44, 20) - .childPadding(2) - .left(44) + .size(if (upstreamLayout) 36 else 44, if (upstreamLayout) 18 else 20) + .childPadding(if (upstreamLayout) 0 else 2) + .left(if (upstreamLayout) 36 else 44) .child(addOreDictEntryButton) .child(removeOreDictEntryButton) .setEnabledIfAndEnabled { filterableWrapper.matchType == IAdvancedFilterable.MatchType.ORE_DICT } @@ -210,8 +243,14 @@ class AdvancedFilterWidget( // Item-based configuration widgets val slotGroup = SlotGroupWidget().name("${syncKey}s") - slotGroup.coverChildren().leftRel(0.5f) + slotGroup.coverChildren() + if (!upstreamLayout) { + slotGroup.leftRel(0.5f) + } slotGroup.disableSortButtons() + slotGroup.setEnabledIfAndEnabled { + (filterableWrapper as? IContentsFilterable)?.contentsFilterType != IContentsFilterable.ContentsFilterType.STORAGE + } filterSlots = mutableListOf() val filterSlotCount = filterableWrapper.filterItems.slots @@ -225,12 +264,14 @@ class AdvancedFilterWidget( } itemBasedConfigurationGroup = Column() - .size(88, 85) - .leftRel(0.5f) - .top(24) + .size(if (upstreamLayout) 72 else 88, 85) + .top(if (upstreamLayout) 21 else 24) .child(slotGroup) .setEnabledIfAndEnabled { filterableWrapper.matchType != IAdvancedFilterable.MatchType.ORE_DICT } .name("item_based_config_group") as Column + if (!upstreamLayout) { + itemBasedConfigurationGroup.leftRel(0.5f) + } // Ore-dict-based configuration widgets oreDictTextField = TextFieldWidget() @@ -270,18 +311,48 @@ class AdvancedFilterWidget( oreDictBasedConfigurationGroup = Column() .size(88, 85) - .leftRel(0.5f) - .top(24) + .top(if (upstreamLayout) 21 else 24) .child(oreDictList) .child(oreDictTextField) .setEnabledIfAndEnabled { filterableWrapper.matchType == IAdvancedFilterable.MatchType.ORE_DICT } .name("ore_dict_based_config_group") as Column + if (!upstreamLayout) { + oreDictBasedConfigurationGroup.leftRel(0.5f) + } child(buttonRow) .child(itemBasedConfigurationGroup) .child(oreDictBasedConfigurationGroup) } + private fun filterButtonIndex(): Int = + (filterableWrapper as? IContentsFilterable)?.contentsFilterType?.ordinal ?: filterableWrapper.filterType.ordinal + + private fun updateFilterType(index: Int) { + val contentsFilterable = filterableWrapper as? IContentsFilterable + if (contentsFilterable != null) { + var filterType = IContentsFilterable.ContentsFilterType.entries[index] + if (filterableWrapper.matchType == IAdvancedFilterable.MatchType.ORE_DICT && + filterType == IContentsFilterable.ContentsFilterType.STORAGE + ) { + filterType = filterType.next() + filterTypeButton.selectIndex(filterType.ordinal) + } + contentsFilterable.contentsFilterType = filterType + syncContentsFilterType(filterType) + return + } + + filterableWrapper.filterType = IBasicFilterable.FilterType.entries[index] + updateWrapper() + } + + private fun syncContentsFilterType(filterType: IContentsFilterable.ContentsFilterType) { + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_CONTENTS_FILTERABLE) { + it.writeEnumValue(filterType) + } + } + private fun updateWrapper() { slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_ADVANCED_FILTERABLE) { it.writeEnumValue(filterableWrapper.filterType) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt index f427393..46f1b88 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt @@ -2,8 +2,10 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade import com.cleanroommc.modularui.widgets.layout.Column import com.cleanroommc.modularui.widgets.layout.Row +import com.cleanroommc.modularui.widgets.slot.PhantomItemSlot import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IBasicFilterable import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.UpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import net.minecraft.item.ItemStack open class BasicExpandedTabWidget( @@ -14,13 +16,21 @@ open class BasicExpandedTabWidget( filterSyncKey: String = "common_filter", coveredTabSize: Int = 4, width: Int = 75, + upstreamLayout: Boolean = false, + contentX: Int = 8, + contentY: Int = 28, + contentWidth: Int = 64, + contentPadding: Int = 2, + filterWidth: Int = 64, + showFilterButton: Boolean = true, + slotFactory: (Int, () -> UpgradeSlotSH?) -> PhantomItemSlot = { _, _ -> PhantomItemSlot() }, ) : ExpandedUpgradeTabWidget(slotIndex, wrap, coveredTabSize, delegatedIconStack, titleKey, width) where T : IBasicFilterable, T : UpgradeWrapper<*> { protected val startingRow: Row = Row() .height(0) .name("starting_row") as Row - protected val filterWidget: BasicFilterWidget = BasicFilterWidget(wrap, slotIndex, filterSyncKey) - .width(64) + protected val filterWidget: BasicFilterWidget = BasicFilterWidget(wrap, slotIndex, filterSyncKey, upstreamLayout, showFilterButton, slotFactory) + .width(filterWidth) .coverChildrenHeight() .name("filter_widget") @@ -31,12 +41,12 @@ open class BasicExpandedTabWidget( init { val column = Column() - .pos(8, 28) - .width(64) - .childPadding(2) + .pos(contentX, contentY) + .width(contentWidth) + .childPadding(contentPadding) .child(startingRow) .child(filterWidget) child(column) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt index 13f473b..456a866 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt @@ -6,15 +6,20 @@ import com.cleanroommc.modularui.widget.ParentWidget import com.cleanroommc.modularui.widgets.SlotGroupWidget import com.cleanroommc.modularui.widgets.slot.PhantomItemSlot import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IBasicFilterable +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IContentsFilterable import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.setEnabledIfAndEnabled class BasicFilterWidget( var filterableWrapper: IBasicFilterable, slotIndex: Int, - syncKey: String = "common_filter" + syncKey: String = "common_filter", + private val upstreamLayout: Boolean = false, + private val showFilterButton: Boolean = true, + private val slotFactory: (Int, () -> UpgradeSlotSH?) -> PhantomItemSlot = { _, _ -> PhantomItemSlot() } ) : ParentWidget() { companion object { @@ -22,6 +27,11 @@ class BasicFilterWidget( CyclicVariantButtonWidget.Variant(IKey.lang("gui.whitelist".asTranslationKey()), RSBTextures.CHECK_ICON), CyclicVariantButtonWidget.Variant(IKey.lang("gui.blacklist".asTranslationKey()), RSBTextures.CROSS_ICON), ) + private val CONTENTS_FILTER_TYPE_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.allow".asTranslationKey()), RSBTextures.CHECK_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.block".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.match_backpack_contents".asTranslationKey()), RSBTextures.MATCH_BACKPACK_CONTENTS_ICON), + ) } private val filterTypeButton: CyclicVariantButtonWidget @@ -33,33 +43,64 @@ class BasicFilterWidget( syncHandler("upgrades", slotIndex) filterTypeButton = CyclicVariantButtonWidget( - FILTER_TYPE_VARIANTS, - filterableWrapper.filterType.ordinal + if (filterableWrapper is IContentsFilterable) CONTENTS_FILTER_TYPE_VARIANTS else FILTER_TYPE_VARIANTS, + filterButtonIndex(), + iconOffset = if (upstreamLayout) 1 else 2, + buttonWidth = if (upstreamLayout) 18 else 20, + buttonHeight = if (upstreamLayout) 18 else 20, + hasCustomTexture = upstreamLayout ) { index -> - filterableWrapper.filterType = IBasicFilterable.FilterType.entries[index] - slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_BASIC_FILTERABLE) { - it.writeEnumValue(filterableWrapper.filterType) - } + updateFilterType(index) } - .size(20, 20) + .size(if (upstreamLayout) 18 else 20, if (upstreamLayout) 18 else 20) val slotGroup = SlotGroupWidget().name("${syncKey}s") - slotGroup.coverChildren().top(26) + slotGroup.coverChildren().top(if (showFilterButton) { + if (upstreamLayout) 21 else 26 + } else { + 0 + }) slotGroup.disableSortButtons() + slotGroup.setEnabledIfAndEnabled { + (filterableWrapper as? IContentsFilterable)?.contentsFilterType != IContentsFilterable.ContentsFilterType.STORAGE + } filterSlots = mutableListOf() val filterSlotCount = filterableWrapper.filterItems.slots val slotsInRow = if (filterSlotCount > 0) filterableWrapper.slotsInRow.coerceIn(1, filterSlotCount) else 1 for (i in 0 until filterSlotCount) { val slot = - PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot + slotFactory(i) { slotSyncHandler }.syncHandler("${syncKey}_$slotIndex", i) + .pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot filterSlots.add(slot) slotGroup.child(slot) } - child(filterTypeButton) - .child(slotGroup) + if (showFilterButton) { + child(filterTypeButton) + } + child(slotGroup) + } + + private fun filterButtonIndex(): Int = + (filterableWrapper as? IContentsFilterable)?.contentsFilterType?.ordinal ?: filterableWrapper.filterType.ordinal + + private fun updateFilterType(index: Int) { + val contentsFilterable = filterableWrapper as? IContentsFilterable + if (contentsFilterable != null) { + val filterType = IContentsFilterable.ContentsFilterType.entries[index] + contentsFilterable.contentsFilterType = filterType + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_CONTENTS_FILTERABLE) { + it.writeEnumValue(filterType) + } + return + } + + filterableWrapper.filterType = IBasicFilterable.FilterType.entries[index] + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_BASIC_FILTERABLE) { + it.writeEnumValue(filterableWrapper.filterType) + } } override fun isValidSyncOrValue(syncHandler: ISyncOrValue): Boolean { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt index 24503d1..2a798bd 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt @@ -10,7 +10,18 @@ import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack class CompactingUpgradeWidget(slotIndex: Int, wrapper: CompactingUpgradeWrapper, stack: ItemStack) : - BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + BasicExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18 + ) { init { startingRow .height(20) @@ -22,14 +33,25 @@ class CompactingUpgradeWidget(slotIndex: Int, wrapper: CompactingUpgradeWrapper, } private fun createCompactModeButton(compactNonUncraftable: Boolean): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { + upstreamButton(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { wrapper.compactNonUncraftable = !wrapper.compactNonUncraftable slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_NON_UNCRAFTABLE) {} } } class AdvancedCompactingUpgradeWidget(slotIndex: Int, wrapper: AdvancedCompactingUpgradeWrapper, stack: ItemStack) : - AdvancedExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + AdvancedExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18 + ) { init { startingRow .height(20) @@ -41,25 +63,19 @@ class AdvancedCompactingUpgradeWidget(slotIndex: Int, wrapper: AdvancedCompactin } private fun createCompactModeButton(compactNonUncraftable: Boolean): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { + upstreamButton(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { wrapper.compactNonUncraftable = !wrapper.compactNonUncraftable slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_NON_UNCRAFTABLE) {} } } -private val COMPACT_MODE_VARIANTS = - listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.compact_uncraftable_only".asTranslationKey()), RSBTextures.CHECK_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.compact_any_recipe".asTranslationKey()), RSBTextures.CROSS_ICON), - ) - -private fun createWorkInGuiButton(shouldWorkInGui: Boolean, toggle: () -> Unit): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(WORK_IN_GUI_VARIANTS, if (shouldWorkInGui) 1 else 0) { - toggle() - } - -private val WORK_IN_GUI_VARIANTS = - listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), - ) +private val COMPACT_MODE_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant( + IKey.lang("gui.compact_only_uncraftable".asTranslationKey()), + RSBTextures.COMPACT_ONLY_UNCRAFTABLE_ICON + ), + CyclicVariantButtonWidget.Variant( + IKey.lang("gui.compact_anything".asTranslationKey()), + RSBTextures.COMPACT_ANYTHING_ICON + ), +) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt index 80bcbbd..b52bd34 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/JukeboxUpgradeWidget.kt @@ -1,97 +1,189 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade +import com.cleanroommc.modularui.api.drawable.IDrawable import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.modularui.api.widget.Interactable import com.cleanroommc.modularui.screen.RichTooltip -import com.cleanroommc.modularui.widgets.ButtonWidget +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry import com.cleanroommc.modularui.widgets.SlotGroupWidget -import com.cleanroommc.modularui.widgets.slot.ItemSlot +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedJukeboxUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.DiscHandlerRegistry import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RepeatMode import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.DynamicIconButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.slot.NoBackgroundItemSlot import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.getThemeOrDefault +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.client.renderer.GlStateManager import net.minecraft.item.ItemStack class JukeboxUpgradeWidget( slotIndex: Int, wrapper: JukeboxUpgradeWrapper, - stack: ItemStack, - private val slots: Int, - private val slotsInRow: Int = if (slots > 1) Config.advancedJukeboxUpgrade.slotsInRow.coerceIn(1, slots) else 1 -) : ExpandedUpgradeTabWidget( + stack: ItemStack +) : BaseJukeboxUpgradeWidget(slotIndex, wrapper, stack, 1, 4, 3) { + init { + size(TAB_WIDTH, 70) + addDiscSlots(slotIndex) + val bottomSlotY = getBottomSlotY() + child(commandButton(UpgradeSlotSH.UPDATE_JUKEBOX_STOP, "gui.jukebox_stop", RSBTextures.JUKEBOX_STOP_ICON).pos(3, bottomSlotY + BUTTON_PADDING)) + child(commandButton(UpgradeSlotSH.UPDATE_JUKEBOX_PLAY, "gui.jukebox_play", RSBTextures.JUKEBOX_PLAY_ICON).pos(21, bottomSlotY + BUTTON_PADDING)) + } +} + +class AdvancedJukeboxUpgradeWidget( + slotIndex: Int, + wrapper: AdvancedJukeboxUpgradeWrapper, + stack: ItemStack +) : BaseJukeboxUpgradeWidget( slotIndex, wrapper, - if (slots > 4) 5 else 4, stack, - wrapper.settingsLangKey, - width = if (slots > 4) 112 else 80 + wrapper.discInventory.slots, + Config.advancedJukeboxUpgrade.slotsInRow.coerceIn(1, wrapper.discInventory.slots), + 5 ) { - companion object { - private const val SLOT_SIZE = 18 + init { + size(TAB_WIDTH, 124) + addDiscSlots(slotIndex) + val bottomSlotY = getBottomSlotY() + child(commandButton(UpgradeSlotSH.UPDATE_JUKEBOX_PREVIOUS, "gui.jukebox_previous", RSBTextures.JUKEBOX_PREVIOUS_ICON).pos(3, bottomSlotY + BUTTON_PADDING)) + child(commandButton(UpgradeSlotSH.UPDATE_JUKEBOX_STOP, "gui.jukebox_stop", RSBTextures.JUKEBOX_STOP_ICON).pos(21, bottomSlotY + BUTTON_PADDING)) + child(commandButton(UpgradeSlotSH.UPDATE_JUKEBOX_PLAY, "gui.jukebox_play", RSBTextures.JUKEBOX_PLAY_ICON).pos(39, bottomSlotY + BUTTON_PADDING)) + child(commandButton(UpgradeSlotSH.UPDATE_JUKEBOX_NEXT, "gui.jukebox_next", RSBTextures.JUKEBOX_NEXT_ICON).pos(57, bottomSlotY + BUTTON_PADDING)) + child(shuffleButton().pos(12, bottomSlotY + BUTTON_PADDING + 20)) + child(repeatButton().pos(48, bottomSlotY + BUTTON_PADDING + 20)) } - init { - size(if (slots > 4) 112 else 80, if (slots > 4) 130 else 94) + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawOverlay(context, widgetTheme) + val activeSlot = wrapper.getDiscSlotActive() + if (context == null || widgetTheme == null || activeSlot !in 0 until slotCount) { + return + } + val remainingProgress = getPlaybackRemainingProgress() + if (remainingProgress <= 0f) { + return + } + val slotX = 4 + activeSlot % slotsInRow * SLOT_SIZE + val slotY = TOP_Y + 1 + activeSlot / slotsInRow * SLOT_SIZE + val progressOver = 16 - (16 * remainingProgress).toInt() + GlStateManager.disableDepth() + Gui.drawRect(slotX + progressOver, slotY, slotX + 16, slotY + 16, PLAYBACK_OVERLAY_COLOR) + GlStateManager.enableDepth() + } - child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_PLAY, "gui.jukebox_play".asTranslationKey(), RSBTextures.CHECK_ICON).pos(8, 28)) - child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_STOP, "gui.jukebox_stop".asTranslationKey(), RSBTextures.CROSS_ICON).pos(30, 28)) - child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_PREVIOUS, "gui.jukebox_previous".asTranslationKey(), RSBTextures.LEFT_ARROW_ICON).pos(52, 28)) - child(createCommandButton(UpgradeSlotSH.UPDATE_JUKEBOX_NEXT, "gui.jukebox_next".asTranslationKey(), RSBTextures.SOLID_UP_ARROW_ICON).pos(74, 28)) - child(createShuffleButton().pos(8, 50)) - child(createRepeatButton().pos(30, 50)) + private fun getPlaybackRemainingProgress(): Float { + val world = Minecraft.getMinecraft().world ?: return 0f + val length = DiscHandlerRegistry.getMusicLengthInTicks(wrapper.getDisc(), world) ?: return 0f + if (length <= 0L) { + return 0f + } + return ((wrapper.getDiscFinishTime() - world.totalWorldTime).toFloat() / length).coerceIn(0f, 1f) + } +} +abstract class BaseJukeboxUpgradeWidget( + slotIndex: Int, + wrapper: U, + stack: ItemStack, + protected val slotCount: Int, + protected val slotsInRow: Int, + coveredTabSize: Int +) : ExpandedUpgradeTabWidget(slotIndex, wrapper, coveredTabSize, stack, wrapper.settingsLangKey, width = TAB_WIDTH) { + protected fun addDiscSlots(slotIndex: Int) { val discs = SlotGroupWidget().name("jukebox_discs_$slotIndex").disableSortButtons() - discs.flex().coverChildren().leftRel(0.5F).top(if (slots > 4) 74 else 72) - repeat(slots) { - discs.child(ItemSlot().syncHandler("jukebox_discs_$slotIndex", it).pos(it % slotsInRow * SLOT_SIZE, it / slotsInRow * SLOT_SIZE)) + discs.size(slotsInRow * SLOT_SIZE, getSlotRows() * SLOT_SIZE).pos(3, TOP_Y) + repeat(slotCount) { + discs.child(NoBackgroundItemSlot().syncHandler("jukebox_discs_$slotIndex", it).pos(it % slotsInRow * SLOT_SIZE, it / slotsInRow * SLOT_SIZE)) } child(discs) } - override fun onWrapperChange(after: JukeboxUpgradeWrapper) { - super.onWrapperChange(after) - } - - private fun createCommandButton(syncId: Int, langKey: String, icon: com.cleanroommc.modularui.api.drawable.IDrawable): ButtonWidget<*> = - ButtonWidget() - .size(20) - .overlay(icon) + protected fun commandButton(syncId: Int, langKey: String, icon: IDrawable): DynamicIconButtonWidget = + DynamicIconButtonWidget({ icon }) + .size(BUTTON_SIZE) .onMousePressed { if (it != 0) { false } else { slotSyncHandler?.syncToServer(syncId) {} + Interactable.playButtonClickSound() true } } .tooltipStatic { - it.addLine(IKey.lang(langKey)).pos(RichTooltip.Pos.NEXT_TO_MOUSE) + it.addLine(IKey.lang(langKey.asTranslationKey())).pos(RichTooltip.Pos.NEXT_TO_MOUSE) } - private fun createShuffleButton(): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(SHUFFLE_VARIANTS, if (wrapper.shuffleEnabled) 1 else 0) { + protected fun shuffleButton(): CyclicVariantButtonWidget = + CyclicVariantButtonWidget( + SHUFFLE_VARIANTS, + if (wrapper.shuffleEnabled) 1 else 0, + iconOffset = 1, + iconSize = 16, + buttonWidth = BUTTON_SIZE, + buttonHeight = BUTTON_SIZE + ) { wrapper.toggleShuffle() slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_JUKEBOX_SHUFFLE) {} } - private fun createRepeatButton(): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(REPEAT_VARIANTS, wrapper.repeatMode.ordinal) { + protected fun repeatButton(): CyclicVariantButtonWidget = + CyclicVariantButtonWidget( + REPEAT_VARIANTS, + wrapper.repeatMode.ordinal, + iconOffset = 1, + iconSize = 16, + buttonWidth = BUTTON_SIZE, + buttonHeight = BUTTON_SIZE + ) { wrapper.repeatMode = RepeatMode.entries[it] - slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_JUKEBOX_REPEAT_MODE) { - it.writeEnumValue(wrapper.repeatMode) + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_JUKEBOX_REPEAT_MODE) { packet -> + packet.writeEnumValue(wrapper.repeatMode) } } + + override fun drawBackground(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { + super.drawBackground(context, widgetTheme) + repeat(slotCount) { + RSBTextures.SLOT_BACKGROUND.draw( + context, + 3 + it % slotsInRow * SLOT_SIZE, + TOP_Y + it / slotsInRow * SLOT_SIZE, + SLOT_SIZE, + SLOT_SIZE, + widgetTheme.getThemeOrDefault() + ) + } + } + + protected fun getBottomSlotY(): Int = TOP_Y + getSlotRows() * SLOT_SIZE + + private fun getSlotRows(): Int = (slotCount + slotsInRow - 1) / slotsInRow } +private const val TOP_Y = 24 +private const val TAB_WIDTH = 80 +private const val BUTTON_SIZE = 18 +private const val SLOT_SIZE = 18 +private const val BUTTON_PADDING = 3 +private const val PLAYBACK_OVERLAY_COLOR = 0x5500CC00 + private val SHUFFLE_VARIANTS = listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_shuffle_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_shuffle_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_shuffle_disabled".asTranslationKey()), RSBTextures.JUKEBOX_SHUFFLE_OFF_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_shuffle_enabled".asTranslationKey()), RSBTextures.JUKEBOX_SHUFFLE_ON_ICON), ) private val REPEAT_VARIANTS = listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_all".asTranslationKey()), RSBTextures.IN_OUT_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_one".asTranslationKey()), RSBTextures.SMALL_1_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_no".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_all".asTranslationKey()), RSBTextures.JUKEBOX_REPEAT_ALL_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_one".asTranslationKey()), RSBTextures.JUKEBOX_REPEAT_ONE_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.jukebox_repeat_no".asTranslationKey()), RSBTextures.JUKEBOX_NO_REPEAT_ICON), ) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt new file mode 100644 index 0000000..b6ec033 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt @@ -0,0 +1,67 @@ +package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade + +import com.cleanroommc.modularui.api.drawable.IKey +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedMagnetUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.MagnetUpgradeWrapper +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures +import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.item.ItemStack + +class MagnetUpgradeWidget(slotIndex: Int, wrapper: MagnetUpgradeWrapper, stack: ItemStack) : + BasicExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18 + ) { + init { + startingRow + .height(20) + .child(createPickupItemsButton(wrapper.pickupItems)) + } + + private fun createPickupItemsButton(pickupItems: Boolean): CyclicVariantButtonWidget = + upstreamButton(PICKUP_ITEMS_VARIANTS, if (pickupItems) 0 else 1) { + wrapper.pickupItems = !wrapper.pickupItems + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_MAGNET_PICKUP_ITEMS) {} + } +} + +class AdvancedMagnetUpgradeWidget(slotIndex: Int, wrapper: AdvancedMagnetUpgradeWrapper, stack: ItemStack) : + AdvancedExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18 + ) { + init { + startingRow + .height(20) + .child(createPickupItemsButton(wrapper.pickupItems)) + } + + private fun createPickupItemsButton(pickupItems: Boolean): CyclicVariantButtonWidget = + upstreamButton(PICKUP_ITEMS_VARIANTS, if (pickupItems) 0 else 1) { + wrapper.pickupItems = !wrapper.pickupItems + slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_MAGNET_PICKUP_ITEMS) {} + } +} + +private val PICKUP_ITEMS_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.pickup_items".asTranslationKey()), RSBTextures.MAGNET_PICKUP_ITEMS_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.do_not_pickup_items".asTranslationKey()), RSBTextures.MAGNET_NO_PICKUP_ITEMS_ICON), +) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt index 48760f0..7948965 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt @@ -1,67 +1,116 @@ package com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.upgrade -import com.cleanroommc.modularui.api.drawable.IDrawable +import com.cleanroommc.modularui.api.UpOrDown import com.cleanroommc.modularui.api.drawable.IKey -import com.cleanroommc.modularui.drawable.ItemDrawable -import com.cleanroommc.modularui.widgets.layout.Row +import com.cleanroommc.modularui.screen.RichTooltip +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext +import com.cleanroommc.modularui.theme.WidgetThemeEntry +import com.cleanroommc.modularui.widgets.slot.PhantomItemSlot import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedRefillUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.RefillUpgradeWrapper -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures -import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey -import net.minecraft.init.Items +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.resources.I18n import net.minecraft.item.ItemStack +import net.minecraft.util.text.TextFormatting class RefillUpgradeWidget(slotIndex: Int, wrapper: RefillUpgradeWrapper, stack: ItemStack) : - BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + BasicExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + coveredTabSize = refillCoveredTabSize(wrapper), + width = refillTabWidth(wrapper), + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18, + showFilterButton = false + ) { init { startingRow.height(0) } } class AdvancedRefillUpgradeWidget(slotIndex: Int, wrapper: AdvancedRefillUpgradeWrapper, stack: ItemStack) : - BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey, width = 130) { + BasicExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + filterSyncKey = "adv_common_filter", + coveredTabSize = refillCoveredTabSize(wrapper), + width = refillTabWidth(wrapper), + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18, + showFilterButton = false, + slotFactory = { filterSlot, syncHandler -> RefillTargetSlot(wrapper, filterSlot, syncHandler) } + ) { init { - startingRow - .height(42) - .childPadding(1) - .child(targetRow(wrapper, 0, 6)) - .child(targetRow(wrapper, 6, 12)) + startingRow.height(0) } +} + +private fun refillTabWidth(wrapper: RefillUpgradeWrapper): Int = + maxOf(75, 3 + wrapper.slotsInRow * 18 + 6) + +private fun refillCoveredTabSize(wrapper: RefillUpgradeWrapper): Int { + val slotsInRow = wrapper.slotsInRow.coerceAtLeast(1) + val rows = (wrapper.filterItems.slots + slotsInRow - 1) / slotsInRow + return ((24 + rows * 18 + 6 + 29) / 30).coerceAtLeast(3) +} + +private class RefillTargetSlot( + private val wrapper: AdvancedRefillUpgradeWrapper, + private val filterSlot: Int, + private val upgradeSyncHandler: () -> UpgradeSlotSH? +) : PhantomItemSlot() { + override fun onMouseScroll(scrollDirection: UpOrDown, amount: Int): Boolean { + if (slot.stack.isEmpty) { + return super.onMouseScroll(scrollDirection, amount) + } - private fun targetRow(wrapper: AdvancedRefillUpgradeWrapper, start: Int, end: Int): Row { - val row = Row().height(20).childPadding(1) as Row - for (filterSlot in start until end) { - row.child(createTargetButton(wrapper, filterSlot)) + val targetSlot = if (scrollDirection.isUp) wrapper.getTargetSlot(filterSlot).next() + else wrapper.getTargetSlot(filterSlot).previous() + wrapper.setTargetSlot(filterSlot, targetSlot) + upgradeSyncHandler()?.syncToServer(UpgradeSlotSH.UPDATE_REFILL_TARGET_SLOT) { + it.writeInt(filterSlot) + it.writeEnumValue(targetSlot) } - return row + markTooltipDirty() + return true } - private fun createTargetButton(wrapper: AdvancedRefillUpgradeWrapper, filterSlot: Int): CyclicVariantButtonWidget = - CyclicVariantButtonWidget( - RefillUpgradeWrapper.TargetSlot.entries.map { CyclicVariantButtonWidget.Variant(it.langKey(), it.icon()) }, - wrapper.getTargetSlot(filterSlot).ordinal, - iconOffset = 4, - iconSize = 12, - buttonWidth = 18, - buttonHeight = 18 - ) { index -> - wrapper.setTargetSlot(filterSlot, RefillUpgradeWrapper.TargetSlot.entries[index]) - slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_REFILL_TARGET_SLOT) { - it.writeInt(filterSlot) - it.writeEnumValue(RefillUpgradeWrapper.TargetSlot.entries[index]) - } + override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { + super.drawOverlay(context, widgetTheme) + if (!isSynced || slot.stack.isEmpty) { + return } -} -private fun RefillUpgradeWrapper.TargetSlot.langKey(): IKey = - IKey.lang("gui.refill_target_${name.lowercase()}".asTranslationKey()) + GlStateManager.disableLighting() + GlStateManager.disableDepth() + Minecraft.getMinecraft().fontRenderer.drawString(wrapper.getTargetSlot(filterSlot).acronym(), 10, 2, 0x55FF55) + GlStateManager.enableDepth() + } + + override fun buildTooltip(stack: ItemStack, tooltip: RichTooltip) { + super.buildTooltip(stack, tooltip) + if (stack.isEmpty) { + return + } -private fun RefillUpgradeWrapper.TargetSlot.icon(): IDrawable = - when (this) { - RefillUpgradeWrapper.TargetSlot.ANY -> RSBTextures.SMALL_A_ICON - RefillUpgradeWrapper.TargetSlot.MAIN_HAND -> RSBTextures.SMALL_M_ICON - RefillUpgradeWrapper.TargetSlot.OFF_HAND -> RSBTextures.SMALL_O_ICON - else -> ItemDrawable(ItemStack(Items.PAPER, 1, ordinal - RefillUpgradeWrapper.TargetSlot.HOTBAR_1.ordinal + 1)) + val targetSlot = wrapper.getTargetSlot(filterSlot) + val targetDescription = I18n.format(targetSlot.descriptionKey()) + tooltip.addLine(IKey.str(I18n.format("gui.refill_target_tooltip".asTranslationKey(), targetDescription)).style(targetSlot.descriptionColor())) + .addLine(IKey.lang("gui.refill_scroll_tooltip".asTranslationKey()).style(TextFormatting.DARK_GRAY, TextFormatting.ITALIC)) } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt index d17634d..b834185 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt @@ -6,66 +6,122 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidType import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.VoidUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.client.gui.RSBTextures import com.cleanroommc.retrosophisticatedbackpacks.client.gui.widgets.CyclicVariantButtonWidget +import com.cleanroommc.retrosophisticatedbackpacks.config.Config import com.cleanroommc.retrosophisticatedbackpacks.sync.UpgradeSlotSH import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack +import net.minecraft.util.text.TextFormatting class VoidUpgradeWidget(slotIndex: Int, wrapper: VoidUpgradeWrapper, stack: ItemStack) : - BasicExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + BasicExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18 + ) { init { startingRow .height(20) - .child(createVoidTypeButton(wrapper.voidType)) .child(createWorkInGuiButton(wrapper.shouldWorkInGui) { wrapper.shouldWorkInGui = !wrapper.shouldWorkInGui slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_WORK_IN_GUI) {} }) + .child(createVoidTypeButton(wrapper.voidType, Config.voidUpgrade.voidAlwaysEnabled)) } - private fun createVoidTypeButton(current: VoidType): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(VOID_TYPE_VARIANTS, current.ordinal) { index -> - wrapper.voidType = VoidType.entries[index] + private fun createVoidTypeButton(current: VoidType, alwaysEnabled: Boolean): CyclicVariantButtonWidget { + val voidTypes = allowedVoidTypes(alwaysEnabled) + return upstreamButton(voidTypes.map(::voidVariant), voidTypes.indexOf(current).coerceAtLeast(0)) { index -> + wrapper.voidType = voidTypes[index] slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_TYPE) { - it.writeEnumValue(VoidType.entries[index]) + it.writeEnumValue(voidTypes[index]) } } + } } class AdvancedVoidUpgradeWidget(slotIndex: Int, wrapper: AdvancedVoidUpgradeWrapper, stack: ItemStack) : - AdvancedExpandedTabWidget(slotIndex, wrapper, stack, wrapper.settingsLangKey) { + AdvancedExpandedTabWidget( + slotIndex, + wrapper, + stack, + wrapper.settingsLangKey, + upstreamLayout = true, + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18 + ) { init { startingRow .height(20) - .child(createVoidTypeButton(wrapper.voidType)) .child(createWorkInGuiButton(wrapper.shouldWorkInGui) { wrapper.shouldWorkInGui = !wrapper.shouldWorkInGui slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_WORK_IN_GUI) {} }) + .child(createVoidTypeButton(wrapper.voidType, Config.advancedVoidUpgrade.voidAlwaysEnabled)) } - private fun createVoidTypeButton(current: VoidType): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(VOID_TYPE_VARIANTS, current.ordinal) { index -> - wrapper.voidType = VoidType.entries[index] + private fun createVoidTypeButton(current: VoidType, alwaysEnabled: Boolean): CyclicVariantButtonWidget { + val voidTypes = allowedVoidTypes(alwaysEnabled) + return upstreamButton(voidTypes.map(::voidVariant), voidTypes.indexOf(current).coerceAtLeast(0)) { index -> + wrapper.voidType = voidTypes[index] slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_TYPE) { - it.writeEnumValue(VoidType.entries[index]) + it.writeEnumValue(voidTypes[index]) } } + } } -private val VOID_TYPE_VARIANTS = - listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.void_always".asTranslationKey()), RSBTextures.CROSS_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.void_slot_overflow".asTranslationKey()), RSBTextures.IN_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.void_storage_overflow".asTranslationKey()), RSBTextures.IN_OUT_ICON), - ) - -private fun createWorkInGuiButton(shouldWorkInGui: Boolean, toggle: () -> Unit): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(WORK_IN_GUI_VARIANTS, if (shouldWorkInGui) 1 else 0) { +internal fun createWorkInGuiButton(shouldWorkInGui: Boolean, toggle: () -> Unit): CyclicVariantButtonWidget = + upstreamButton(WORK_IN_GUI_VARIANTS, if (shouldWorkInGui) 1 else 0) { toggle() } -private val WORK_IN_GUI_VARIANTS = - listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.work_in_gui_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), +internal fun upstreamButton( + variants: List, + index: Int, + updater: CyclicVariantButtonWidget.(Int) -> Unit +): CyclicVariantButtonWidget = + CyclicVariantButtonWidget( + variants, + index, + iconOffset = 1, + buttonWidth = 18, + buttonHeight = 18, + hasCustomTexture = true, + mousePressedUpdater = updater ) + +private fun allowedVoidTypes(alwaysEnabled: Boolean): List = + if (alwaysEnabled) VoidType.entries else listOf(VoidType.SLOT_OVERFLOW, VoidType.STORAGE_OVERFLOW) + +private fun voidVariant(type: VoidType): CyclicVariantButtonWidget.Variant = + when (type) { + VoidType.ALWAYS -> CyclicVariantButtonWidget.Variant( + IKey.lang("gui.void_always".asTranslationKey()), + RSBTextures.VOID_ALWAYS_ICON + ) + VoidType.SLOT_OVERFLOW -> CyclicVariantButtonWidget.Variant( + IKey.lang("gui.void_slot_overflow".asTranslationKey()), + RSBTextures.VOID_SLOT_OVERFLOW_ICON, + listOf(IKey.lang("gui.void_slot_overflow_detail".asTranslationKey()).style(TextFormatting.GRAY)) + ) + VoidType.STORAGE_OVERFLOW -> CyclicVariantButtonWidget.Variant( + IKey.lang("gui.void_storage_overflow".asTranslationKey()), + RSBTextures.VOID_STORAGE_OVERFLOW_ICON, + listOf(IKey.lang("gui.void_storage_overflow_detail".asTranslationKey()).style(TextFormatting.GRAY)) + ) + } + +private val WORK_IN_GUI_VARIANTS = listOf( + CyclicVariantButtonWidget.Variant(IKey.lang("gui.only_automatic".asTranslationKey()), RSBTextures.WORK_IN_GUI_OFF_ICON), + CyclicVariantButtonWidget.Variant(IKey.lang("gui.works_in_gui".asTranslationKey()), RSBTextures.WORK_IN_GUI_ON_ICON), +) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt index 2ee7a69..7929b2e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/BackpackItem.kt @@ -188,8 +188,7 @@ class BackpackItem( if (entityIn.ticksExisted % 20 == 0) wrapper.feed(entityIn, wrapper) - if (entityIn.ticksExisted % 5 == 0) - wrapper.tickUpgrades(entityIn, worldIn, entityIn.posX, entityIn.posY, entityIn.posZ) + wrapper.tickUpgrades(entityIn, worldIn, entityIn.posX, entityIn.posY, entityIn.posZ) if (!Config.tickDedupeLogicDisabled && !wrapper.isCached) CapabilityHandler.cacheBackpackInventory(wrapper) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CraftingUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CraftingUpgradeItem.kt index 7c5f4d3..31a61a6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CraftingUpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/CraftingUpgradeItem.kt @@ -1,12 +1,8 @@ package com.cleanroommc.retrosophisticatedbackpacks.item import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CraftingUpgradeWrapper -import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey -import net.minecraft.client.util.ITooltipFlag import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound -import net.minecraft.util.text.TextComponentTranslation -import net.minecraft.world.World import net.minecraftforge.common.capabilities.ICapabilityProvider class CraftingUpgradeItem(registryName: String) : UpgradeItem(registryName, true) { @@ -15,8 +11,4 @@ class CraftingUpgradeItem(registryName: String) : UpgradeItem(registryName, true nbt?.let(wrapper::deserializeNBT) return wrapper } - - override fun addInformation(stack: ItemStack, worldIn: World?, tooltip: MutableList, flagIn: ITooltipFlag) { - tooltip.add(TextComponentTranslation("tooltip.crafting_upgrade".asTranslationKey()).formattedText) - } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt index 542ec5a..8f4c53d 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/StackUpgradeItem.kt @@ -1,9 +1,7 @@ package com.cleanroommc.retrosophisticatedbackpacks.item -import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.client.util.ITooltipFlag import net.minecraft.item.ItemStack -import net.minecraft.util.text.TextComponentTranslation import net.minecraft.world.World class StackUpgradeItem(registryName: String, val multiplier: () -> Int) : UpgradeItem(registryName, upgradeGroup = "stack") { @@ -13,6 +11,6 @@ class StackUpgradeItem(registryName: String, val multiplier: () -> Int) : Upgrad tooltip: MutableList, flagIn: ITooltipFlag ) { - tooltip.add(TextComponentTranslation("tooltip.stack_upgrade".asTranslationKey(), multiplier()).formattedText) + addUpgradeTooltip(tooltip, multiplier()) } } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt index 46568c9..320ed79 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/item/UpgradeItem.kt @@ -4,10 +4,11 @@ import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.handler.RegistryHandler import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import net.minecraft.client.resources.I18n import net.minecraft.client.util.ITooltipFlag import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound -import net.minecraft.util.text.TextComponentTranslation +import net.minecraft.util.text.TextFormatting import net.minecraft.world.World abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false, val upgradeGroup: String? = null) : ItemBase() { @@ -21,7 +22,19 @@ abstract class UpgradeItem(registryName: String, val hasTab: Boolean = false, va } override fun addInformation(stack: ItemStack, worldIn: World?, tooltip: MutableList, flagIn: ITooltipFlag) { - tooltip.add(TextComponentTranslation("tooltip.${registryName!!.path}".asTranslationKey()).formattedText) + addUpgradeTooltip(tooltip) + } + + protected fun addUpgradeTooltip(tooltip: MutableList, vararg args: Any) { + val path = registryName!!.path + val key = "item.${registryName!!.namespace}.$path.tooltip" + val legacyKey = "tooltip.$path".asTranslationKey() + val tooltipText = when { + I18n.hasKey(key) -> I18n.format(key, *args) + I18n.hasKey(legacyKey) -> I18n.format(legacyKey, *args) + else -> return + } + tooltipText.replace("\\n", "\n").split('\n').forEach { tooltip.add(TextFormatting.DARK_GRAY.toString() + it) } } override fun getNBTShareTag(stack: ItemStack): NBTTagCompound? { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt index a5ca418..249d3f7 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/sync/UpgradeSlotSH.kt @@ -8,6 +8,7 @@ import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.CraftingUp import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IAdvancedFilterable import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IAnvilUpgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IBasicFilterable +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IContentsFilterable import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IFilterUpgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IPumpUpgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.JukeboxUpgradeWrapper @@ -64,6 +65,8 @@ class UpgradeSlotSH( const val UPDATE_ANVIL_SHIFT_CLICK = 33 const val UPDATE_ANVIL_TAKE_RESULT = 34 const val UPDATE_REOPEN_BACKPACK = 35 + const val UPDATE_MAGNET_PICKUP_ITEMS = 36 + const val UPDATE_CONTENTS_FILTERABLE = 37 } private var lastCapabilityNbt = NBTTagCompound() @@ -122,6 +125,8 @@ class UpgradeSlotSH( UPDATE_ANVIL_SHIFT_CLICK -> updateAnvilShiftClick() UPDATE_ANVIL_TAKE_RESULT -> updateAnvilTakeResult() UPDATE_REOPEN_BACKPACK -> reopenBackpackGui() + UPDATE_MAGNET_PICKUP_ITEMS -> updateMagnetPickupItems() + UPDATE_CONTENTS_FILTERABLE -> updateContentsFilterable(buf) } } @@ -206,6 +211,16 @@ class UpgradeSlotSH( slot.stack.getCapability(Capabilities.ADVANCED_COMPACTING_UPGRADE_CAPABILITY, null)?.toggleWorkInGui() } + private fun updateMagnetPickupItems() { + slot.stack.getCapability(Capabilities.MAGNET_UPGRADE_CAPABILITY, null)?.togglePickupItems() + slot.stack.getCapability(Capabilities.ADVANCED_MAGNET_UPGRADE_CAPABILITY, null)?.togglePickupItems() + } + + private fun updateContentsFilterable(buf: PacketBuffer) { + val filterType = buf.readEnumValue(IContentsFilterable.ContentsFilterType::class.java) + (slot.stack.getCapability(Capabilities.UPGRADE_CAPABILITY, null) as? IContentsFilterable)?.contentsFilterType = filterType + } + private fun updateRefillTargetSlot(buf: PacketBuffer) { val filterSlot = buf.readInt() val targetSlot = buf.readEnumValue(RefillUpgradeWrapper.TargetSlot::class.java) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt index ca0595a..e9a9ee9 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/tileentity/BackpackTileEntity.kt @@ -138,7 +138,7 @@ class BackpackTileEntity(val wrapper: BackpackWrapper = BackpackWrapper()) : else TextComponentTranslation("container.backpack".asTranslationKey()) override fun update() { - if (!world.isRemote && world.totalWorldTime % 5L == 0L) { + if (!world.isRemote) { wrapper.tickUpgrades(null, world, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, pos) syncTankState() syncBatteryState() diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang index 47b6ae3..02763ff 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang @@ -18,7 +18,7 @@ item.retro_sophisticated_backpacks.inception_upgrade.name=Inception Upgrade item.retro_sophisticated_backpacks.pickup_upgrade.name=Pickup Upgrade item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=Advanced Pickup Upgrade item.retro_sophisticated_backpacks.feeding_upgrade.name=Feeding Upgrade -item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=Advanced Feeding Upgrade +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=Advanced Feeding upgrade item.retro_sophisticated_backpacks.deposit_upgrade.name=Deposit Upgrade item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=Advanced Deposit Upgrade item.retro_sophisticated_backpacks.restock_upgrade.name=Restock Upgrade @@ -48,37 +48,21 @@ retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Co retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift -retro_sophisticated_backpacks.tooltip.upgrade_base=It does nothing! Feel free to put it in your upgrade slots! -retro_sophisticated_backpacks.tooltip.stack_upgrade=Multiplies stack size by %d -retro_sophisticated_backpacks.tooltip.exponential_stack_upgrade=Stack multipliers will stack by multiplying instead of adding -retro_sophisticated_backpacks.tooltip.crafting_upgrade=Adds additional crafting grid to side of backpack -retro_sophisticated_backpacks.tooltip.inception_upgrade=Allows backpacks to be stored inside backpack -retro_sophisticated_backpacks.tooltip.pickup_upgrade=Allows backpacks to pickup items -retro_sophisticated_backpacks.tooltip.advanced_pickup_upgrade=Allows backpack to pickup items with more configurations -retro_sophisticated_backpacks.tooltip.feeding_upgrade=Allows backpacks to automatically feed player -retro_sophisticated_backpacks.tooltip.advanced_feeding_upgrade=Allows backpack to automatically feed player with more configurations -retro_sophisticated_backpacks.tooltip.deposit_upgrade=Deposits items from backpack into sneak-right-clicked inventory -retro_sophisticated_backpacks.tooltip.advanced_deposit_upgrade=Deposits items from backpack into sneak-right-clicked inventory with more configurations -retro_sophisticated_backpacks.tooltip.restock_upgrade=Restocks items from sneak-right-clicked inventory to backpack -retro_sophisticated_backpacks.tooltip.advanced_restock_upgrade=Restocks items from sneak-right-clicked inventory to backpack with more configurations -retro_sophisticated_backpacks.tooltip.filter_upgrade=Filters inserted items when placing in world -retro_sophisticated_backpacks.tooltip.advanced_filter_upgrade=Filters inserted items when placing in world with more configurations -retro_sophisticated_backpacks.tooltip.shift_to_reveal= # Gui Elements retro_sophisticated_backpacks.container.backpack=Backpack @@ -103,40 +87,36 @@ retro_sophisticated_backpacks.gui.crafting_settings=Craft retro_sophisticated_backpacks.gui.memory_settings=Memory retro_sophisticated_backpacks.gui.sorting_settings=No Sort retro_sophisticated_backpacks.gui.backpack_settings=Backpack Settings -retro_sophisticated_backpacks.gui.item_display_settings=Item Display Settings +retro_sophisticated_backpacks.gui.item_display_settings=Item Disp. retro_sophisticated_backpacks.gui.backpack_settings.tooltip=Backpack Settings retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Item Display Settings -retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Allows selecting the backpack slot rendered on the backpack\nOpen tab to modify item display -retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Allows selecting the backpack slot rendered on the backpack\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Allows selecting a slot that will be used to show its item on top of storage +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Allows selecting a slot that will be used to show its item on top of storage\nSelect slot = left click/drag\nUnselect slot = right click/drag retro_sophisticated_backpacks.gui.search=Click to search -retro_sophisticated_backpacks.gui.search_detail=Use @modid for mod id and #text for tooltip search +retro_sophisticated_backpacks.gui.search_detail=@ prefix to search by mod name retro_sophisticated_backpacks.gui.settings_button.context_player=Player retro_sophisticated_backpacks.gui.settings_button.context_backpack=Backpack -retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Player settings context -retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=Settings are saved for your player and follow you between backpacks -retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=Backpack settings context -retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=Settings are saved on this backpack and apply to anyone using it -retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift-click into open tab -retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift-click normally -retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.detail=Controls where shift-clicked stacks go while an upgrade tab is open -retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Keep tab open -retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Close tab after action -retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.detail=Controls whether upgrade tabs stay expanded after interacting with slots -retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep search phrase -retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Clear search phrase -retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.detail=Controls whether the search text is kept after closing the backpack -retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=Other players can open -retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=Only owner can open -retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.detail=Controls whether other players may open this backpack -retro_sophisticated_backpacks.gui.settings_button.rotate=Rotate display item -retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Left click rotates clockwise\nRight click rotates counter-clockwise -retro_sophisticated_backpacks.gui.settings_button.item_display_color=Display color -retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=Left click selects next color\nRight click selects previous color -retro_sophisticated_backpacks.gui.settings_button.display_side_front=Display on front -retro_sophisticated_backpacks.gui.settings_button.display_side_left=Display on left -retro_sophisticated_backpacks.gui.settings_button.display_side_right=Display on right +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Player level settings +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=Apply to all backpacks/storages unless overriden +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=This Backpack's settings +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=Inherited from player or overriden for this backpack +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift Click Into Open Tab First +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift Click Into Inventory First +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Keep Tab Open: ON +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Keep Tab Open: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep Search Phrase: ON +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Keep Search Phrase: OFF +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=Another player can open +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=Another player can NOT open +retro_sophisticated_backpacks.gui.settings_button.rotate=Rotate +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Clockwise = Left Click\nCounter-Clockwise = Right Click +retro_sophisticated_backpacks.gui.settings_button.item_display_color=Toggle Color +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=Next = Left Click\nPrevious = Right Click +retro_sophisticated_backpacks.gui.settings_button.display_side_front=Show on Front +retro_sophisticated_backpacks.gui.settings_button.display_side_left=Show on Left side +retro_sophisticated_backpacks.gui.settings_button.display_side_right=Show on Right side retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings @@ -149,11 +129,11 @@ retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows se retro_sophisticated_backpacks.gui.stack_size_extra=Count: %s / %s retro_sophisticated_backpacks.gui.not_in_effect=Not in effect -retro_sophisticated_backpacks.gui.whitelist=Whitelist -retro_sophisticated_backpacks.gui.blacklist=Blacklist +retro_sophisticated_backpacks.gui.whitelist=Allow +retro_sophisticated_backpacks.gui.blacklist=Block -retro_sophisticated_backpacks.gui.match_item=By Item -retro_sophisticated_backpacks.gui.match_mod_id=By Mod ID +retro_sophisticated_backpacks.gui.match_item=Match Item +retro_sophisticated_backpacks.gui.match_mod_id=Match Mod retro_sophisticated_backpacks.gui.match_ore_dict=By Ore Dictionary retro_sophisticated_backpacks.gui.match_durability=Match Durability @@ -177,23 +157,23 @@ retro_sophisticated_backpacks.gui.ignore_health=Do not consider health\nIgnores retro_sophisticated_backpacks.gui.consider_health=Feed player immediately when hurt\nIgnores hunger setting when player is not at max health retro_sophisticated_backpacks.gui.input_output=Input & Output -retro_sophisticated_backpacks.gui.input=Input Only -retro_sophisticated_backpacks.gui.output=Output Only +retro_sophisticated_backpacks.gui.input=Input +retro_sophisticated_backpacks.gui.output=Output -retro_sophisticated_backpacks.gui.sort_inventory=Sort Backpack Inventory -retro_sophisticated_backpacks.gui.sort_by_name=Sort By Name -retro_sophisticated_backpacks.gui.sort_by_mod_id=Sort By Mod ID -retro_sophisticated_backpacks.gui.sort_by_count=Sort By Count -retro_sophisticated_backpacks.gui.sort_by_ore_dict=Sort By Ore Dictionary +retro_sophisticated_backpacks.gui.sort_inventory=Sort Inventory +retro_sophisticated_backpacks.gui.sort_by_name=By Name +retro_sophisticated_backpacks.gui.sort_by_mod_id=By Mod +retro_sophisticated_backpacks.gui.sort_by_count=By Count +retro_sophisticated_backpacks.gui.sort_by_ore_dict=By Tags retro_sophisticated_backpacks.gui.craft_into_backpack=Shift Click Result Into Backpack retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift Click Result Into Player's Inventory -retro_sophisticated_backpacks.gui.transfer_to_player_inv=Transfer All Items to Player Inventory -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Transfer Matched Items to Player Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv=Transfer to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Transfer Matching to Inventory retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift To Transfer All -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Transfer All Items to Backpack Inventory -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transfer Matched Items to Backpack Inventory +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Transfer to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transfer Matching to Storage retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift To Transfer All retro_sophisticated_backpacks.gui.settings=Settings @@ -201,12 +181,12 @@ retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Back To Backpack retro_sophisticated_backpacks.gui.configuration_tab=Configuration Tab retro_sophisticated_backpacks.gui.memorized_slot=Memorized Slot -retro_sophisticated_backpacks.gui.memorize_all=Memorize All Slots -retro_sophisticated_backpacks.gui.unmemorize_all=Forget All Slots +retro_sophisticated_backpacks.gui.memorize_all=Select All Slots +retro_sophisticated_backpacks.gui.unmemorize_all=Unselect All Slots retro_sophisticated_backpacks.gui.no_sorting_slot=No Sorting Slot -retro_sophisticated_backpacks.gui.lock_all_sort=Select All Slots For No Sorting -retro_sophisticated_backpacks.gui.unlock_all_sort=Select All Slots For Sorting +retro_sophisticated_backpacks.gui.lock_all_sort=Select All Slots +retro_sophisticated_backpacks.gui.unlock_all_sort=Unselect All Slots item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade @@ -216,14 +196,6 @@ item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade -retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations -retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations -retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations -retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations retro_sophisticated_backpacks.gui.magnet_settings=Magnet retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet retro_sophisticated_backpacks.gui.void_settings=Void @@ -235,22 +207,31 @@ retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting retro_sophisticated_backpacks.gui.void_always=Void Always retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow -retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes -retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes -retro_sophisticated_backpacks.gui.refill_target_any=Any Slot -retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand -retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI -retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI +retro_sophisticated_backpacks.gui.refill_target_any=Any slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Main hand +retro_sophisticated_backpacks.gui.refill_target_off_hand=Off hand +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar slot 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar slot 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar slot 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar slot 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar slot 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar slot 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar slot 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar slot 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar slot 9 +retro_sophisticated_backpacks.gui.allow=Allow +retro_sophisticated_backpacks.gui.block=Block +retro_sophisticated_backpacks.gui.match_backpack_contents=Match Backpack Contents +retro_sophisticated_backpacks.gui.pickup_items=Pickup Items +retro_sophisticated_backpacks.gui.do_not_pickup_items=Do Not Pickup Items +retro_sophisticated_backpacks.gui.compact_only_uncraftable=Compact Only Uncraftable +retro_sophisticated_backpacks.gui.compact_anything=Compact Anything +retro_sophisticated_backpacks.gui.only_automatic=Only works with other upgrades/automation +retro_sophisticated_backpacks.gui.works_in_gui=Works in GUI as well +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=Allows single slot to be filled with the item\nand voids anything that overflows +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=Allows whole storage to be filled with the item\n and voids anything that overflows +retro_sophisticated_backpacks.gui.refill_target_tooltip=Refill %s +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=Scroll to change target slot item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade @@ -263,56 +244,44 @@ item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support -retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack -retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls -retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack -retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack -retro_sophisticated_backpacks.tooltip.mob_catcher_upgrade=Captures passive mobs into backpack storage slots with sneak right-click -retro_sophisticated_backpacks.tooltip.advanced_mob_catcher_upgrade=Captures passive and hostile mobs into backpack storage slots with sneak right-click retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper +retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swap +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Tool Swap retro_sophisticated_backpacks.gui.tank_settings=Tank retro_sophisticated_backpacks.gui.pump_settings=Pump retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump -retro_sophisticated_backpacks.gui.battery_settings=Battery +retro_sophisticated_backpacks.gui.battery_settings=Batt. retro_sophisticated_backpacks.gui.anvil_settings=Anvil -retro_sophisticated_backpacks.gui.pump_input=Pump into backpack +retro_sophisticated_backpacks.gui.pump_input=Input retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank -retro_sophisticated_backpacks.gui.pump_output=Pump out of backpack +retro_sophisticated_backpacks.gui.pump_output=Output retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank -retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interact with tanks and pipes +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interact With Tanks & Pipes retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers -retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Do not interact with tanks and pipes +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Do Not Interact With Tanks & Pipes retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers -retro_sophisticated_backpacks.gui.pump_world=Interact with world +retro_sophisticated_backpacks.gui.pump_world=Interact With World retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world -retro_sophisticated_backpacks.gui.pump_no_world=Do not interact with world +retro_sophisticated_backpacks.gui.pump_no_world=Do Not Interact With World retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world -retro_sophisticated_backpacks.gui.pump_hand=Interact with held containers +retro_sophisticated_backpacks.gui.pump_hand=Interact With\nFluid Container in Hand retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player -retro_sophisticated_backpacks.gui.pump_no_hand=Do not interact with held containers +retro_sophisticated_backpacks.gui.pump_no_hand=Do Not Interact With\nFluid Container in Hand retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it retro_sophisticated_backpacks.gui.anvil_no_result=No Result retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage retro_sophisticated_backpacks.gui.jukebox_play=Play retro_sophisticated_backpacks.gui.jukebox_stop=Stop -retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc -retro_sophisticated_backpacks.gui.jukebox_next=Next Disc -retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_previous=Previous +retro_sophisticated_backpacks.gui.jukebox_next=Next +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Disabled +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle Enabled retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One -retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Disabled retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item @@ -337,3 +306,53 @@ retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slot retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Compacts items into their compressed variants\nBoth 2x2 and 3x3 recipes with more filtering options +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Deposits items from backpack into sneak right clicked inventory\nHas more filtering options +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=Feeds player with food from backpack's inventory\nMore options for when food gets fed to player +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=Filters items piped in and/or out of backpack\nHas more filtering options +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=Portable Jukebox with support for more music discs\nAlso more playback options +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=Magnets items into backpack at a greater range\nHas more filtering options +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=Captures passive and hostile mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=Makes backpack pickup items\nHas more filtering options +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=Pumps Fluids between Tank upgrade and adjacent blocks\nWorks with fluid containers in hand and fluid blocks in world\nAllows to filter which fluids are pumped +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=Keeps refilling stack of selected items in player's inventory\nAllows for more precise target slot selection\nAlso allows middle click picking blocks from backpack +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=Restocks backpack from sneak right clicked inventory\nHas more filtering options +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=Automatically swaps item in player's hand for the one effective on the block/entity when left clicked\nHas filter options and extra interaction support +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=Voids items selected in filter\nHas more filtering options +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=Anvil in an upgrade tab +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=Replaces part of backpack's inventory with energy storage +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=Compacts items into their compressed variants\nOnly 2x2 recipes +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=Crafting table in an upgrade tab +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=Deposits items from backpack into sneak right clicked inventory +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=Backpack becomes indestructible\nCan't despawn or fall into void +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=Stack multipliers will stack by multiplying instead of adding +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=Feeds player with food from backpack's inventory +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=Filters items piped in and/or out of backpack +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=Makes it possible to put backpacks into the backpack +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=Portable Jukebox +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=Magnets items into backpack at range +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=Captures passive mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=Makes backpack pickup items +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=Pumps fluids between Tank upgrade and adjacent blocks +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=Keeps refilling stack of selected items in player's inventory +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=Restocks backpack from sneak right clicked inventory +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=Multiplies the number of stacks that can fit in a slot by %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=Multiplies the number of stacks that can fit in a slot by %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=Multiplies the number of stacks that can fit in a slot by %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=Multiplies the number of stacks that can fit in a slot by %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=Multiplies the number of stacks that can fit in a slot by %s +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=Replaces part of backpack's inventory with fluid storage +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=Automatically swaps item in player's hand for the one effective on the block/entity when these are left clicked. +item.retro_sophisticated_backpacks.void_upgrade.tooltip=Voids items selected in filter +retro_sophisticated_backpacks.gui.inception_settings=Inception +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=Backpack can not be open by another player when right clicking on this player's back even if the backpack is worn there +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=When this backpack is worn and visible another player can open it when right clicking on this player's back +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=Backpack / Storage gui clears the search phrase when closed and shows all unfiltered item when open again +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=Backpack / Storage gui keeps the search phrase and prefills it / filters by it when open again +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=Open upgrade tab gets closed when the backpack/storage gui is closed and when the gui is next open all of the tabs are closed +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=On close of its gui the backpack/storage records which upgrade tab was last open and opens it when the gui is open next time +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=Shift click from storage/inventory will first try to put the stack in inventory/storage and only then into an open tab. +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=Shift click from storage/inventory will first try to put the stack in an open tab and only then into inventory/storage. +retro_sophisticated_backpacks.gui.tooltip.stack_count=Count: %s diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang index 0f44b1d..350823a 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang @@ -6,14 +6,15 @@ tile.retro_sophisticated_backpacks.backpack_diamond.name=Mochila de Diamante tile.retro_sophisticated_backpacks.backpack_obsidian.name=Mochila de Obsidiana #Objetos -item.retro_sophisticated_backpacks.upgrade_base.name=Base de Mejora -item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=Mejora de Apilado Nivel Inicial -item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=Mejora de Apilado Nivel 1 -item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=Mejora de Apilado Nivel 2 -item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=Mejora de Apilado Nivel 3 -item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=Mejora de Apilado Nivel 4 -item.retro_sophisticated_backpacks.crafting_upgrade.name=Mejora de Artesanía -item.retro_sophisticated_backpacks.inception_upgrade.name=Mejora de Incepción +item.retro_sophisticated_backpacks.upgrade_base.name=Base de mejora +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=Mejora de stack nivel inicial +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=Mejora de stack nivel 1 +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=Mejora de stack nivel 2 +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=Mejora de stack nivel 3 +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=Mejora de stack nivel 4 +item.retro_sophisticated_backpacks.exponential_stack_upgrade.name=Mejora de stack exponencial +item.retro_sophisticated_backpacks.crafting_upgrade.name=Mejora de fabricación +item.retro_sophisticated_backpacks.inception_upgrade.name=Mejora de incepción #Pestañas Creativas itemGroup.retro_sophisticated_backpacks.creative_tab=Mochila Sofisticada Retro @@ -21,128 +22,303 @@ itemGroup.retro_sophisticated_backpacks.creative_tab=Mochila Sofisticada Retro #Descripciones emergentes (Tooltips) retro_sophisticated_backpacks.tooltip.backpack.inventory_size=Tamaño de inventario: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=Tamaño de ranuras de mejora: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Multiplicador de tamaño de stack: %s retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s -retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank -retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Tanque vacío +retro_sophisticated_backpacks.tooltip.backpack.energy=%s EF retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy -retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades -retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory -retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents -retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents -retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Mejoras +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventario +retro_sophisticated_backpacks.tooltip.backpack.empty=Sin mejoras o contenidos de inventario +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Presiona <%s> para ver los contenidos +retro_sophisticated_backpacks.tooltip.backpack.shift=Shift izquierdo -retro_sophisticated_backpacks.tooltip.upgrade_base=¡No hace nada! Siéntete libre de ponerlo en tus ranuras de mejora. -retro_sophisticated_backpacks.tooltip.stack_upgrade=Multiplica el tamaño del apilado por %d -retro_sophisticated_backpacks.tooltip.crafting_upgrade=Añade una cuadrícula de fabricación adicional al lado de la mochila -retro_sophisticated_backpacks.tooltip.inception_upgrade=Permite que las mochilas se guarden dentro de otras mochilas -retro_sophisticated_backpacks.tooltip.shift_to_reveal= #Elementos de GUI retro_sophisticated_backpacks.container.backpack=Mochila -item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade -item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade -item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade -item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade -item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade -item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade -item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade -item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade -retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations -retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations -retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations -retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations -retro_sophisticated_backpacks.gui.magnet_settings=Magnet -retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet -retro_sophisticated_backpacks.gui.void_settings=Void -retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void -retro_sophisticated_backpacks.gui.refill_settings=Refill -retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill -retro_sophisticated_backpacks.gui.compacting_settings=Compa... -retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting -retro_sophisticated_backpacks.gui.void_always=Void Always -retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow -retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow -retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes -retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes -retro_sophisticated_backpacks.gui.refill_target_any=Any Slot -retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand -retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI -retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI -item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade -item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade -item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade -item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade -item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade -item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade -item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade -item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade -item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support -retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack -retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls -retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack -retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +item.retro_sophisticated_backpacks.magnet_upgrade.name=Mejora de imán +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Mejora de imán avanzada +item.retro_sophisticated_backpacks.void_upgrade.name=Mejora de vacío +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Mejora de vacío avanzada +item.retro_sophisticated_backpacks.refill_upgrade.name=Mejora de rellenado +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Mejora de rellenado avanzada +item.retro_sophisticated_backpacks.compacting_upgrade.name=Mejora de compactación +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Mejora de compactación avanzada +retro_sophisticated_backpacks.gui.magnet_settings=Imán +retro_sophisticated_backpacks.gui.advanced_magnet_settings=Imán avanzado +retro_sophisticated_backpacks.gui.void_settings=Vacío +retro_sophisticated_backpacks.gui.advanced_void_settings=Vacío avanzado +retro_sophisticated_backpacks.gui.refill_settings=Rellenado +retro_sophisticated_backpacks.gui.advanced_refill_settings=Rellenado avanzado +retro_sophisticated_backpacks.gui.compacting_settings=Compactación +retro_sophisticated_backpacks.gui.advanced_compacting_settings=Compactación avanzada +retro_sophisticated_backpacks.gui.void_always=Vaciar cualquiera +retro_sophisticated_backpacks.gui.void_slot_overflow=Vaciar desbordamiento +retro_sophisticated_backpacks.gui.void_storage_overflow=Vaciar desbordamiento de almacenamiento +retro_sophisticated_backpacks.gui.refill_target_any=Cualquier slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Mano principal +retro_sophisticated_backpacks.gui.refill_target_off_hand=Mano secundaria +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Slot de barra rápida 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Slot de barra rápida 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Slot de barra rápida 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Slot de barra rápida 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Slot de barra rápida 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Slot de barra rápida 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Slot de barra rápida 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Slot de barra rápida 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Slot de barra rápida 9 +retro_sophisticated_backpacks.gui.allow=Permitir +retro_sophisticated_backpacks.gui.block=Bloquear +retro_sophisticated_backpacks.gui.match_backpack_contents=Coincidir con el contenido de la mochila +retro_sophisticated_backpacks.gui.pickup_items=Recoger objetos +retro_sophisticated_backpacks.gui.do_not_pickup_items=No recoger objetos +retro_sophisticated_backpacks.gui.compact_only_uncraftable=Compactar solo no fabricables +retro_sophisticated_backpacks.gui.compact_anything=Compactar cualquier cosa +retro_sophisticated_backpacks.gui.only_automatic=Solo funciona con otras mejoras/automatización +retro_sophisticated_backpacks.gui.works_in_gui=Funciona también en la interfaz +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=Permite que una sola ranura se llene con el objeto\ny vacía cualquier cosa que desborde +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=Permite que todo el almacenamiento se llene con el objeto\ny vacía cualquier cosa que desborde +retro_sophisticated_backpacks.gui.refill_target_tooltip=Rellenar %s +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=Desplazar para cambiar el slot objetivo +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Mejora de eternidad +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Mejora de tocadiscos +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Mejora de tocadiscos avanzada +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Mejora de cambio de herramienta +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Mejora de cambio de herramienta avanzada +item.retro_sophisticated_backpacks.tank_upgrade.name=Mejora de tanque +item.retro_sophisticated_backpacks.pump_upgrade.name=Mejora de bombeado +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Mejora de bombeado avanzada +item.retro_sophisticated_backpacks.battery_upgrade.name=Mejora de batería +item.retro_sophisticated_backpacks.anvil_upgrade.name=Mejora de yunque retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting -retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper -retro_sophisticated_backpacks.gui.tank_settings=Tank -retro_sophisticated_backpacks.gui.pump_settings=Pump -retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump -retro_sophisticated_backpacks.gui.battery_settings=Battery -retro_sophisticated_backpacks.gui.anvil_settings=Anvil -retro_sophisticated_backpacks.gui.pump_input=Pump In -retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers -retro_sophisticated_backpacks.gui.pump_world=World -retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.jukebox_settings=Tocadiscos +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Tocadiscos avanzado +retro_sophisticated_backpacks.gui.tool_swapper_settings=Intercambio de herramientas +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Intercambio de herramientas +retro_sophisticated_backpacks.gui.tank_settings=Tanque +retro_sophisticated_backpacks.gui.pump_settings=Bombeado +retro_sophisticated_backpacks.gui.advanced_pump_settings=Bombeado avanzado +retro_sophisticated_backpacks.gui.battery_settings=Batería +retro_sophisticated_backpacks.gui.anvil_settings=Yunque +retro_sophisticated_backpacks.gui.pump_input=Entrada +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interactuar con tanques y tuberías +retro_sophisticated_backpacks.gui.pump_world=Interactuar con el mundo +retro_sophisticated_backpacks.gui.pump_hand=Interactuar con\ncontenedor de fluido en la mano retro_sophisticated_backpacks.gui.anvil_no_result=No Result retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage -retro_sophisticated_backpacks.gui.jukebox_play=Play -retro_sophisticated_backpacks.gui.jukebox_stop=Stop -retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc -retro_sophisticated_backpacks.gui.jukebox_next=Next Disc -retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On -retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All -retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One -retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.jukebox_play=Reproducir +retro_sophisticated_backpacks.gui.jukebox_stop=Detener +retro_sophisticated_backpacks.gui.jukebox_previous=Anterior +retro_sophisticated_backpacks.gui.jukebox_next=Siguiente +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Reproducción aleatoria desactivada +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Reproducción aleatoria activada +retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repetir todo +retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repetir uno +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repetición desactivada retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools -retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Back To Backpack -retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings -retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings -retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag -retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Volver a mochila +retro_sophisticated_backpacks.gui.memory_settings.tooltip=Configuración de ranuras de memoria +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Permite seleccionar ranuras que recuerdan su contenido y solo permiten stacks coincidentes en ellas\nAbre la pestaña para modificar la configuración de las ranuras +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Permite seleccionar ranuras que recuerdan su contenido y solo permiten stacks coincidentes en ellas\nSeleccionar todo / Deseleccionar todo = botones\nSeleccionar ranura = clic izquierdo/arrastrar\nDeseleccionar ranura = clic derecho/arrastrar +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=Configuración de ranuras sin ordenar +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Permite seleccionar ranuras que son ignoradas por el ordenamiento\nAbre la pestaña para modificar la configuración de las ranuras +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Permite seleccionar ranuras que son ignoradas por el ordenamiento\nSeleccionar todo / Deseleccionar todo = botones\nSeleccionar ranura = clic izquierdo/arrastrar\nDeseleccionar ranura = clic derecho/arrastrar + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Compacta objetos en sus variantes comprimidas\nRecetas 2x2 y 3x3 con más opciones de filtrado +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=Mejora de depósito avanzada +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Deposita objetos de la mochila en el inventario al que se le hace clic derecho agachado\nTiene más opciones de filtrado +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=Mejora de alimentación avanzada +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=Alimenta al jugador con comida del inventario de la mochila\nMás opciones para cuando la comida se le da al jugador +item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=Mejora de filtrado avanzada +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=Filtra objetos que entran y/o salen de la mochila\nTiene más opciones de filtrado +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=Tocadiscos portátil con soporte para más discos de música\nTambién más opciones de reproducción +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=Atrae objetos a la mochila a mayor distancia\nTiene más opciones de filtrado +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=Captures passive and hostile mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=Mejora de recolección avanzada +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=Hace que la mochila recoja objetos\nTiene más opciones de filtrado +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=Bombea fluidos entre la mejora de tanque y bloques adyacentes\nFunciona con contenedores de fluido en la mano y bloques de fluido en el mundo\nPermite filtrar qué fluidos se bombean +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=Mantiene rellenando el stack de objetos seleccionados en el inventario del jugador\nPermite una selección de slot de objetivo más precisa\nTambién permite la selección de bloques al hacer clic con el botón central en la mochila +item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=Mejora de reabastecimiento avanzada +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=Reabastece la mochila del inventario al que se le hace clic derecho agachado\nTiene más opciones de filtrado +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=Cambia automáticamente el objeto en la mano del jugador por el adecuado para el bloque/entidad al hacer clic izquierdo\nTiene opciones de filtro e interacción adicional +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=Destruye objetos seleccionados en el filtro\nTiene más opciones de filtrado +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=Yunque en una pestaña de mejora +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=Reemplaza parte del inventario de la mochila con almacenamiento de energía +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=Compacta objetos en sus variantes comprimidas\nSólo recetas 2x2 +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=Mesa de trabajo en una pestaña de mejora +item.retro_sophisticated_backpacks.deposit_upgrade.name=Mejora de depósito +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=Deposita objetos de la mochila en el inventario al que se le hace clic derecho agachado +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=La mochila se vuelve indestructible\nNo puede desaparecer o caer al vacío +item.retro_sophisticated_backpacks.feeding_upgrade.name=Mejora de alimentación +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=Alimenta al jugador con comida del inventario de la mochila +item.retro_sophisticated_backpacks.filter_upgrade.name=Mejora de filtrado +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=Filtra objetos que entran y/o salen de la mochila +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=Hace posible poner mochilas dentro de la mochila +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=Tocadiscos portátil +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=Atrae objetos a la mochila a distancia +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=Captures passive mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.pickup_upgrade.name=Mejora de recolección +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=Hace que la mochila recoja objetos +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=Bombea fluidos entre la mejora de tanque y bloques adyacentes +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=Mantiene rellenando el stack de objetos seleccionados en el inventario del jugador +item.retro_sophisticated_backpacks.restock_upgrade.name=Mejora de reabastecimiento +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=Reabastece la mochila del inventario al que se le hace clic derecho agachado +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=Multiplica el número de stacks que caben en un slot por %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=Multiplica el número de stacks que caben en un slot por %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=Multiplica el número de stacks que caben en un slot por %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=Multiplica el número de stacks que caben en un slot por %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=Multiplica el número de stacks que caben en un slot por %s +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=Los multiplicadores de stack se acumulan multiplicándose en lugar de sumándose +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=Reemplaza parte del inventario de la mochila con almacenamiento de fluido +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=Cambia automáticamente el objeto en la mano del jugador por el efectivo en el bloque/entidad cuando se hace clic izquierdo. +item.retro_sophisticated_backpacks.void_upgrade.tooltip=Destruye objetos seleccionados en el filtro +retro_sophisticated_backpacks.gui.advanced_deposit_settings=Depósito avanzado +retro_sophisticated_backpacks.gui.advanced_feeding_settings=Alimentación avanzada +retro_sophisticated_backpacks.gui.advanced_filter_settings=Filtro avanzado +retro_sophisticated_backpacks.gui.advanced_pickup_settings=Recolección avanzada +retro_sophisticated_backpacks.gui.advanced_restock_settings=Reabastecimiento avanzado +retro_sophisticated_backpacks.gui.backpack_settings=Configuración de mochila +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=Configuración de mochila +retro_sophisticated_backpacks.gui.blacklist=Bloquear +retro_sophisticated_backpacks.gui.complete_hunger=Solo alimentar cuando el jugador tenga suficiente hambre para\nno desperdiciar ningún punto de hambre de la comida en absoluto +retro_sophisticated_backpacks.gui.consider_health=Alimentar al jugador inmediatamente cuando sea herido\nIgnora la configuración de hambre cuando el jugador no está a máxima salud +retro_sophisticated_backpacks.gui.crafting_settings=Fabricación +retro_sophisticated_backpacks.gui.deposit_settings=Depósito +retro_sophisticated_backpacks.gui.feeding_settings=Alimentación +retro_sophisticated_backpacks.gui.filter_settings=Filtro +retro_sophisticated_backpacks.gui.half_hunger=Solo alimentar cuando el jugador tenga suficiente hambre para\ndesperdiciar como máximo la mitad de los puntos de hambre de la comida +retro_sophisticated_backpacks.gui.ignore_durability=Ignorar durabilidad +retro_sophisticated_backpacks.gui.ignore_health=No considerar salud\nIgnora la salud del jugador y solo alimenta según la configuración de hambre +retro_sophisticated_backpacks.gui.ignore_nbt=Ignorar NBT +retro_sophisticated_backpacks.gui.immediate_hunger=Alimentar tan pronto como el jugador tenga un poco de hambre\ndesperdicia bastantes puntos de hambre de la comida +retro_sophisticated_backpacks.gui.inception_settings=Incepción +retro_sophisticated_backpacks.gui.input=Entrada +retro_sophisticated_backpacks.gui.input_output=Entrada y salida +retro_sophisticated_backpacks.gui.item_display_settings=Disposición de objetos +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Configuración de visualización de objetos +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Permite seleccionar una ranura que se usará para mostrar su objeto en la parte superior del almacenamiento +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Permite seleccionar una ranura que se usará para mostrar su objeto en la parte superior del almacenamiento\nSeleccionar ranura = clic izquierdo/arrastrar\nDeseleccionar ranura = clic derecho/arrastrar +retro_sophisticated_backpacks.gui.lock_all_sort=Seleccionar todas las ranuras +retro_sophisticated_backpacks.gui.match_durability=Coincidir durabilidad +retro_sophisticated_backpacks.gui.match_item=Coincidir objeto +retro_sophisticated_backpacks.gui.match_mod_id=Coincidir mod +retro_sophisticated_backpacks.gui.match_nbt=Coincidir NBT +retro_sophisticated_backpacks.gui.memorize_all=Seleccionar todas las ranuras +retro_sophisticated_backpacks.gui.memory_settings=Memoria +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release +retro_sophisticated_backpacks.gui.output=Salida +retro_sophisticated_backpacks.gui.pickup_settings=Recolección +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=No interactuar con tanques y tuberías +retro_sophisticated_backpacks.gui.pump_no_hand=No interactuar con\ncontenedor de fluido en la mano +retro_sophisticated_backpacks.gui.pump_no_world=No interactuar con el mundo +retro_sophisticated_backpacks.gui.pump_output=Salida +retro_sophisticated_backpacks.gui.restock_settings=Reabastecimiento +retro_sophisticated_backpacks.gui.search=Haz clic para buscar +retro_sophisticated_backpacks.gui.search_detail=@ prefijo para buscar por nombre de mod +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=Otro jugador NO puede abrir +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=La mochila no puede ser abierta por otro jugador al hacer clic derecho en la espalda de este jugador, incluso si está equipada allí +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=Otro jugador puede abrir +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=Cuando esta mochila está equipada y visible, otro jugador puede abrirla al hacer clic derecho en la espalda de este jugador +retro_sophisticated_backpacks.gui.settings_button.context_backpack=Mochila +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=Configuración de esta mochila +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=Heredado del jugador o anulado para esta mochila +retro_sophisticated_backpacks.gui.settings_button.context_player=Jugador +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Configuración de nivel del jugador +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=Aplica a todas las mochilas/almacenamientos a menos que se anule +retro_sophisticated_backpacks.gui.settings_button.display_side_front=Mostrar en la parte frontal +retro_sophisticated_backpacks.gui.settings_button.display_side_left=Mostrar en el lado izquierdo +retro_sophisticated_backpacks.gui.settings_button.display_side_right=Mostrar en el lado derecho +retro_sophisticated_backpacks.gui.settings_button.item_display_color=Alternar color +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=Siguiente = Clic izquierdo\nAnterior = Clic derecho +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Mantener frase de búsqueda: APAGADO +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=La interfaz de mochila/almacenamiento borra la frase de búsqueda cuando se cierra y muestra todos los objetos sin filtrar cuando se abre nuevamente +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Mantener frase de búsqueda: ENCENDIDO +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=La interfaz de mochila/almacenamiento mantiene la frase de búsqueda y la prellena/filtra por ella cuando se abre nuevamente +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Mantener pestaña abierta: APAGADO +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=La pestaña de mejora abierta se cierra cuando se cierra la interfaz de la mochila/almacenamiento y cuando la interfaz se abre la próxima vez, todas las pestañas están cerradas +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Mantener pestaña abierta: ENCENDIDO +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=Al cerra su interfaz, la mochila/almacenamiento registra qué pestaña de mejora estaba abierta por última vez y la abre cuando la interfaz se abre la próxima vez +retro_sophisticated_backpacks.gui.settings_button.rotate=Rotar +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Sentido horario = Clic izquierdo\nSentido antihorario = Clic derecho +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift clic en el inventario primero +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=Al shift clic desde el almacenamiento/inventario, primero intentará poner el stack en el inventario/almacenamiento y solo luego en una pestaña abierta. +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift clic en la pestaña abierta primero +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=Al shift clic desde el almacenamiento/inventario, primero intentará poner el stack en una pestaña abierta y solo luego en el inventario/almacenamiento. +retro_sophisticated_backpacks.gui.sort_by_count=Por cantidad +retro_sophisticated_backpacks.gui.sort_by_mod_id=Por mod +retro_sophisticated_backpacks.gui.sort_by_name=Por nombre +retro_sophisticated_backpacks.gui.sort_by_ore_dict=Por etiquetas +retro_sophisticated_backpacks.gui.sort_inventory=Ordenar inventario +retro_sophisticated_backpacks.gui.sorting_settings=Sin ordenar +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=That mob is blocked from capture +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=Bosses cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=Captured %s +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=Hostile mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=That mob cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=Mobs with inventories cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=Backpack has no Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=Only the owner can capture that mob +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=Only one Mob Catcher Upgrade is allowed per backpack +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=Mobs with passengers or vehicles cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=Players cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there +retro_sophisticated_backpacks.gui.status.mob_catcher_released=Released %s +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slots, more than this upgrade allows (%s) +retro_sophisticated_backpacks.gui.tooltip.stack_count=Cantidad: %s +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Transferir al almacenamiento +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transferir coincidente al almacenamiento +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift para transferir todo +retro_sophisticated_backpacks.gui.transfer_to_player_inv=Transferir al inventario +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Transferir coincidente al inventario +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift para transferir todo +retro_sophisticated_backpacks.gui.unlock_all_sort=Deseleccionar todas las ranuras +retro_sophisticated_backpacks.gui.unmemorize_all=Deseleccionar todas las ranuras +retro_sophisticated_backpacks.gui.whitelist=Permitir + +# Fallbacks for keys used by current code +retro_sophisticated_backpacks.key.open_backpack.desc=Opens Backpack in Inventory +retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpacks +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side +retro_sophisticated_backpacks.gui.stack_size_extra=Count: %s / %s +retro_sophisticated_backpacks.gui.not_in_effect=Not in effect +retro_sophisticated_backpacks.gui.match_ore_dict=By Ore Dictionary +retro_sophisticated_backpacks.gui.add_ore_dict_entry=Add Ore Dict. +retro_sophisticated_backpacks.gui.remove_ore_dict_entry=Remove Ore Dict. +retro_sophisticated_backpacks.gui.ore_dict_input_help=You can input ore dictionary here,\nregex is supported. +retro_sophisticated_backpacks.gui.ore_dict_input_help.pro_tip=Protip: You can hover item onto entry\n to check if the entry is applicable,\nor hover on textfield to see available entries. +retro_sophisticated_backpacks.gui.ore_dict_list_entries=Available ore dict: +retro_sophisticated_backpacks.gui.none=(None) +retro_sophisticated_backpacks.gui.craft_into_backpack=Shift Click Result Into Backpack +retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift Click Result Into Player's Inventory +retro_sophisticated_backpacks.gui.settings=Settings +retro_sophisticated_backpacks.gui.configuration_tab=Configuration Tab +retro_sophisticated_backpacks.gui.memorized_slot=Memorized Slot +retro_sophisticated_backpacks.gui.no_sorting_slot=No Sorting Slot +retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank +retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang index 13b9e42..49425fa 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang @@ -6,25 +6,25 @@ tile.retro_sophisticated_backpacks.backpack_diamond.name=ダイヤモンドの tile.retro_sophisticated_backpacks.backpack_obsidian.name=黒曜石のバックパック # Items -item.retro_sophisticated_backpacks.upgrade_base.name=アップグレードの原型 -item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=スタックアップグレード スターターティア -item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=スタックアップグレード ティア1 -item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=スタックアップグレード ティア2 -item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=スタックアップグレード ティア3 -item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=スタックアップグレード ティア4 +item.retro_sophisticated_backpacks.upgrade_base.name=リュックの強化素材 +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=スタック数増加x1.5 +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=スタック数増加x2 +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=スタック数増加x4 +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=スタック数増加x8 +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=スタック数増加x16 item.retro_sophisticated_backpacks.exponential_stack_upgrade.name=指数スタックアップグレード -item.retro_sophisticated_backpacks.crafting_upgrade.name=クラフトアップグレード -item.retro_sophisticated_backpacks.inception_upgrade.name=入れ子アップグレード -item.retro_sophisticated_backpacks.pickup_upgrade.name=収集アップグレード -item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=強化収集アップグレード -item.retro_sophisticated_backpacks.feeding_upgrade.name=食事アップグレード -item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=強化食事アップグレード -item.retro_sophisticated_backpacks.deposit_upgrade.name=収納アップグレード -item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=強化収納アップグレード -item.retro_sophisticated_backpacks.restock_upgrade.name=回収アップグレード -item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=強化回収アップグレード -item.retro_sophisticated_backpacks.filter_upgrade.name=フィルターアップグレード -item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=強化フィルターアップグレード +item.retro_sophisticated_backpacks.crafting_upgrade.name=作業台機能 +item.retro_sophisticated_backpacks.inception_upgrade.name=入れ子機能 +item.retro_sophisticated_backpacks.pickup_upgrade.name=アイテム直入れ機能 +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=アイテム直入れ機能・改 +item.retro_sophisticated_backpacks.feeding_upgrade.name=ごはん機能 +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=ごはん機能・改 +item.retro_sophisticated_backpacks.deposit_upgrade.name=収納機能 +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=収納機能・改 +item.retro_sophisticated_backpacks.restock_upgrade.name=回収機能 +item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=回収機能・改 +item.retro_sophisticated_backpacks.filter_upgrade.name=仕分けフィルタ機能 +item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=仕分けフィルタ機能・改 # Creative Tabs itemGroup.retro_sophisticated_backpacks.creative_tab=Retro Sophisticated Backpacks @@ -36,224 +36,323 @@ retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpacks # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=インベントリスロット数: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=アップグレードスロット数: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=スタック数: %s倍 retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s -retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=空のタンク retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy -retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades -retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory -retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents -retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents -retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=アップグレード +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=インベントリ +retro_sophisticated_backpacks.tooltip.backpack.empty=からっぽ +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=<%s>を押すと中身を表示 +retro_sophisticated_backpacks.tooltip.backpack.shift=左SHIFTキー -retro_sophisticated_backpacks.tooltip.upgrade_base=何もしません! ご自由にアップグレードスロットに入れてください! -retro_sophisticated_backpacks.tooltip.stack_upgrade=スタック数の上限を%d倍にします -retro_sophisticated_backpacks.tooltip.exponential_stack_upgrade=スタックアップグレードを複数使用した時の計算方法を加算から乗算にします -retro_sophisticated_backpacks.tooltip.crafting_upgrade=バックパックの側面にクラフトグリッドを追加します -retro_sophisticated_backpacks.tooltip.inception_upgrade=バックパックの中に別のバックパックを入れられるようになります -retro_sophisticated_backpacks.tooltip.pickup_upgrade=拾ったアイテムを直接リュックに入れられるようになります -retro_sophisticated_backpacks.tooltip.advanced_pickup_upgrade=拾ったアイテムを直接リュックに入れられるようになります より詳細な設定が可能です -retro_sophisticated_backpacks.tooltip.feeding_upgrade=バックパックに入っている食べ物を自動で食べられるようになります -retro_sophisticated_backpacks.tooltip.advanced_feeding_upgrade=バックパックに入っている食べ物を自動で食べられるようになります より詳細な設定が可能です -retro_sophisticated_backpacks.tooltip.deposit_upgrade=スニーク右クリックしたインベントリにアイテムを収納できるようになります -retro_sophisticated_backpacks.tooltip.advanced_deposit_upgrade=スニーク右クリックしたインベントリにアイテムを収納できるようになります より詳細な設定が可能です -retro_sophisticated_backpacks.tooltip.restock_upgrade=スニーク右クリックしたインベントリからアイテムを回収できるようになります -retro_sophisticated_backpacks.tooltip.advanced_restock_upgrade=スニーク右クリックしたインベントリからアイテムを回収できるようになります より詳細な設定が可能です -retro_sophisticated_backpacks.tooltip.filter_upgrade=置かれているときのアイテムの入出力を制限できるようになります -retro_sophisticated_backpacks.tooltip.advanced_filter_upgrade=置かれているときに出し入れできるアイテムを制限できるようになります より詳細な設定が可能です -retro_sophisticated_backpacks.tooltip.shift_to_reveal= # Gui Elements retro_sophisticated_backpacks.container.backpack=バックパック -retro_sophisticated_backpacks.gui.pickup_settings=収集 -retro_sophisticated_backpacks.gui.advanced_pickup_settings=強化収集 +retro_sophisticated_backpacks.gui.pickup_settings=直入れ +retro_sophisticated_backpacks.gui.advanced_pickup_settings=直入れ・改 -retro_sophisticated_backpacks.gui.feeding_settings=食事 -retro_sophisticated_backpacks.gui.advanced_feeding_settings=強化食事 +retro_sophisticated_backpacks.gui.feeding_settings=ごはん +retro_sophisticated_backpacks.gui.advanced_feeding_settings=ごはん・改 retro_sophisticated_backpacks.gui.deposit_settings=収納 -retro_sophisticated_backpacks.gui.advanced_deposit_settings=強化収納 +retro_sophisticated_backpacks.gui.advanced_deposit_settings=収納・改 retro_sophisticated_backpacks.gui.restock_settings=回収 -retro_sophisticated_backpacks.gui.advanced_restock_settings=強化回収 +retro_sophisticated_backpacks.gui.advanced_restock_settings=回収・改 -retro_sophisticated_backpacks.gui.filter_settings=フィルター -retro_sophisticated_backpacks.gui.advanced_filter_settings=強化フィルター +retro_sophisticated_backpacks.gui.filter_settings=仕分け +retro_sophisticated_backpacks.gui.advanced_filter_settings=仕分け・改 -retro_sophisticated_backpacks.gui.memory_settings=記憶 -retro_sophisticated_backpacks.gui.sorting_settings=並べ替え無効 -retro_sophisticated_backpacks.gui.memory_settings.tooltip=スロット記憶設定 -retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=内容を記憶し、一致するアイテムのみ収納するスロットを選択します\nタブを開いてスロット設定を変更します -retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=内容を記憶し、一致するアイテムのみ収納するスロットを選択します\n全選択/全解除=ボタン\n選択=左クリック/ドラッグ\n解除=右クリック/ドラッグ -retro_sophisticated_backpacks.gui.sorting_settings.tooltip=並べ替え除外設定 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=並べ替え時に無視されるスロットを選択します\nタブを開いてスロット設定を変更します -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=並べ替え時に無視されるスロットを選択します\n全選択/全解除=ボタン\n選択=左クリック/ドラッグ\n解除=右クリック/ドラッグ +retro_sophisticated_backpacks.gui.memory_settings=個別設定 +retro_sophisticated_backpacks.gui.sorting_settings=並び替え除外 +retro_sophisticated_backpacks.gui.memory_settings.tooltip=スロットごとの設定 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=スロットの内容を記憶し、一致するアイテムのみ収納します。\n設定タブを開く +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=スロットの内容を記憶し、一致するアイテムのみ収納します。\n全選択/全解除=ボタンを押す\n個別選択=左クリック/ドラッグ\n選択解除=右クリック/ドラッグ +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=並び替えの除外設定 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=並び替えしないスロットを指定します。\n除外設定のタブを開きます。 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=並び替えしないスロットを指定します。\n全選択/全解除=ボタンを押す\nスロットの選択=左クリック/ドラッグ\n選択解除=右クリック/ドラッグ # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=個数: %s / %s retro_sophisticated_backpacks.gui.not_in_effect=効果なし -retro_sophisticated_backpacks.gui.whitelist=ホワイトリスト -retro_sophisticated_backpacks.gui.blacklist=ブラックリスト +retro_sophisticated_backpacks.gui.whitelist=指定したアイテムのみ +retro_sophisticated_backpacks.gui.blacklist=指定したアイテム以外 -retro_sophisticated_backpacks.gui.match_item=アイテムが一致 -retro_sophisticated_backpacks.gui.match_mod_id=Mod IDが一致 +retro_sophisticated_backpacks.gui.match_item=一致するアイテムのみ +retro_sophisticated_backpacks.gui.match_mod_id=MODが一致するアイテムのみ retro_sophisticated_backpacks.gui.match_ore_dict=鉱石辞書が一致 -retro_sophisticated_backpacks.gui.match_durability=耐久値が一致 -retro_sophisticated_backpacks.gui.ignore_durability=耐久値を無視 +retro_sophisticated_backpacks.gui.match_durability=耐久力が一致するアイテムのみ +retro_sophisticated_backpacks.gui.ignore_durability=耐久力は無視 -retro_sophisticated_backpacks.gui.match_nbt=NBTが一致 -retro_sophisticated_backpacks.gui.ignore_nbt=NBTを無視 +retro_sophisticated_backpacks.gui.match_nbt=NBTが一致するアイテムのみ +retro_sophisticated_backpacks.gui.ignore_nbt=NBTは無視 retro_sophisticated_backpacks.gui.add_ore_dict_entry=鉱石辞書の追加 retro_sophisticated_backpacks.gui.remove_ore_dict_entry=鉱石辞書の削除 retro_sophisticated_backpacks.gui.ore_dict_input_help=ここに鉱石辞書を入力 正規表現に対応しています -retro_sophisticated_backpacks.gui.complete_hunger=満腹度が十分に減少している場合のみ食べる\n満腹度を無駄にしない -retro_sophisticated_backpacks.gui.half_hunger=満腹度が十分に減少している場合のみ食べる\n最大でも半分までしか満腹度を無駄にしない -retro_sophisticated_backpacks.gui.immediate_hunger=満腹度が少しでも減少したら食べる\n満腹度がかなり無駄になる +retro_sophisticated_backpacks.gui.complete_hunger=食料が全く無駄にならないように食べます。 +retro_sophisticated_backpacks.gui.half_hunger=適当なタイミングで食べます。\n食料をあまり無駄にしません。 +retro_sophisticated_backpacks.gui.immediate_hunger=満腹度が少しでも減ると食べます。\n食料の消費が激しいです。 -retro_sophisticated_backpacks.gui.ignore_health=体力を考慮しない\nプレイヤーの体力を無視し、空腹の設定にのみ基づく -retro_sophisticated_backpacks.gui.consider_health=体力が減少したらすぐに食べる\nプレイヤーの体力が最大でない場合、空腹度設定を無視する +retro_sophisticated_backpacks.gui.ignore_health=体力を考慮しません。\n満腹度の設定のみで食べます。 +retro_sophisticated_backpacks.gui.consider_health=体力が減るとすぐに食べます。\n体力が減った場合は満腹度の設定より優先されます。 -retro_sophisticated_backpacks.gui.input_output=入力&出力 -retro_sophisticated_backpacks.gui.input=入力のみ -retro_sophisticated_backpacks.gui.output=出力のみ +retro_sophisticated_backpacks.gui.input_output=出し入れを制限 +retro_sophisticated_backpacks.gui.input=入れるアイテムを制限 +retro_sophisticated_backpacks.gui.output=取り出すアイテムを制限 -retro_sophisticated_backpacks.gui.sort_inventory=バックパックインベントリを並べ替える -retro_sophisticated_backpacks.gui.sort_by_name=アイテム名で並べ替える -retro_sophisticated_backpacks.gui.sort_by_mod_id=Mod IDで並べ替える -retro_sophisticated_backpacks.gui.sort_by_count=個数で並べ替える -retro_sophisticated_backpacks.gui.sort_by_ore_dict=鉱石辞書で並べ替える +retro_sophisticated_backpacks.gui.sort_inventory=並べ替え +retro_sophisticated_backpacks.gui.sort_by_name=五十音順 +retro_sophisticated_backpacks.gui.sort_by_mod_id=By Mod +retro_sophisticated_backpacks.gui.sort_by_count=個数順 +retro_sophisticated_backpacks.gui.sort_by_ore_dict=タグ順 -retro_sophisticated_backpacks.gui.transfer_to_player_inv=全てのアイテムをプレイヤーのインベントリに移動させる -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=一致するアイテムのみをプレイヤーのインベントリに移動させる -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shiftを押してすべて移動 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=全てのアイテムをバックパックのインベントリに移動させる -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=一致するアイテムのみをバックパックのインベントリに移動させる -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shiftを押してすべて移動 +retro_sophisticated_backpacks.gui.transfer_to_player_inv=Transfer to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Transfer Matching to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift To Transfer All +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Transfer to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transfer Matching to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift To Transfer All retro_sophisticated_backpacks.gui.settings=設定 retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=戻る retro_sophisticated_backpacks.gui.configuration_tab=構成タブ retro_sophisticated_backpacks.gui.memorized_slot=記憶スロット -retro_sophisticated_backpacks.gui.memorize_all=全てのスロットを記憶する -retro_sophisticated_backpacks.gui.unmemorize_all=全てのスロットの記憶を解除する +retro_sophisticated_backpacks.gui.memorize_all=全てのスロットを選択 +retro_sophisticated_backpacks.gui.unmemorize_all=スロット選択を全解除 retro_sophisticated_backpacks.gui.no_sorting_slot=並べ替え無効スロット -retro_sophisticated_backpacks.gui.lock_all_sort=全てのスロットを並べ替え無効にする -retro_sophisticated_backpacks.gui.unlock_all_sort=全てのスロットの並べ替え無効を解除する - -item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade -item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade -item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade -item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade -item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade -item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade -item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade -item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade -retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations -retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations -retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations -retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations -retro_sophisticated_backpacks.gui.magnet_settings=Magnet -retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet -retro_sophisticated_backpacks.gui.void_settings=Void -retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void -retro_sophisticated_backpacks.gui.refill_settings=Refill -retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill -retro_sophisticated_backpacks.gui.compacting_settings=Compa... -retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting -retro_sophisticated_backpacks.gui.void_always=Void Always -retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow +retro_sophisticated_backpacks.gui.lock_all_sort=全てのスロットを選択 +retro_sophisticated_backpacks.gui.unlock_all_sort=スロット選択を全解除 + +item.retro_sophisticated_backpacks.magnet_upgrade.name=アイテム引き寄せ機能 +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=アイテム引き寄せ機能・改 +item.retro_sophisticated_backpacks.void_upgrade.name=ごみ箱機能 +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=ごみ箱機能・改 +item.retro_sophisticated_backpacks.refill_upgrade.name=補充機能 +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=補充機能・改 +item.retro_sophisticated_backpacks.compacting_upgrade.name=アイテム圧縮機能 +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=アイテム圧縮機能・改 +retro_sophisticated_backpacks.gui.magnet_settings=引き寄せ +retro_sophisticated_backpacks.gui.advanced_magnet_settings=引き寄せ・改 +retro_sophisticated_backpacks.gui.void_settings=ごみ箱 +retro_sophisticated_backpacks.gui.advanced_void_settings=ごみ箱・改 +retro_sophisticated_backpacks.gui.refill_settings=補充 +retro_sophisticated_backpacks.gui.advanced_refill_settings=補充・改 +retro_sophisticated_backpacks.gui.compacting_settings=圧縮 +retro_sophisticated_backpacks.gui.advanced_compacting_settings=圧縮・改 +retro_sophisticated_backpacks.gui.void_always=全て消去 +retro_sophisticated_backpacks.gui.void_slot_overflow=1枠キープして消去 retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow -retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes -retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes -retro_sophisticated_backpacks.gui.refill_target_any=Any Slot -retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand -retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI -retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI -item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade -item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade -item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade -item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade -item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade -item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade -item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade -item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade -item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support -retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack -retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls -retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack -retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.gui.refill_target_any=指定したスロット +retro_sophisticated_backpacks.gui.refill_target_main_hand=手持ちのスロット +retro_sophisticated_backpacks.gui.refill_target_off_hand=オフハンド +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=スロット 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=スロット 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=スロット 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=スロット 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=スロット 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=スロット 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=スロット 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=スロット 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=スロット 9 +retro_sophisticated_backpacks.gui.allow=指定したアイテムのみ +retro_sophisticated_backpacks.gui.block=指定したアイテム以外 +retro_sophisticated_backpacks.gui.match_backpack_contents=既に入っているアイテムのみ +retro_sophisticated_backpacks.gui.pickup_items=アイテムを回収する +retro_sophisticated_backpacks.gui.do_not_pickup_items=アイテムを回収しない +retro_sophisticated_backpacks.gui.compact_only_uncraftable=元に戻せないアイテムは圧縮しない +retro_sophisticated_backpacks.gui.compact_anything=全てのアイテムを圧縮 +retro_sophisticated_backpacks.gui.only_automatic=他の追加機能や、ホッパー・ケーブルなどで入ってきたアイテムのみ +retro_sophisticated_backpacks.gui.works_in_gui=手動で入れたアイテムも対象 +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=1枠分は残し、2枠目以降のアイテムを消去します。 +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=Allows whole storage to be filled with the item\n and voids anything that overflows +retro_sophisticated_backpacks.gui.refill_target_tooltip=%sを補充 +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=スクロールで対象スロットを変更 +item.retro_sophisticated_backpacks.everlasting_upgrade.name=防護機能 +item.retro_sophisticated_backpacks.jukebox_upgrade.name=ジュークボックス機能 +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=ジュークボックス機能・改 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=ツール交換機能 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=ツール交換機能・改 +item.retro_sophisticated_backpacks.tank_upgrade.name=タンク機能 +item.retro_sophisticated_backpacks.pump_upgrade.name=ポンプ機能 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=ポンプ機能・改 +item.retro_sophisticated_backpacks.battery_upgrade.name=バッテリ機能 +item.retro_sophisticated_backpacks.anvil_upgrade.name=金床機能 retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting -retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.jukebox_settings=音楽 retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper -retro_sophisticated_backpacks.gui.tank_settings=Tank -retro_sophisticated_backpacks.gui.pump_settings=Pump -retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump -retro_sophisticated_backpacks.gui.battery_settings=Battery -retro_sophisticated_backpacks.gui.anvil_settings=Anvil -retro_sophisticated_backpacks.gui.pump_input=Pump In -retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers -retro_sophisticated_backpacks.gui.pump_world=World -retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.tool_swapper_settings=ツール交換 +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=ツール交換 +retro_sophisticated_backpacks.gui.tank_settings=タンク +retro_sophisticated_backpacks.gui.pump_settings=ポンプ +retro_sophisticated_backpacks.gui.advanced_pump_settings=ポンプ・改 +retro_sophisticated_backpacks.gui.battery_settings=バッテリ +retro_sophisticated_backpacks.gui.anvil_settings=金床 +retro_sophisticated_backpacks.gui.pump_input=液体を回収 +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_world=周囲の液体を回収 +retro_sophisticated_backpacks.gui.pump_hand=手に持った液体容器から回収 retro_sophisticated_backpacks.gui.anvil_no_result=No Result retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage -retro_sophisticated_backpacks.gui.jukebox_play=Play -retro_sophisticated_backpacks.gui.jukebox_stop=Stop -retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc -retro_sophisticated_backpacks.gui.jukebox_next=Next Disc -retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_play=再生 +retro_sophisticated_backpacks.gui.jukebox_stop=停止 +retro_sophisticated_backpacks.gui.jukebox_previous=Previous +retro_sophisticated_backpacks.gui.jukebox_next=Next +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Disabled +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle Enabled retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One -retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Disabled retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=圧縮できるアイテムを自動で圧縮します。\n3x3で圧縮するアイテムにも対応。 +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=スニークで右クリックしたチェストにアイテムを収納します。\nアイテムフィルタの数が増えます。 +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=リュック内の食料を自動で食べます。\n食事のタイミングを指定可能。 +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=出し入れするアイテムにフィルタをかけます。\nアイテムフィルタの数が増えます。 +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=リュックでより多くのディスクによるジュークボックスの機能を楽しめます。\n再生オプションも充実。 +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=より拾い範囲のアイテムを引き寄せてリュックに入れます。\nアイテムフィルタの数が増えます。 +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=Captures passive and hostile mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=拾ったアイテムが直接リュックに入ります。\nアイテムフィルタの数が増えます。 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=タンク機能に置いたストレージに液体を出し入れします。\n周囲の液体を回収できます。\n回収する液体を指定することができます。 +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=消費したアイテムをリュックから補充します。\n対象スロットの選択が可能。\nミドルクリックで補充可能。 +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=スニークで右クリックしたチェストから、アイテムをリュックに回収します。\nアイテムフィルタの数が増えます。 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=左クリック時、手に持ったアイテムをブロック/エンティティに有効なものへ自動で入れ替えます\nフィルター設定と追加の相互作用に対応しています +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=指定したアイテムを消滅させます。\n指定できるアイテム数が増えます。 +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=リュック内で金床が使えるようになります。 +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=リュック内のインベントリを2列使用して電力を蓄積します。 +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=2x2で圧縮できるアイテムを自動で圧縮します。 +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=リュック内で手動でクラフトできるようになります。 +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=スニークで右クリックしたチェストにアイテムを収納します。 +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=死亡時や奈落に落ちてもリュックが消滅しなくなります。 +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=スタックアップグレードを複数使用した時の計算方法を加算から乗算にします +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=リュック内の食料を自動で食べます。 +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=出し入れするアイテムにフィルタをかけます。 +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=リュックの中にリュックを入れることができます。 +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=リュックでジュークボックスの機能を楽しめます。 +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=周囲のアイテムを引き寄せてリュックに入れます。 +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=Captures passive mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=拾ったアイテムが直接リュックに入ります。 +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=タンク機能と併用し、液体を出し入れします。 +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=消費したアイテムをリュックから補充します。 +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=スニークで右クリックしたチェストから、アイテムをリュックに回収します。 +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=1スロットあたりのスタック数を%s倍にします +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=1スロットあたりのスタック数を%s倍にします +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=1スロットあたりのスタック数を%s倍にします +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=1スロットあたりのスタック数を%s倍にします +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=1スロットあたりのスタック数を%s倍にします +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=リュック内のインベントリを2列使用して液体を蓄積します。 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=ブロックを破壊するとき、適切なツールに自動で切り替わります。 +item.retro_sophisticated_backpacks.void_upgrade.tooltip=フィルタで指定したアイテムを消滅させます。 +retro_sophisticated_backpacks.gui.backpack_settings=リュックの設定 +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=リュックの設定 +retro_sophisticated_backpacks.gui.crafting_settings=作業台 +retro_sophisticated_backpacks.gui.inception_settings=入れ子 +retro_sophisticated_backpacks.gui.item_display_settings=ラベル表示 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=ラベル表示設定 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=リュックのラベルとして表示するアイテムを指定します。 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=リュックのラベルとして表示するアイテムを指定します。\n左クリック=スロットを選択\n右クリック=選択を解除 +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Do Not Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_no_hand=手に持った液体容器から回収しない +retro_sophisticated_backpacks.gui.pump_no_world=周囲の液体は回収しない +retro_sophisticated_backpacks.gui.pump_output=液体を取り出す +retro_sophisticated_backpacks.gui.search=Click to search +retro_sophisticated_backpacks.gui.search_detail=@ prefix to search by mod name +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=他のプレイヤは開けない +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=装備した背中のリュックを他のプレイヤが開けない +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=他のプレイヤも開ける +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=装備した背中のリュックを他のプレイヤが開ける +retro_sophisticated_backpacks.gui.settings_button.context_backpack=個別に適用 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=リュックごとに設定 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=プレイヤ単位の設定を引き継ぐか、個別に設定したものが適用されます。 +retro_sophisticated_backpacks.gui.settings_button.context_player=全てに適用 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=プレイヤ単位で設定 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=個別に上書き設定がない限り、プレイヤが保有する全てのリュックに適用されます。 +retro_sophisticated_backpacks.gui.settings_button.display_side_front=正面に表示 +retro_sophisticated_backpacks.gui.settings_button.display_side_left=左側に表示 +retro_sophisticated_backpacks.gui.settings_button.display_side_right=右側に表示 +retro_sophisticated_backpacks.gui.settings_button.item_display_color=選択スロットの色 +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=左クリック=次の色へ\n右クリック=前の色へ +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Keep Search Phrase: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=Backpack / Storage gui clears the search phrase when closed and shows all unfiltered item when open again +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep Search Phrase: ON +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=Backpack / Storage gui keeps the search phrase and prefills it / filters by it when open again +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=開いたタブを記憶: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=リュックのGUIを閉じたときに、全ての追加機能タブを閉じ、次に開いたときにはどのタブも開きません。 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=開いたタブを記憶: ON +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=リュックのGUIを閉じたときに、最後に開いていた追加機能タブを記憶し、次回開いたときにそのタブを開きます。 +retro_sophisticated_backpacks.gui.settings_button.rotate=回転 +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=左クリック=時計回り\n右クリック=反時計回り +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=インベントリ優先 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=リュックやインベントリからSHIFTキーを押すと、インベントリやリュックに優先的に入れ、その後に追加機能タブにアイテムを収納します。 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=拡張機能のタブ優先 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=リュックやインベントリからSHIFTキーを押すと、開いている追加機能タブに優先的に入れ、その後にインベントリやリュックにアイテムを収納します。 +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=That mob is blocked from capture +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=Bosses cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=Captured %s +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=Hostile mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=That mob cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=Mobs with inventories cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=Backpack has no Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=Only the owner can capture that mob +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=Only one Mob Catcher Upgrade is allowed per backpack +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=Mobs with passengers or vehicles cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=Players cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there +retro_sophisticated_backpacks.gui.status.mob_catcher_released=Released %s +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slots, more than this upgrade allows (%s) +retro_sophisticated_backpacks.gui.tooltip.stack_count=個数: %s + +# Fallbacks for keys used by current code +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side +retro_sophisticated_backpacks.gui.ore_dict_input_help.pro_tip=Protip: You can hover item onto entry\n to check if the entry is applicable,\nor hover on textfield to see available entries. +retro_sophisticated_backpacks.gui.ore_dict_list_entries=Available ore dict: +retro_sophisticated_backpacks.gui.none=(None) +retro_sophisticated_backpacks.gui.craft_into_backpack=Shift Click Result Into Backpack +retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift Click Result Into Player's Inventory +retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank +retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang index b16e124..360006b 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang @@ -6,25 +6,25 @@ tile.retro_sophisticated_backpacks.backpack_diamond.name=다이아몬드 가방 tile.retro_sophisticated_backpacks.backpack_obsidian.name=흑요석 가방 # Items -item.retro_sophisticated_backpacks.upgrade_base.name=업그레이드 기반 -item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=묶음 업그레이드 기본 단계 -item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=묶음 업그레이드 1단계 -item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=묶음 업그레이드 2단계 -item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=묶음 업그레이드 3단계 -item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=묶음 업그레이드 4단계 +item.retro_sophisticated_backpacks.upgrade_base.name=기능 틀 +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=0.5단계 쌓기 기능 +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=1단계 쌓기 기능 +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=2단계 쌓기 기능 +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=3단계 쌓기 기능 +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=4단계 쌓기 기능 item.retro_sophisticated_backpacks.exponential_stack_upgrade.name=지수 묶음 업그레이드 -item.retro_sophisticated_backpacks.crafting_upgrade.name=조합 업그레이드 -item.retro_sophisticated_backpacks.inception_upgrade.name=인셉션 업그레이드 -item.retro_sophisticated_backpacks.pickup_upgrade.name=아이템 줍기 업그레이드 -item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=고급 아이템 줍기 업그레이드 -item.retro_sophisticated_backpacks.feeding_upgrade.name=음식 공급 업그레이드 -item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=고급 음식 공급 업그레이드 -item.retro_sophisticated_backpacks.deposit_upgrade.name=보관 업그레이드 -item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=고급 보관 업그레이드 -item.retro_sophisticated_backpacks.restock_upgrade.name=재보급 업그레이드 -item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=고급 재보급 업그레이드 -item.retro_sophisticated_backpacks.filter_upgrade.name=필터 업그레이드 -item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=고급 필터 업그레이드 +item.retro_sophisticated_backpacks.crafting_upgrade.name=제작대 기능 +item.retro_sophisticated_backpacks.inception_upgrade.name=배낭 보관 기능 +item.retro_sophisticated_backpacks.pickup_upgrade.name=줍기 기능 +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=고급 줍기 기능 +item.retro_sophisticated_backpacks.feeding_upgrade.name=식사 기능 +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=고급 식사 기능 +item.retro_sophisticated_backpacks.deposit_upgrade.name=꺼내기 기능 +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=고급 꺼내기 기능 +item.retro_sophisticated_backpacks.restock_upgrade.name=넣기 기능 +item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=고급 넣기 기능 +item.retro_sophisticated_backpacks.filter_upgrade.name=필터 기능 +item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=고급 필터 기능 # Creative Tabs itemGroup.retro_sophisticated_backpacks.creative_tab=레트로 복잡한 배낭 @@ -36,64 +36,48 @@ retro_sophisticated_backpacks.key.category=레트로 복잡한 배낭 # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=인벤토리 크기: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=업그레이드 슬롯: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s -retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s -retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=쌓을 수 있는 아이템 최대 개수: §fx%s +retro_sophisticated_backpacks.tooltip.backpack.fluid=%s 밀리버킷만큼의 %s +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=탱크가 비어있음 retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy -retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades -retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory -retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents -retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents -retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=강화 +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=인벤토리 +retro_sophisticated_backpacks.tooltip.backpack.empty=배낭에 아이템이나 강화가 없습니다 +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=<%s>을(를) 누르면 배낭을 확인할 수 있습니다 +retro_sophisticated_backpacks.tooltip.backpack.shift=왼쪽 Shift -retro_sophisticated_backpacks.tooltip.upgrade_base=아무 기능도 없습니다! 업그레이드 슬롯에 마음껏 넣으세요! -retro_sophisticated_backpacks.tooltip.stack_upgrade=아이템 스택 크기를 %d배로 늘립니다 -retro_sophisticated_backpacks.tooltip.exponential_stack_upgrade=묶음 배율이 더하기가 아닌 곱하기로 중첩됩니다 -retro_sophisticated_backpacks.tooltip.crafting_upgrade=가방 측면에 추가 조합 그리드를 추가합니다 -retro_sophisticated_backpacks.tooltip.inception_upgrade=가방 안에 가방을 보관할 수 있게 합니다 -retro_sophisticated_backpacks.tooltip.pickup_upgrade=가방이 아이템을 주울 수 있게 합니다 -retro_sophisticated_backpacks.tooltip.advanced_pickup_upgrade=가방이 더 많은 설정으로 아이템을 주울 수 있게 합니다 -retro_sophisticated_backpacks.tooltip.feeding_upgrade=가방이 플레이어에게 자동으로 음식을 공급합니다 -retro_sophisticated_backpacks.tooltip.advanced_feeding_upgrade=가방이 더 자세한 설정에 맞춰 플레이어에게 자동으로 음식을 공급합니다 -retro_sophisticated_backpacks.tooltip.deposit_upgrade=웅크린 채 우클릭한 인벤토리로 가방의 아이템을 보관합니다 -retro_sophisticated_backpacks.tooltip.advanced_deposit_upgrade=더 많은 설정으로, 웅크린 채 우클릭한 인벤토리로 가방의 아이템을 보관합니다 -retro_sophisticated_backpacks.tooltip.restock_upgrade=웅크린 채 우클릭한 인벤토리에서 가방으로 아이템을 재보급합니다 -retro_sophisticated_backpacks.tooltip.advanced_restock_upgrade=더 많은 설정으로, 웅크린 채 우클릭한 인벤토리에서 가방으로 아이템을 재보급합니다 -retro_sophisticated_backpacks.tooltip.filter_upgrade=월드에 설치 시 넣는 아이템을 필터링합니다 -retro_sophisticated_backpacks.tooltip.advanced_filter_upgrade=더 많은 설정으로, 월드에 설치 시 넣는 아이템을 필터링합니다 -retro_sophisticated_backpacks.tooltip.shift_to_reveal= # Gui Elements retro_sophisticated_backpacks.container.backpack=가방 -retro_sophisticated_backpacks.gui.pickup_settings=아이템 줍기 -retro_sophisticated_backpacks.gui.advanced_pickup_settings=고급 아이템 줍기 +retro_sophisticated_backpacks.gui.pickup_settings=획득 +retro_sophisticated_backpacks.gui.advanced_pickup_settings=고급 획득 -retro_sophisticated_backpacks.gui.feeding_settings=음식 공급 -retro_sophisticated_backpacks.gui.advanced_feeding_settings=고급 음식 공급 +retro_sophisticated_backpacks.gui.feeding_settings=식사 +retro_sophisticated_backpacks.gui.advanced_feeding_settings=고급 식사 -retro_sophisticated_backpacks.gui.deposit_settings=보관 -retro_sophisticated_backpacks.gui.advanced_deposit_settings=고급 보관 +retro_sophisticated_backpacks.gui.deposit_settings=꺼내기 +retro_sophisticated_backpacks.gui.advanced_deposit_settings=고급 꺼내기 -retro_sophisticated_backpacks.gui.restock_settings=재보급 -retro_sophisticated_backpacks.gui.advanced_restock_settings=고급 재보급 +retro_sophisticated_backpacks.gui.restock_settings=넣기 +retro_sophisticated_backpacks.gui.advanced_restock_settings=고급 넣기 retro_sophisticated_backpacks.gui.filter_settings=필터 retro_sophisticated_backpacks.gui.advanced_filter_settings=고급 필터 @@ -101,30 +85,30 @@ retro_sophisticated_backpacks.gui.advanced_filter_settings=고급 필터 retro_sophisticated_backpacks.gui.crafting_settings=제작 retro_sophisticated_backpacks.gui.memory_settings=기억 -retro_sophisticated_backpacks.gui.sorting_settings=정렬 안 함 +retro_sophisticated_backpacks.gui.sorting_settings=미정렬 retro_sophisticated_backpacks.gui.memory_settings.tooltip=기억 슬롯 설정 -retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=내용을 기억하고 일치하는 스택만 허용하는 슬롯을 선택합니다\n탭을 열어 슬롯 설정을 수정합니다 -retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=내용을 기억하고 일치하는 스택만 허용하는 슬롯을 선택합니다\n전부 선택 / 전부 선택 해제 = 버튼\n슬롯 선택 = 왼쪽 클릭/드래그\n슬롯 선택 해제 = 오른쪽 클릭/드래그 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip=정렬 제외 슬롯 설정 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=정렬에서 제외할 슬롯을 선택합니다\n탭을 열어 슬롯 설정을 수정합니다 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=정렬에서 제외할 슬롯을 선택합니다\n전부 선택 / 전부 선택 해제 = 버튼\n슬롯 선택 = 왼쪽 클릭/드래그\n슬롯 선택 해제 = 오른쪽 클릭/드래그 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=내용을 기억하고 일치하는 스택만 허용하는 슬롯을 선택할 수 있습니다\n탭을 열어 슬롯 설정을 수정합니다 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=내용을 기억하고 일치하는 스택만 허용하는 슬롯을 선택할 수 있습니다\n전부 선택 / 전부 선택 해제 = 버튼\n슬롯 선택 = 마우스 왼쪽 버튼/드래그\n슬롯 선택 해제 = 마우스 오른쪽 버튼/드래 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=미정렬 슬롯 설정 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=정렬하지 않을 슬롯을 선택할 수 있습니다\n창을 열어 슬롯을 수정할 수 있습니다 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=정렬하지 않을 슬롯을 선택할 수 있습니다\n전부 선택 / 전부 선택 해제 = 버튼\n슬롯 선택 = 왼쪽 버튼/드래그\n슬롯 선택 해제 = 오른쪽 버튼/드래그 # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=개수: %s / %s retro_sophisticated_backpacks.gui.not_in_effect=효과 없음 -retro_sophisticated_backpacks.gui.whitelist=허용 목록 -retro_sophisticated_backpacks.gui.blacklist=금지 목록 +retro_sophisticated_backpacks.gui.whitelist=허용 +retro_sophisticated_backpacks.gui.blacklist=차단 -retro_sophisticated_backpacks.gui.match_item=아이템 기준 -retro_sophisticated_backpacks.gui.match_mod_id=모드 ID 기준 +retro_sophisticated_backpacks.gui.match_item=아이템 일치 +retro_sophisticated_backpacks.gui.match_mod_id=모드 일치 retro_sophisticated_backpacks.gui.match_ore_dict=광물 사전 기준 -retro_sophisticated_backpacks.gui.match_durability=내구성 일치 -retro_sophisticated_backpacks.gui.ignore_durability=내구성 무시 +retro_sophisticated_backpacks.gui.match_durability=내구도 일치 +retro_sophisticated_backpacks.gui.ignore_durability=내구도 무시 -retro_sophisticated_backpacks.gui.match_nbt=NBT 데이터 일치 -retro_sophisticated_backpacks.gui.ignore_nbt=NBT 데이터 무시 +retro_sophisticated_backpacks.gui.match_nbt=NBT 일치 +retro_sophisticated_backpacks.gui.ignore_nbt=NBT 무시 retro_sophisticated_backpacks.gui.add_ore_dict_entry=광물 사전 추가 retro_sophisticated_backpacks.gui.remove_ore_dict_entry=광물 사전 제거 @@ -133,135 +117,244 @@ retro_sophisticated_backpacks.gui.ore_dict_input_help.pro_tip=꿀팁: 목록 위 retro_sophisticated_backpacks.gui.ore_dict_list_entries=사용 가능한 광물 사전: retro_sophisticated_backpacks.gui.none=(없음) -retro_sophisticated_backpacks.gui.complete_hunger=음식의 허기 포인트를 전혀 낭비하지\n않을 만큼 배고플 때만 음식을 공급합니다 -retro_sophisticated_backpacks.gui.half_hunger=음식의 허기 포인트를 최대 절반만\n낭비할 만큼 배고플 때만 음식을 공급합니다 -retro_sophisticated_backpacks.gui.immediate_hunger=플레이어가 조금이라도 배고프면 즉시 음식을\n공급합니다. 음식의 허기 포인트를 꽤 낭비합니다 +retro_sophisticated_backpacks.gui.complete_hunger=플레이어가 배고플 때만 음식을 줍니다\n음식이 채우는 배고픔을 전혀 낭비하지 않습니다 +retro_sophisticated_backpacks.gui.half_hunger=플레이어가 충분히 배고플 때만 음식을 줍니다\n많아야 음식이 채우는 배고픔의 반 칸 정도만 낭비합니다 +retro_sophisticated_backpacks.gui.immediate_hunger=플레이어가 배가 고파지면 바로 음식을 줍니다\n음식이 채우는 배고픔을 꽤 많이 낭비합니다 -retro_sophisticated_backpacks.gui.ignore_health=체력을 고려하지 않음\n플레이어의 체력을 무시하고 허기 설정에 따라 음식을 공급합니다 -retro_sophisticated_backpacks.gui.consider_health=피해를 입으면 즉시 음식 공급\n플레이어의 체력이 최대가 아닐 경우 허기 설정을 무시합니다 +retro_sophisticated_backpacks.gui.ignore_health=체력에 영향받지 않습니다\n플레이어의 체력을 무시하고 배고픔 설정에 따라 음식을 줍니다 +retro_sophisticated_backpacks.gui.consider_health=다쳤을 때 즉시 플레이어에게 음식을 줍니다\n플레이어가 최대 체력이 아닐 때 배고픔 설정을 무시하고 바로 음식을 줍니다 -retro_sophisticated_backpacks.gui.input_output=입력 및 출력 -retro_sophisticated_backpacks.gui.input=입력만 -retro_sophisticated_backpacks.gui.output=출력만 +retro_sophisticated_backpacks.gui.input_output=입력 & 출력 +retro_sophisticated_backpacks.gui.input=입력 +retro_sophisticated_backpacks.gui.output=출력 -retro_sophisticated_backpacks.gui.sort_inventory=가방 인벤토리 정렬 -retro_sophisticated_backpacks.gui.sort_by_name=이름순 정렬 -retro_sophisticated_backpacks.gui.sort_by_mod_id=모드 ID순 정렬 -retro_sophisticated_backpacks.gui.sort_by_count=개수순 정렬 -retro_sophisticated_backpacks.gui.sort_by_ore_dict=광물 사전순 정렬 +retro_sophisticated_backpacks.gui.sort_inventory=배낭 정렬 +retro_sophisticated_backpacks.gui.sort_by_name=이름순 +retro_sophisticated_backpacks.gui.sort_by_mod_id=By Mod +retro_sophisticated_backpacks.gui.sort_by_count=개수순 +retro_sophisticated_backpacks.gui.sort_by_ore_dict=태그순 retro_sophisticated_backpacks.gui.craft_into_backpack=결과물을 배낭으로 한꺼번에 옮기기 retro_sophisticated_backpacks.gui.craft_into_player_inventory=결과물을 플레이어의 인벤토리로 한꺼번에 옮기기 -retro_sophisticated_backpacks.gui.transfer_to_player_inv=모든 아이템을 플레이어 인벤토리로 옮기기 -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=일치하는 아이템을 플레이어 인벤토리로 옮기기 -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift 키를 눌러 모두 옮기기 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=모든 아이템을 가방 인벤토리로 옮기기 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=일치하는 아이템을 가방 인벤토리로 옮기기 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift 키를 눌러 모두 옮기기 +retro_sophisticated_backpacks.gui.transfer_to_player_inv=Transfer to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Transfer Matching to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift To Transfer All +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Transfer to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transfer Matching to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift To Transfer All retro_sophisticated_backpacks.gui.settings=설정 retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=배낭으로 돌아가기 retro_sophisticated_backpacks.gui.configuration_tab=구성 탭 retro_sophisticated_backpacks.gui.memorized_slot=기억하는 슬롯 -retro_sophisticated_backpacks.gui.memorize_all=모든 슬롯 기억하기 -retro_sophisticated_backpacks.gui.unmemorize_all=모든 슬롯 잊기 +retro_sophisticated_backpacks.gui.memorize_all=전부 선택 +retro_sophisticated_backpacks.gui.unmemorize_all=전부 선택 해제 retro_sophisticated_backpacks.gui.no_sorting_slot=정렬 안 하는 슬롯 -retro_sophisticated_backpacks.gui.lock_all_sort=모든 슬롯을 정렬 안 하도록 선택 -retro_sophisticated_backpacks.gui.unlock_all_sort=모든 슬롯을 정렬하도록 선택 - -item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade -item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade -item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade -item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade -item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade -item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade -item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade -item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade -retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations -retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations -retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations -retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations -retro_sophisticated_backpacks.gui.magnet_settings=Magnet -retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet -retro_sophisticated_backpacks.gui.void_settings=Void -retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void -retro_sophisticated_backpacks.gui.refill_settings=Refill -retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill -retro_sophisticated_backpacks.gui.compacting_settings=Compa... -retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting +retro_sophisticated_backpacks.gui.lock_all_sort=전부 선택 +retro_sophisticated_backpacks.gui.unlock_all_sort=전부 선택 해제 + +item.retro_sophisticated_backpacks.magnet_upgrade.name=자석 기능 +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=고급 자석 기능 +item.retro_sophisticated_backpacks.void_upgrade.name=제거 기능 +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=고급 제거 기능 +item.retro_sophisticated_backpacks.refill_upgrade.name=보충 기능 +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=고급 보충 기능 +item.retro_sophisticated_backpacks.compacting_upgrade.name=압축 기능 +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=고급 압축 기능 +retro_sophisticated_backpacks.gui.magnet_settings=자석 +retro_sophisticated_backpacks.gui.advanced_magnet_settings=고급 자석 +retro_sophisticated_backpacks.gui.void_settings=제거 +retro_sophisticated_backpacks.gui.advanced_void_settings=고급 제거 +retro_sophisticated_backpacks.gui.refill_settings=보충 +retro_sophisticated_backpacks.gui.advanced_refill_settings=고급 보충 +retro_sophisticated_backpacks.gui.compacting_settings=압축 +retro_sophisticated_backpacks.gui.advanced_compacting_settings=고급 압축 retro_sophisticated_backpacks.gui.void_always=Void Always retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow -retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes -retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes -retro_sophisticated_backpacks.gui.refill_target_any=Any Slot -retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand -retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI -retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI -item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade -item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade -item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade -item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade -item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade -item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade -item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade -item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade -item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support -retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack -retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls -retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack -retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +retro_sophisticated_backpacks.gui.refill_target_any=모든 슬롯 +retro_sophisticated_backpacks.gui.refill_target_main_hand=주로 사용하는 손 +retro_sophisticated_backpacks.gui.refill_target_off_hand=다른 손 +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=단축 바 슬롯 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=단축 바 슬롯 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=단축 바 슬롯 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=단축 바 슬롯 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=단축 바 슬롯 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=단축 바 슬롯 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=단축 바 슬롯 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=단축 바 슬롯 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=단축 바 슬롯 9 +retro_sophisticated_backpacks.gui.allow=허용 +retro_sophisticated_backpacks.gui.block=차단 +retro_sophisticated_backpacks.gui.match_backpack_contents=배낭 아이템과 일치 +retro_sophisticated_backpacks.gui.pickup_items=아이템 자동 줍기 +retro_sophisticated_backpacks.gui.do_not_pickup_items=아이템 자동 줍기 비활성화 +retro_sophisticated_backpacks.gui.compact_only_uncraftable=되돌릴 수 있는 아이템만 압축 +retro_sophisticated_backpacks.gui.compact_anything=전부 압축 +retro_sophisticated_backpacks.gui.only_automatic=다른 강화/장치에서만 작동합니다 +retro_sophisticated_backpacks.gui.works_in_gui=GUI에서도 작동합니다 +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=Allows single slot to be filled with the item\nand voids anything that overflows +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=Allows whole storage to be filled with the item\n and voids anything that overflows +retro_sophisticated_backpacks.gui.refill_target_tooltip=%s 보충 +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=스크롤하여 대상 슬롯을 변경합니다. +item.retro_sophisticated_backpacks.everlasting_upgrade.name=영구 기능 +item.retro_sophisticated_backpacks.jukebox_upgrade.name=주크박스 기능 +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=고급 주크박스 기능 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=도구 전환 기능 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=고급 도구 전환 기능 +item.retro_sophisticated_backpacks.tank_upgrade.name=탱크 기능 +item.retro_sophisticated_backpacks.pump_upgrade.name=펌프 기능 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=고급 펌프 기능 +item.retro_sophisticated_backpacks.battery_upgrade.name=배터리 기능 +item.retro_sophisticated_backpacks.anvil_upgrade.name=모루 기능 retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting -retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.jukebox_settings=주크박스 retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper -retro_sophisticated_backpacks.gui.tank_settings=Tank -retro_sophisticated_backpacks.gui.pump_settings=Pump -retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump -retro_sophisticated_backpacks.gui.battery_settings=Battery -retro_sophisticated_backpacks.gui.anvil_settings=Anvil -retro_sophisticated_backpacks.gui.pump_input=Pump In -retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers -retro_sophisticated_backpacks.gui.pump_world=World -retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.tool_swapper_settings=도구 전환 +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=도구 전환 +retro_sophisticated_backpacks.gui.tank_settings=탱크 +retro_sophisticated_backpacks.gui.pump_settings=펌프 +retro_sophisticated_backpacks.gui.advanced_pump_settings=고급 펌프 +retro_sophisticated_backpacks.gui.battery_settings=배터리 +retro_sophisticated_backpacks.gui.anvil_settings=모루 +retro_sophisticated_backpacks.gui.pump_input=입력 +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_world=월드와 상호작용 +retro_sophisticated_backpacks.gui.pump_hand=손의 액체 저장소와 상호작용 retro_sophisticated_backpacks.gui.anvil_no_result=No Result retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage -retro_sophisticated_backpacks.gui.jukebox_play=Play -retro_sophisticated_backpacks.gui.jukebox_stop=Stop -retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc -retro_sophisticated_backpacks.gui.jukebox_next=Next Disc -retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_play=재생 +retro_sophisticated_backpacks.gui.jukebox_stop=정지 +retro_sophisticated_backpacks.gui.jukebox_previous=Previous +retro_sophisticated_backpacks.gui.jukebox_next=Next +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Disabled +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle Enabled retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One -retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Disabled retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=아이템을 압축할 수 있게 됩니다.\n2x2와 3x3 제작법을 사용할 수 있고, 필터 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=저장소에다 웅크리고 우클릭하면 배낭의 아이템을 저장소로 꺼낼 수 있게 됩니다.\n필터 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=플레이어에게 배낭 속 음식을 먹일 수 있게 됩니다.\n설정 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=배낭에 들어가거나 나가는 아이템을 필터링할 수 있게 됩니다.\n필터 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=더 많은 음반과 재생 옵션을 지원하는 휴대용 주크박스 +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=배낭이 넓은 범위 내에 있는 아이템을 끌어당길 수 있게 됩니다.\n필터 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=Captures passive and hostile mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=배낭이 아이템을 주울 수 있게 됩니다.\n필터 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=탱크 기능이 된 배낭과 인접한 블록 사이에 액체를 넣고 뺄 수 있습니다.\n손에 든 액체 용기와 세계에 있는 액체 블록에서 작동합니다.\n어떤 액체를 받을지 지정할 수 있습니다. +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=선택한 아이템을 플레이어의 보관함으로 보충할 수 있게 됩니다.\n더욱 정밀한 대상 슬롯을 선택 가능합니다.\n또한 배낭에서 블록을 마우스 휠 클릭으로 선택할 수 있습니다. +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=저장소에다 웅크리고 우클릭하면 배낭에 저장소의 아이템을 넣을 수 있게 됩니다.\n필터 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=왼쪽 클릭 시 손에 든 아이템을 블록/엔티티에 효과적인 아이템으로 자동 교체합니다\n필터 옵션과 추가 상호작용을 지원합니다 +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=필터로 선택한 아이템을 제거할 수 있게 됩니다.\n필터 옵션이 추가됩니다. +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=기능 탭의 모루입니다. +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=배낭의 일부가 에너지 저장소로 변경됩니다. +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=아이템을 압축할 수 있게 됩니다.\n2x2 제작법만 사용할 수 있습니다. +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=기능 창에서 제작대를 사용할 수 있게 됩니다. +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=저장소에다 웅크리고 우클릭하면 배낭의 아이템을 저장소로 꺼낼 수 있게 됩니다. +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=배낭이 사라지지 않게 됩니다.\n아이템이 떨어져 있어도 사라지지 않고, 세계 밖으로 떨어지지 않게 됩니다. +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=묶음 배율이 더하기가 아닌 곱하기로 중첩됩니다 +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=플레이어에게 배낭 속 음식을 먹일 수 있게 됩니다. +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=배낭에 들어가거나 나가는 아이템을 필터링할 수 있게 됩니다. +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=배낭에 배낭을 넣을 수 있게 됩니다. +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=휴대용 주크박스 +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=배낭이 범위 내에 있는 아이템을 끌어당길 수 있게 됩니다. +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=Captures passive mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=배낭이 아이템을 주울 수 있게 됩니다. +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=탱크 기능이 된 배낭과 인접한 블록 사이에 액체를 넣고 뺄 수 있습니다. +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=선택한 아이템을 플레이어의 보관함으로 보충할 수 있게 됩니다. +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=저장소에다 웅크리고 우클릭하면 배낭에 저장소의 아이템을 넣을 수 있게 됩니다. +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=한 슬롯에 들어갈 수 있는 스택 수가 %s배 증가합니다 +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=한 슬롯에 들어갈 수 있는 스택 수가 %s배 증가합니다 +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=한 슬롯에 들어갈 수 있는 스택 수가 %s배 증가합니다 +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=한 슬롯에 들어갈 수 있는 스택 수가 %s배 증가합니다 +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=한 슬롯에 들어갈 수 있는 스택 수가 %s배 증가합니다 +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=배낭의 일부가 액체 저장소로 변경됩니다. +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=플레이어의 손에 있는 도구를 해당 블록/개체에 맞는 도구로 전환합니다. +item.retro_sophisticated_backpacks.void_upgrade.tooltip=필터로 선택한 아이템을 제거할 수 있게 됩니다. +retro_sophisticated_backpacks.gui.backpack_settings=배낭 설정 +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=배낭 설정 +retro_sophisticated_backpacks.gui.inception_settings=넣기 +retro_sophisticated_backpacks.gui.item_display_settings=Item Disp. +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Item Display Settings +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Allows selecting a slot that will be used to show its item on top of storage +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Allows selecting a slot that will be used to show its item on top of storage\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Do Not Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_no_hand=손의 액체 저장소와 상호작용 비활성화 +retro_sophisticated_backpacks.gui.pump_no_world=월드와 상호작용 비활성화 +retro_sophisticated_backpacks.gui.pump_output=출력 +retro_sophisticated_backpacks.gui.search=Click to search +retro_sophisticated_backpacks.gui.search_detail=@ prefix to search by mod name +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=다른 플레이어가 열기: 차단 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=배낭을 착용한 경우에도 다른 플레이어가 우클릭으로 배낭을 열 수 없습니다. +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=다른 플레이어가 열기: 허용 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=배낭을 보이게 착용했을 때, 다른 플레이어가 이 플레이어의 등을 우클릭해서 배낭을 열 수 있습니다. +retro_sophisticated_backpacks.gui.settings_button.context_backpack=배낭 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=이 배낭의 설정 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=이 배낭을 재정의합니다. +retro_sophisticated_backpacks.gui.settings_button.context_player=플레이어 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=플레이어 설정 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=재정의되지 않는 한 모든 배낭에 적용합니다 +retro_sophisticated_backpacks.gui.settings_button.display_side_front=Show on Front +retro_sophisticated_backpacks.gui.settings_button.display_side_left=Show on Left side +retro_sophisticated_backpacks.gui.settings_button.display_side_right=Show on Right side +retro_sophisticated_backpacks.gui.settings_button.item_display_color=선택 색 +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=다음 = 왼쪽 버튼\n이전 = 오른쪽 버튼 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Keep Search Phrase: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=Backpack / Storage gui clears the search phrase when closed and shows all unfiltered item when open again +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep Search Phrase: ON +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=Backpack / Storage gui keeps the search phrase and prefills it / filters by it when open again +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=창 유지: 꺼짐 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=GUI가 닫히고 열리면 모든 창이 닫힙니다 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=창 유지: 켜짐 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=마지막으로 연 강화 창이 GUI가 닫히고 열려도 유지됩니다 +retro_sophisticated_backpacks.gui.settings_button.rotate=Rotate +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Clockwise = Left Click\nCounter-Clockwise = Right Click +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift 클릭이 인벤토리 우선 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=인벤토리/배낭에서 Shift 클릭을 하면 먼저 아이템을 인벤토리/배낭에 넣은 다음 열린 창에 넣습니다 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift 클릭이 열린 창 우선 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=인벤토리/배낭에서 Shift 클릭을 하면 먼저 아이템을 열린 창에 넣은 다음 인벤토리/배낭에 넣습니다 +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=That mob is blocked from capture +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=Bosses cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=Captured %s +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=Hostile mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=That mob cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=Mobs with inventories cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=Backpack has no Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=Only the owner can capture that mob +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=Only one Mob Catcher Upgrade is allowed per backpack +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=Mobs with passengers or vehicles cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=Players cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there +retro_sophisticated_backpacks.gui.status.mob_catcher_released=Released %s +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slots, more than this upgrade allows (%s) +retro_sophisticated_backpacks.gui.tooltip.stack_count=개수: %s + +# Fallbacks for keys used by current code +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side +retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank +retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang index 51c206b..3af57c8 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang @@ -6,18 +6,19 @@ tile.retro_sophisticated_backpacks.backpack_diamond.name=Diamentowy plecak tile.retro_sophisticated_backpacks.backpack_obsidian.name=Obsydianowy plecak # Przedmioty -item.retro_sophisticated_backpacks.upgrade_base.name=Podstawa ulepszeń -item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=Podstawowe ulepszenie stosu -item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=Ulepszenie stosu poziomu 1 -item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=Ulepszenie stosu poziomu 2 -item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=Ulepszenie stosu poziomu 3 -item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=Ulepszenie stosu poziomu 4 -item.retro_sophisticated_backpacks.crafting_upgrade.name=Ulepszenie rzemieślnicze -item.retro_sophisticated_backpacks.inception_upgrade.name=Ulepszenie incepcyjne -item.retro_sophisticated_backpacks.pickup_upgrade.name=Ulepszenie zbierające -item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=Zaawansowane ulepszenie zbierające -item.retro_sophisticated_backpacks.feeding_upgrade.name=Ulepszenie karmiące -item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=Zaawansoawane ulepszenie karmiące +item.retro_sophisticated_backpacks.upgrade_base.name=Moduł ulepszenia +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=Ulepszenie stosów bazowe +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=Ulepszenie stosów poziom 1 +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=Ulepszenie stosów poziom 2 +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=Ulepszenie stosów poziom 3 +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=Ulepszenie stosów poziom 4 +item.retro_sophisticated_backpacks.exponential_stack_upgrade.name=Ulepszenie stosów wykładnicze +item.retro_sophisticated_backpacks.crafting_upgrade.name=Ulepszenie wytwarzania +item.retro_sophisticated_backpacks.inception_upgrade.name=Ulepszenie incepcji +item.retro_sophisticated_backpacks.pickup_upgrade.name=Ulepszenie podnoszenia +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=Zaawansowane ulepszenie podnoszenia +item.retro_sophisticated_backpacks.feeding_upgrade.name=Ulepszenie karmienia +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=Zaawansowane ulepszenie Karmienia # Zakładki trybu kreatywnego itemGroup.retro_sophisticated_backpacks.creative_tab=Retro Sophisticated Backpack @@ -41,159 +42,302 @@ retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Co retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift -retro_sophisticated_backpacks.tooltip.upgrade_base=Nic nie robi! Możesz umieścić ją w miejscu na ulepszenia! -retro_sophisticated_backpacks.tooltip.stack_upgrade=Mnoży rozmiar stosu o %d -retro_sophisticated_backpacks.tooltip.crafting_upgrade=Dodaje siatkę rzemieślniczą z boku plecaka -retro_sophisticated_backpacks.tooltip.inception_upgrade=Pozwala umieścić plecaki w plecaku -retro_sophisticated_backpacks.tooltip.pickup_upgrade=Pozwala plecakom podnosić przedmioty -retro_sophisticated_backpacks.tooltip.advanced_pickup_upgrade=Pozwala plecakom podnosić przedmioty z większą ilością konfiguracji -retro_sophisticated_backpacks.tooltip.feeding_upgrade=Pozwala plecakom automatycznie karmić gracza -retro_sophisticated_backpacks.tooltip.advanced_feeding_upgrade=Pozwala plecakom automatycznie karmić z większą ilością konfiguracji -retro_sophisticated_backpacks.tooltip.shift_to_reveal= # Elementy interfejsu retro_sophisticated_backpacks.container.backpack=Plecak -retro_sophisticated_backpacks.gui.pickup_settings=Zbieranie +retro_sophisticated_backpacks.gui.pickup_settings=Pickup -retro_sophisticated_backpacks.gui.advanced_pickup_settings=Zaaw. zbieranie +retro_sophisticated_backpacks.gui.advanced_pickup_settings=Adv. Pickup -retro_sophisticated_backpacks.gui.feeding_settings=Karmienie +retro_sophisticated_backpacks.gui.feeding_settings=Feeding -retro_sophisticated_backpacks.gui.advanced_feeding_settings=Zaaw. karmienie +retro_sophisticated_backpacks.gui.advanced_feeding_settings=Adv. Feeding # Podpowiedzi interfejsu retro_sophisticated_backpacks.gui.not_in_effect=Wyłączone -retro_sophisticated_backpacks.gui.whitelist=Biała lista -retro_sophisticated_backpacks.gui.blacklist=Czarna lista +retro_sophisticated_backpacks.gui.whitelist=Allow +retro_sophisticated_backpacks.gui.blacklist=Block -retro_sophisticated_backpacks.gui.match_item=Po przedmiocie -retro_sophisticated_backpacks.gui.match_mod_id=Po Mod ID +retro_sophisticated_backpacks.gui.match_item=Match Item +retro_sophisticated_backpacks.gui.match_mod_id=Match Mod retro_sophisticated_backpacks.gui.match_ore_dict=Po Ore Dictionary -retro_sophisticated_backpacks.gui.consider_durability=Dopasuj zużycie -retro_sophisticated_backpacks.gui.ignore_durability=Ignoruj zużycie +retro_sophisticated_backpacks.gui.ignore_durability=Ignore Durability -retro_sophisticated_backpacks.gui.consider_nbt=Dopasuj NBT -retro_sophisticated_backpacks.gui.ignore_nbt=Ignoruj NBT +retro_sophisticated_backpacks.gui.ignore_nbt=Ignore NBT retro_sophisticated_backpacks.gui.add_ore_dict_entry=Dodaj Ore Dict. retro_sophisticated_backpacks.gui.remove_ore_dict_entry=Usuń Ore Dict. retro_sophisticated_backpacks.gui.ore_dict_input_help=Tu możesz wprowadzić ore dictionary, regex jest wspierany -retro_sophisticated_backpacks.gui.complete_hunger=Karm gracza tylko jeśli jest wystarczająco głodny\naby nie marnować żadnych punktów głodu jedzenia -retro_sophisticated_backpacks.gui.half_hunger=Karm gracza tylko jeśli jest wystarczająco głodny\naby marnować co najwyżej połowę punktów głodu jedzenia -retro_sophisticated_backpacks.gui.immediate_hunger=Karm gracza kiedy tylko stanie się głodny\nmarnuje sporo punktów głodu jedzenia - -retro_sophisticated_backpacks.gui.ignore_health=Nie bierz pod uwagę zdrowia\nIgnoruje punkty zdrowia gracza i karmi go tylko na podstawie ustawienia głodu -retro_sophisticated_backpacks.gui.consider_health=Karm gracza natychmiast po otrzymaniu obrażeń\nIgnoruje ustawienia głodu kiedy gracz nie ma wszystkich punktów zdrowia - -item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade -item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade -item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade -item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade -item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade -item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade -item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade -item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade -retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations -retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations -retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations -retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations +retro_sophisticated_backpacks.gui.complete_hunger=Only feed when player is hungry enough\nto not waste any hunger points of the food at all +retro_sophisticated_backpacks.gui.half_hunger=Only feed when player is hungry enough\nto only waste half hunger points of the food at most +retro_sophisticated_backpacks.gui.immediate_hunger=Feed as soon as player is tiny bit hungry\nwastes quite a few hunger points of the food + +retro_sophisticated_backpacks.gui.ignore_health=Do not consider health\nIgnores player's health and only feeds based on hunger setting +retro_sophisticated_backpacks.gui.consider_health=Feed player immediately when hurt\nIgnores hunger setting when player is not at max health + +item.retro_sophisticated_backpacks.magnet_upgrade.name=Ulepszenie magnesu +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Zaawansowane ulepszenie magnesu +item.retro_sophisticated_backpacks.void_upgrade.name=Ulepszenie pustki +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Zaawansowane ulepszenie pustki +item.retro_sophisticated_backpacks.refill_upgrade.name=Ulepszenie zapasu +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Zaawansowane ulepszenie zapasu +item.retro_sophisticated_backpacks.compacting_upgrade.name=Ulepszenie kompaktujące +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Zaawansowane ulepszenie kompaktujące retro_sophisticated_backpacks.gui.magnet_settings=Magnet retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet retro_sophisticated_backpacks.gui.void_settings=Void retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void -retro_sophisticated_backpacks.gui.refill_settings=Refill -retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill +retro_sophisticated_backpacks.gui.refill_settings=Zapas +retro_sophisticated_backpacks.gui.advanced_refill_settings=Zaaw. zapas retro_sophisticated_backpacks.gui.compacting_settings=Compa... retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting retro_sophisticated_backpacks.gui.void_always=Void Always retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow -retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes -retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes -retro_sophisticated_backpacks.gui.refill_target_any=Any Slot -retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand -retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI -retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI -item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade -item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade +retro_sophisticated_backpacks.gui.refill_target_any=Dowolny slot +retro_sophisticated_backpacks.gui.refill_target_main_hand=Główna ręka +retro_sophisticated_backpacks.gui.refill_target_off_hand=Druga ręka +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Slot paska narzędzi 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Slot paska narzędzi 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Slot paska narzędzi 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Slot paska narzędzi 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Slot paska narzędzi 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Slot paska narzędzi 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Slot paska narzędzi 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Slot paska narzędzi 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Slot paska narzędzi 9 +retro_sophisticated_backpacks.gui.allow=Allow +retro_sophisticated_backpacks.gui.block=Block +retro_sophisticated_backpacks.gui.match_backpack_contents=Dopasuj zawartość plecaka +retro_sophisticated_backpacks.gui.pickup_items=Pickup Items +retro_sophisticated_backpacks.gui.do_not_pickup_items=Do Not Pickup Items +retro_sophisticated_backpacks.gui.compact_only_uncraftable=Compact Only Uncraftable +retro_sophisticated_backpacks.gui.compact_anything=Compact Anything +retro_sophisticated_backpacks.gui.only_automatic=Only works with other upgrades/automation +retro_sophisticated_backpacks.gui.works_in_gui=Works in GUI as well +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=Allows single slot to be filled with the item\nand voids anything that overflows +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=Allows whole storage to be filled with the item\n and voids anything that overflows +retro_sophisticated_backpacks.gui.refill_target_tooltip=Uzupełnij %s +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=Przewiń, aby zmienić docelowy slot. +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Ulepszenie wieczne +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Ulepszenie szafy grającej item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade -item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade -item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade -item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade -item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade -item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade -item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support -retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack -retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls -retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack -retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Ulepszenie zamiany narzędzi +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Zaawansowane ulepszenie zamiany narzędzi +item.retro_sophisticated_backpacks.tank_upgrade.name=Ulepszenie zbiornika +item.retro_sophisticated_backpacks.pump_upgrade.name=Ulepszenie pompy +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Zaawansowane ulepszenie Pompy +item.retro_sophisticated_backpacks.battery_upgrade.name=Ulepszenie baterii +item.retro_sophisticated_backpacks.anvil_upgrade.name=Ulepszenie kowadła retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper +retro_sophisticated_backpacks.gui.tool_swapper_settings=Zamiana narzędzi +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Zamiana narzędzi retro_sophisticated_backpacks.gui.tank_settings=Tank retro_sophisticated_backpacks.gui.pump_settings=Pump retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump -retro_sophisticated_backpacks.gui.battery_settings=Battery -retro_sophisticated_backpacks.gui.anvil_settings=Anvil -retro_sophisticated_backpacks.gui.pump_input=Pump In -retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers -retro_sophisticated_backpacks.gui.pump_world=World -retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.battery_settings=Batt. +retro_sophisticated_backpacks.gui.anvil_settings=Kowadło +retro_sophisticated_backpacks.gui.pump_input=Input +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_world=Interact With World +retro_sophisticated_backpacks.gui.pump_hand=Interact With\nFluid Container in Hand retro_sophisticated_backpacks.gui.anvil_no_result=No Result retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage retro_sophisticated_backpacks.gui.jukebox_play=Play retro_sophisticated_backpacks.gui.jukebox_stop=Stop -retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc -retro_sophisticated_backpacks.gui.jukebox_next=Next Disc -retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_previous=Previous +retro_sophisticated_backpacks.gui.jukebox_next=Next +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Disabled +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle Enabled retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One -retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Disabled retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools -retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Back To Backpack +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Wróć Do plecaka retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Kompaktuje przedmioty\nzarówno crafting 2x2 jak i 3x3 z większą ilością opcji filtrujących +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=Zaawansowane ulepszenie depozytu +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Umieszcza przedmioty z plecaka do wybranego inwentarza skradając się i klikając prawy przycisk myszy, trzymając plecak w ręce\nma więcej opcji filtrowania +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=Karmi gracza jedzeniem z wyposażenia plecaka\nmożna wybrać kiedy karmi +item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=Zaawansowane ulepszenie filtra +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=Filtruje przedmioty przesłane do lub z plecaka\nma więcej opcjii filtrowania +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=Portable Jukebox with support for more music discs\nAlso more playback options +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=Przyciąga przedmioty do plecaka z daleka\nma wiecej opcjii filtrowania +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=Captures passive and hostile mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=Sprawia że plecak podnosi przedmioty\nma więcej filtrów +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=Pompuje płyny między ulepszeniem zbiornika a pobliskimi blokami\ndziała z pojemnikami na płyn trzymanymi w ręce i blokami płynów w świecie\nPozwala na wybranie które płyny są pompowane +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=Utrzymuje uzupełnianie stosu wybranych przedmiotów w ekwipunku gracza\nUmożliwia precyzyjniejszy wybór docelowego slotu\nUmożliwia również wybieranie bloków z plecaka za pomocą środkowego przycisku myszki +item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=Zaawansowane ulepszenie uzupełnienia +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=Przerzuca rzeczy z wyposażenia gracza do wyposażenia plecaka jeżeli trzymany w ręce przy prawym kliknięciu i skradając się\nma więcej opcji filtrowania +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=Automatycznie zamienia przedmiot w ręce gracza na skuteczny dla bloku/bytu przy kliknięciu lewym przyciskiem\nMa opcje filtrowania i dodatkową obsługę interakcji +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=Wyrzuca, wybrane w filtrze przedmioty do pustki\nma więcej opcjii filtrowania +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=Kowadło w rubryce ulepszenia +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=Zamienia część inwentarza plecaka na magazyn energii +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=Kompaktuje przedmioty\ntylko crafting 2x2 +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=Stół Rzemieślniczy w rubryce ulepszenia +item.retro_sophisticated_backpacks.deposit_upgrade.name=Ulepszenie depozytu +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=Umieszcza przedmioty z plecaka do wybranego inwentarza skradając się i klikając prawy przycisk myszy, trzymając plecak w ręce. +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=Plecak staje się nieznisczalny\nnie może zniknąć ani wpaść do pustki +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=Karmi gracza jedzeniem z wyposażenia plecaka +item.retro_sophisticated_backpacks.filter_upgrade.name=Ulepszenia filtra +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=Filtruje przedmioty przesłane do lub z plecaka +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=Umożliwia umieszczanie plecaków w plecakach +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=Przenośna szafa grająca +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=Przyciąga przedmioty do plecaka +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=Captures passive mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=Sprawia że plecak podnosi przedmioty +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=Pompuje płyny między ulepszeniem zbiornika a pobliskimi blokami +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=Uzupełnia stack przedmiotów w ekwipunku gracza +item.retro_sophisticated_backpacks.restock_upgrade.name=Ulepszenie uzupełnienia +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=Przerzuca rzeczy z wyposażenia gracza do wyposażenia plecaka jeżeli trzymany w ręce przy prawym kliknięciu i skradając się +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=Mnoży liczbę stosów mieszczących się w slocie przez %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=Mnoży liczbę stosów mieszczących się w slocie przez %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=Mnoży liczbę stosów mieszczących się w slocie przez %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=Mnoży liczbę stosów mieszczących się w slocie przez %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=Mnoży liczbę stosów mieszczących się w slocie przez %s +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=Mnożniki stosów będą się łączyć przez mnożenie zamiast dodawania +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=Zamienia część inwentarza plecaka na zbiornik na płyny +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=Automatycznie zamienia przedmiot w ręku gracza na ten, który jest skuteczny na bloku/przedmiocie, gdy te zostaną kliknięte lewym przyciskiem myszy. +item.retro_sophisticated_backpacks.void_upgrade.tooltip=Wyrzuca, wybrane w filtrze przedmioty do pustki +retro_sophisticated_backpacks.gui.advanced_deposit_settings=Zaaw. depozyt +retro_sophisticated_backpacks.gui.advanced_filter_settings=Adv. Filter +retro_sophisticated_backpacks.gui.advanced_restock_settings=Zaaw. uzupełnienie +retro_sophisticated_backpacks.gui.backpack_settings=Ustawienia plecaka +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=Ustawienia plecaka +retro_sophisticated_backpacks.gui.crafting_settings=Craft +retro_sophisticated_backpacks.gui.deposit_settings=Depozyt +retro_sophisticated_backpacks.gui.filter_settings=Filter +retro_sophisticated_backpacks.gui.inception_settings=Incepcja +retro_sophisticated_backpacks.gui.input=Input +retro_sophisticated_backpacks.gui.input_output=Input & Output +retro_sophisticated_backpacks.gui.item_display_settings=Item Disp. +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Item Display Settings +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Allows selecting a slot that will be used to show its item on top of storage +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Allows selecting a slot that will be used to show its item on top of storage\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.lock_all_sort=Select All Slots +retro_sophisticated_backpacks.gui.match_durability=Match Durability +retro_sophisticated_backpacks.gui.match_nbt=Match NBT +retro_sophisticated_backpacks.gui.memorize_all=Select All Slots +retro_sophisticated_backpacks.gui.memory_settings=Memory +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release +retro_sophisticated_backpacks.gui.output=Output +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Do Not Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_no_hand=Do Not Interact With\nFluid Container in Hand +retro_sophisticated_backpacks.gui.pump_no_world=Do Not Interact With World +retro_sophisticated_backpacks.gui.pump_output=Output +retro_sophisticated_backpacks.gui.restock_settings=Uzupełnienie +retro_sophisticated_backpacks.gui.search=Click to search +retro_sophisticated_backpacks.gui.search_detail=@ prefix to search by mod name +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=Inny gracz NIE może otworzyć +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=Plecak nie może być otwarty przez innego gracza po kliknięciu prawym przyciskiem myszy na plecy tego gracza. +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=Inny gracz może otworzyć +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=Kiedy ten plecak jest noszony i widoczny, inny gracz może go otworzyć, klikając prawym przyciskiem myszy na plecach tego gracza +retro_sophisticated_backpacks.gui.settings_button.context_backpack=Plecak +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=Ustawienia Tego plecaka +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=Odziedziczone od gracza lub nadpisane dla tego plecaka +retro_sophisticated_backpacks.gui.settings_button.context_player=Player +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Player level settings +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=Apply to all backpacks/storages unless overriden +retro_sophisticated_backpacks.gui.settings_button.display_side_front=Show on Front +retro_sophisticated_backpacks.gui.settings_button.display_side_left=Show on Left side +retro_sophisticated_backpacks.gui.settings_button.display_side_right=Show on Right side +retro_sophisticated_backpacks.gui.settings_button.item_display_color=Toggle Color +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=Next = Left Click\nPrevious = Right Click +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Keep Search Phrase: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=Backpack / Storage gui clears the search phrase when closed and shows all unfiltered item when open again +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep Search Phrase: ON +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=Backpack / Storage gui keeps the search phrase and prefills it / filters by it when open again +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Keep Tab Open: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=Open upgrade tab gets closed when the backpack/storage gui is closed and when the gui is next open all of the tabs are closed +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Keep Tab Open: ON +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=On close of its gui the backpack/storage records which upgrade tab was last open and opens it when the gui is open next time +retro_sophisticated_backpacks.gui.settings_button.rotate=Rotate +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Clockwise = Left Click\nCounter-Clockwise = Right Click +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift Click Into Inventory First +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=Shift click from storage/inventory will first try to put the stack in inventory/storage and only then into an open tab. +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift Click Into Open Tab First +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=Shift click from storage/inventory will first try to put the stack in an open tab and only then into inventory/storage. +retro_sophisticated_backpacks.gui.sort_by_count=By Count +retro_sophisticated_backpacks.gui.sort_by_mod_id=By Mod +retro_sophisticated_backpacks.gui.sort_by_name=By Name +retro_sophisticated_backpacks.gui.sort_by_ore_dict=By Tags +retro_sophisticated_backpacks.gui.sort_inventory=Sort Inventory +retro_sophisticated_backpacks.gui.sorting_settings=No Sort +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=That mob is blocked from capture +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=Bosses cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=Captured %s +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=Hostile mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=That mob cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=Mobs with inventories cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=Backpack has no Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=Only the owner can capture that mob +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=Only one Mob Catcher Upgrade is allowed per backpack +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=Mobs with passengers or vehicles cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=Players cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there +retro_sophisticated_backpacks.gui.status.mob_catcher_released=Released %s +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slots, more than this upgrade allows (%s) +retro_sophisticated_backpacks.gui.tooltip.stack_count=Count: %s +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Transfer to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transfer Matching to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift To Transfer All +retro_sophisticated_backpacks.gui.transfer_to_player_inv=Transfer to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Transfer Matching to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift To Transfer All +retro_sophisticated_backpacks.gui.unlock_all_sort=Unselect All Slots +retro_sophisticated_backpacks.gui.unmemorize_all=Unselect All Slots + +# Fallbacks for keys used by current code +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side +retro_sophisticated_backpacks.gui.stack_size_extra=Count: %s / %s +retro_sophisticated_backpacks.gui.ore_dict_input_help.pro_tip=Protip: You can hover item onto entry\n to check if the entry is applicable,\nor hover on textfield to see available entries. +retro_sophisticated_backpacks.gui.ore_dict_list_entries=Available ore dict: +retro_sophisticated_backpacks.gui.none=(None) +retro_sophisticated_backpacks.gui.craft_into_backpack=Shift Click Result Into Backpack +retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift Click Result Into Player's Inventory +retro_sophisticated_backpacks.gui.settings=Settings +retro_sophisticated_backpacks.gui.configuration_tab=Configuration Tab +retro_sophisticated_backpacks.gui.memorized_slot=Memorized Slot +retro_sophisticated_backpacks.gui.no_sorting_slot=No Sorting Slot +retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank +retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang index 985e566..427b59b 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang @@ -6,14 +6,15 @@ tile.retro_sophisticated_backpacks.backpack_diamond.name=Алмазный Рюк tile.retro_sophisticated_backpacks.backpack_obsidian.name=Обсидиановый Рюкзак #Предметы -item.retro_sophisticated_backpacks.upgrade_base.name=База для улучшений -item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=Начальный уровень улучшения стаков -item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=Улучшение стаков Уровень 1 -item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=Улучшение стаков Уровень 2 -item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=Улучшение стаков Уровень 3 -item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=Улучшение стаков Уровень 4 -item.retro_sophisticated_backpacks.crafting_upgrade.name=Улучшение Крафта -item.retro_sophisticated_backpacks.inception_upgrade.name=Улучшение Инцепции +item.retro_sophisticated_backpacks.upgrade_base.name=Основа улучшения +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=Улучшение «Переполнение 0» +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=Улучшение «Переполнение I» +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=Улучшение «Переполнение II» +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=Улучшение «Переполнение III» +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=Улучшение «Переполнение IV» +item.retro_sophisticated_backpacks.exponential_stack_upgrade.name=Экспоненциальное улучшение стака +item.retro_sophisticated_backpacks.crafting_upgrade.name=Улучшение: «Верстак» +item.retro_sophisticated_backpacks.inception_upgrade.name=Улучшение «Внедрение» #Творческие вкладки itemGroup.retro_sophisticated_backpacks.creative_tab=Ретро Современный Рюкзак @@ -21,128 +22,303 @@ itemGroup.retro_sophisticated_backpacks.creative_tab=Ретро Современ #Всплывающие подсказки (Tooltips) retro_sophisticated_backpacks.tooltip.backpack.inventory_size=Размер инвентаря: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=Размер слотов для улучшений: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Множитель стака: %s retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s -retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Резервуар пуст retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE retro_sophisticated_backpacks.tooltip.backpack.fluid_title=Fluids retro_sophisticated_backpacks.tooltip.backpack.energy_title=Energy -retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades -retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory -retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents -retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents -retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Улучшения +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Инвентарь +retro_sophisticated_backpacks.tooltip.backpack.empty=Не содержит предметы или улучшения +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Зажмите <%s> для просмотра содержимого +retro_sophisticated_backpacks.tooltip.backpack.shift=Shift слева -retro_sophisticated_backpacks.tooltip.upgrade_base=Ничего не делает! Можете положить в слоты для улучшений! -retro_sophisticated_backpacks.tooltip.stack_upgrade=Умножает размер стака на %d -retro_sophisticated_backpacks.tooltip.crafting_upgrade=Добавляет дополнительную сетку крафта на боковую часть рюкзака -retro_sophisticated_backpacks.tooltip.inception_upgrade=Позволяет рюкзакам храниться внутри других рюкзаков -retro_sophisticated_backpacks.tooltip.shift_to_reveal= #Элементы интерфейса (GUI) retro_sophisticated_backpacks.container.backpack=Рюкзак -item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade -item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade -item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade -item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade -item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade -item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade -item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade -item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade -retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations -retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations -retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations -retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations -retro_sophisticated_backpacks.gui.magnet_settings=Magnet -retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet -retro_sophisticated_backpacks.gui.void_settings=Void -retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void -retro_sophisticated_backpacks.gui.refill_settings=Refill -retro_sophisticated_backpacks.gui.advanced_refill_settings=Adv. Refill -retro_sophisticated_backpacks.gui.compacting_settings=Compa... -retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting -retro_sophisticated_backpacks.gui.void_always=Void Always -retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow -retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow -retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes -retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes -retro_sophisticated_backpacks.gui.refill_target_any=Any Slot -retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand -retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI -retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI -item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade -item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade -item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade -item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade -item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade -item.retro_sophisticated_backpacks.pump_upgrade.name=Pump Upgrade -item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Advanced Pump Upgrade -item.retro_sophisticated_backpacks.battery_upgrade.name=Battery Upgrade -item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support -retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack -retro_sophisticated_backpacks.tooltip.pump_upgrade=Moves fluids between the backpack tank and the world or adjacent tanks -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=Moves filtered fluids with extra interaction controls -retro_sophisticated_backpacks.tooltip.battery_upgrade=Adds energy storage to the backpack -retro_sophisticated_backpacks.tooltip.anvil_upgrade=Repairs and renames items from the backpack +item.retro_sophisticated_backpacks.magnet_upgrade.name=Улучшение «Магнит» +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Продвинутое улучшение «Магнит» +item.retro_sophisticated_backpacks.void_upgrade.name=Улучшение «Пустота» +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Продвинутое улучшение «Пустота» +item.retro_sophisticated_backpacks.refill_upgrade.name=Улучшение «Пополнение» +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Продвинутое улучшение «Пополнение» +item.retro_sophisticated_backpacks.compacting_upgrade.name=Улучшение «Сжатие» +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Продвинутое улучшение «Сжатие» +retro_sophisticated_backpacks.gui.magnet_settings=Магнит +retro_sophisticated_backpacks.gui.advanced_magnet_settings=Продв. магнит +retro_sophisticated_backpacks.gui.void_settings=Уничт. +retro_sophisticated_backpacks.gui.advanced_void_settings=Продв. уничт. +retro_sophisticated_backpacks.gui.refill_settings=Пополн. +retro_sophisticated_backpacks.gui.advanced_refill_settings=Продв. пополн. +retro_sophisticated_backpacks.gui.compacting_settings=Сжатие +retro_sophisticated_backpacks.gui.advanced_compacting_settings=Продв. сжатие +retro_sophisticated_backpacks.gui.void_always=Уничтожать всегда +retro_sophisticated_backpacks.gui.void_slot_overflow=Уничтожать сверх слота +retro_sophisticated_backpacks.gui.void_storage_overflow=Уничтожать сверх хранилища +retro_sophisticated_backpacks.gui.refill_target_any=Любой слот +retro_sophisticated_backpacks.gui.refill_target_main_hand=Основная рука +retro_sophisticated_backpacks.gui.refill_target_off_hand=Вторая рука +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Слот 1 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Слот 2 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Слот 3 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Слот 4 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Слот 5 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Слот 6 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Слот 7 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Слот 8 на хотбаре +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Слот 9 на хотбаре +retro_sophisticated_backpacks.gui.allow=Допускать +retro_sophisticated_backpacks.gui.block=Исключать +retro_sophisticated_backpacks.gui.match_backpack_contents=Соответствовать содержимому рюкзака +retro_sophisticated_backpacks.gui.pickup_items=Подбирать предметы +retro_sophisticated_backpacks.gui.do_not_pickup_items=Не подбирать предметы +retro_sophisticated_backpacks.gui.compact_only_uncraftable=Сжимать только то, что раскрафчивается +retro_sophisticated_backpacks.gui.compact_anything=Сжимать всё +retro_sophisticated_backpacks.gui.only_automatic=Работать лишь с другими улучшениями и при автоматизации +retro_sophisticated_backpacks.gui.works_in_gui=Работать также при открытом интерфейсе +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=Позволяет заполнять предметами лишь один слот\nи уничтожать лишнее при переполнении +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=Позволяет заполнять предметами всё хранилище\nи уничтожать лишнее при переполнении +retro_sophisticated_backpacks.gui.refill_target_tooltip=Пополнять: %s +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=Прокрутите для смены целевого слота +item.retro_sophisticated_backpacks.everlasting_upgrade.name=Улучшение «Вечность» +item.retro_sophisticated_backpacks.jukebox_upgrade.name=Улучшение «Проигрыватель» +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Продвинутое улучшение «Проигрыватель» +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Улучшение «Мультиинструмент» +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Продвинутое улучшение «Мультиинструмент» +item.retro_sophisticated_backpacks.tank_upgrade.name=Улучшение «Резервуар» +item.retro_sophisticated_backpacks.pump_upgrade.name=Улучшение «Помпа» +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=Продвинутое улучшение «Помпа» +item.retro_sophisticated_backpacks.battery_upgrade.name=Улучшение «Аккумулятор» +item.retro_sophisticated_backpacks.anvil_upgrade.name=Улучшение «Наковальня» retro_sophisticated_backpacks.gui.everlasting_settings=Everlasting -retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox -retro_sophisticated_backpacks.gui.tool_swapper_settings=Tool Swapper -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Adv. Tool Swapper -retro_sophisticated_backpacks.gui.tank_settings=Tank -retro_sophisticated_backpacks.gui.pump_settings=Pump -retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump -retro_sophisticated_backpacks.gui.battery_settings=Battery -retro_sophisticated_backpacks.gui.anvil_settings=Anvil -retro_sophisticated_backpacks.gui.pump_input=Pump In -retro_sophisticated_backpacks.gui.pump_fluid_handlers=Fluid Handlers -retro_sophisticated_backpacks.gui.pump_world=World -retro_sophisticated_backpacks.gui.pump_hand=Held Items +retro_sophisticated_backpacks.gui.jukebox_settings=Проигр. +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Продв. проигр. +retro_sophisticated_backpacks.gui.tool_swapper_settings=Мультиинстр. +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=Мультиинстр. +retro_sophisticated_backpacks.gui.tank_settings=Рез. +retro_sophisticated_backpacks.gui.pump_settings=Помпа +retro_sophisticated_backpacks.gui.advanced_pump_settings=Продв. помпа +retro_sophisticated_backpacks.gui.battery_settings=Аккум. +retro_sophisticated_backpacks.gui.anvil_settings=Наковальня +retro_sophisticated_backpacks.gui.pump_input=Принимать +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Взаимодействовать с жидкостными хранилищами и трубами +retro_sophisticated_backpacks.gui.pump_world=Взаимодействовать с миром +retro_sophisticated_backpacks.gui.pump_hand=Взаимодействовать с резервуаром в руке retro_sophisticated_backpacks.gui.anvil_no_result=No Result retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift-click result into storage -retro_sophisticated_backpacks.gui.jukebox_play=Play -retro_sophisticated_backpacks.gui.jukebox_stop=Stop -retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc -retro_sophisticated_backpacks.gui.jukebox_next=Next Disc -retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On -retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All -retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One -retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.jukebox_play=Проиграть +retro_sophisticated_backpacks.gui.jukebox_stop=Остановить +retro_sophisticated_backpacks.gui.jukebox_previous=Пред. +retro_sophisticated_backpacks.gui.jukebox_next=След. +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Случайный порядок выключен +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Случайный порядок включён +retro_sophisticated_backpacks.gui.jukebox_repeat_all=Повтор всех пластинок +retro_sophisticated_backpacks.gui.jukebox_repeat_one=Повтор одной пластинки +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Повтор выключен retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools -retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Back To Backpack -retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings -retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings -retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag -retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=Назад к рюкзаку +retro_sophisticated_backpacks.gui.memory_settings.tooltip=Настройки запоминания слота +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Позволяют задавать слоты для запоминания содержимого и учёта точного совпадения предметов в них\nОткройте вкладку для дальнейшей настройки +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Позволяют задавать слоты для запоминания содержимого и учёта точного совпадения предметов в них\nВыделить все слоты или снять всё выделение = отдельные клавиши\nВыделить слот = нажмите или зажмите ЛКМ\nСнять выделение со слота = нажмите или зажмите ПКМ +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=Настройки игнорирования сортировки +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Позволяют задавать слоты для их исключения из сортировки\nОткройте вкладку для дальнейшей настройки +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Позволяют задавать слоты для их исключения из сортировки\nВыделить все слоты или снять всё выделение = отдельные клавиши\nВыделить слот = нажмите или зажмите ЛКМ\nСнять выделение со слота = нажмите или зажмите ПКМ + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Упаковывает предметы в их сжатые варианты\nПоддерживает рецепты 2×2 и 3×3, а также имеет больше настроек фильтрации +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=Продвинутое улучшение «Разгрузка» +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Выгружает предметы из рюкзака во внешний инвентарь при нажатии Shift + ПКМ\nИмеет больше настроек фильтрации +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=Продвинутое улучшение «Кормление» +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=Кормит игрока едой из инвентаря рюкзака\nИмеет больше настроек кормления +item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=Продвинутое улучшение «Фильтр» +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=Фильтрует предметы, проходящие через рюкзак при автоматизации\nИмеет больше настроек фильтрации +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=Портативный проигрыватель для большего количества пластинок\nИмеет больше настроек воспроизведения +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=Притягивает предметы в рюкзак на большем расстоянии\nИмеет больше настроек фильтрации +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=Advanced Mob Catcher Upgrade +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=Captures passive and hostile mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=Продвинутое улучшение «Подбор» +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=Позволяет рюкзаку подбирать предметы\nИмеет больше настроек фильтрации +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=Перекачивает жидкости между резервуаром от улучшения и прилегающими блоками\nРаботает с жидкостными контейнерами в руке и блоками в мире\nПозволяет фильтровать перекачиваемые жидкости +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=Поддерживает стак заданных предметов из рюкзака в инвентаре игрока\nПозволяет тонко настраивать целевой слот\nТакже выдаёт блоки из рюкзака при нажатии СКМ +item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=Продвинутое улучшение «Загрузка» +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=Нагружает рюкзак предметами из внешнего инвентаря при нажатии Shift + ПКМ\nИмеет больше настроек фильтрации +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=Автоматически меняет предмет в руке игрока на подходящий для блока/сущности при щелчке ЛКМ\nИмеет параметры фильтра и дополнительное взаимодействие +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=Уничтожает попадающие в рюкзак предметы согласно фильтру\nИмеет больше настроек фильтрации +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=Наковальня во вкладке улучшения +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=Замещает часть инвентаря рюкзака на хранилище энергии +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=Упаковывает предметы в их сжатые варианты\nПоддерживает только рецепты 2×2 +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=Верстак во вкладке улучшения +item.retro_sophisticated_backpacks.deposit_upgrade.name=Улучшение «Разгрузка» +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=Выгружает предметы из рюкзака во внешний инвентарь при нажатии Shift + ПКМ +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=Делает рюкзак неразрушимым\nНе позволяет ему исчезнуть или упасть в пустоту +item.retro_sophisticated_backpacks.feeding_upgrade.name=Улучшение «Кормление» +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=Кормит игрока едой из инвентаря рюкзака +item.retro_sophisticated_backpacks.filter_upgrade.name=Улучшение «Фильтр» +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=Фильтрует предметы, проходящие через рюкзак при автоматизации +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=Позволяет рюкзаку хранить в себе другие рюкзаки +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=Портативный проигрыватель +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=Притягивает предметы в рюкзак на расстоянии +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=Mob Catcher Upgrade +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=Captures passive mobs into backpack storage slots with sneak right-click +item.retro_sophisticated_backpacks.pickup_upgrade.name=Улучшение «Подбор» +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=Позволяет рюкзаку подбирать предметы +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=Перекачивает жидкости между резервуаром от улучшения и прилегающими блоками +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=Поддерживает стак заданных предметов из рюкзака в инвентаре игрока +item.retro_sophisticated_backpacks.restock_upgrade.name=Улучшение «Загрузка» +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=Нагружает рюкзак предметами из внешнего инвентаря при нажатии Shift + ПКМ +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=Умножает количество стаков, помещаемых в слот, на %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=Умножает количество стаков, помещаемых в слот, на %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=Умножает количество стаков, помещаемых в слот, на %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=Умножает количество стаков, помещаемых в слот, на %s +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=Умножает количество стаков, помещаемых в слот, на %s +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=Множители стаков складываются умножением, а не сложением +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=Замещает часть инвентаря рюкзака на хранилище жидкости +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=Автоматически заменяет инструмент в руке игрока на подходящий блоку или сущности при взаимодействии +item.retro_sophisticated_backpacks.void_upgrade.tooltip=Уничтожает попадающие в рюкзак предметы согласно фильтру +retro_sophisticated_backpacks.gui.advanced_deposit_settings=Продв. разгр. +retro_sophisticated_backpacks.gui.advanced_feeding_settings=Продв. корм. +retro_sophisticated_backpacks.gui.advanced_filter_settings=Продв. фильтр +retro_sophisticated_backpacks.gui.advanced_pickup_settings=Продв. подбор +retro_sophisticated_backpacks.gui.advanced_restock_settings=Продв. загр. +retro_sophisticated_backpacks.gui.backpack_settings=Общие настройки +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=Общие настройки +retro_sophisticated_backpacks.gui.blacklist=Исключать +retro_sophisticated_backpacks.gui.complete_hunger=Кормить лишь в том случае, когда игрок достаточно голоден\n(с максимально эффективным расходом потребляемой пищи) +retro_sophisticated_backpacks.gui.consider_health=Кормить игрока при малейшем получении урона\n(с игнорированием настройки кормления при неполном здоровье игрока) +retro_sophisticated_backpacks.gui.crafting_settings=Созд. +retro_sophisticated_backpacks.gui.deposit_settings=Разгр. +retro_sophisticated_backpacks.gui.feeding_settings=Корм. +retro_sophisticated_backpacks.gui.filter_settings=Фильтр +retro_sophisticated_backpacks.gui.half_hunger=Кормить лишь в том случае, когда игрок достаточно голоден\n(с расходом потребляемой пищи до половины единиц насыщения) +retro_sophisticated_backpacks.gui.ignore_durability=Игнорировать прочность +retro_sophisticated_backpacks.gui.ignore_health=Кормить игрока без учёта уровня здоровья\n(c игнорированием здоровья игрока и исключительным учётом настройки кормления) +retro_sophisticated_backpacks.gui.ignore_nbt=Игнорировать NBT +retro_sophisticated_backpacks.gui.immediate_hunger=Кормить игрока при малейшем падении уровня голода\n(с максимально неэффективным расходом потребляемой пищи) +retro_sophisticated_backpacks.gui.inception_settings=Внедрение +retro_sophisticated_backpacks.gui.input=Принимать +retro_sophisticated_backpacks.gui.input_output=Принимать и отдавать +retro_sophisticated_backpacks.gui.item_display_settings=Отображ. +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Настройки отображения предмета +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Позволяют задавать слот под показ находящегося в нём предмета на модели хранилища\nОткройте вкладку для дальнейшей настройки +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Позволяют задавать слот под показ находящегося в нём предмета на модели хранилища\nВыбрать слот = нажмите или зажмите ЛКМ\nСнять выделение со слота = нажмите или зажмите ПКМ +retro_sophisticated_backpacks.gui.lock_all_sort=Выделить все слоты +retro_sophisticated_backpacks.gui.match_durability=Соответствовать прочности +retro_sophisticated_backpacks.gui.match_item=Соответствовать предметам +retro_sophisticated_backpacks.gui.match_mod_id=Соответствовать списку модов +retro_sophisticated_backpacks.gui.match_nbt=Соответствовать NBT +retro_sophisticated_backpacks.gui.memorize_all=Выделить все слоты +retro_sophisticated_backpacks.gui.memory_settings=Запом. +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release +retro_sophisticated_backpacks.gui.output=Отдавать +retro_sophisticated_backpacks.gui.pickup_settings=Подбор +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Не взаимодействовать с жидкостными хранилищами и трубами +retro_sophisticated_backpacks.gui.pump_no_hand=Не взаимодействовать с резервуаром в руке +retro_sophisticated_backpacks.gui.pump_no_world=Не взаимодействовать с миром +retro_sophisticated_backpacks.gui.pump_output=Отдавать +retro_sophisticated_backpacks.gui.restock_settings=Загр. +retro_sophisticated_backpacks.gui.search=Нажмите ЛКМ для поиска +retro_sophisticated_backpacks.gui.search_detail=Добавьте @ для поиска по имени мода +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=Запретить открывать другим игрокам +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=Другой игрок никак не сможет открыть рюкзак владельца (даже надетый и видимый), нажав ПКМ по чужой спине +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=Разрешить открывать другим игрокам +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=При надетом на владельце видимом рюкзаке другой игрок сможет открыть его, нажав ПКМ по чужой спине +retro_sophisticated_backpacks.gui.settings_button.context_backpack=Рюкзак +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=Настройки на уровне данного рюкзака +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=Наследуются от игрока или переназначаются для данного рюкзака +retro_sophisticated_backpacks.gui.settings_button.context_player=Игрок +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Настройки на уровне игрока +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=Применяются ко всем рюкзакам или хранилищам до переназначения +retro_sophisticated_backpacks.gui.settings_button.display_side_front=Отобразить спереди +retro_sophisticated_backpacks.gui.settings_button.display_side_left=Отобразить слева +retro_sophisticated_backpacks.gui.settings_button.display_side_right=Отобразить справа +retro_sophisticated_backpacks.gui.settings_button.item_display_color=Задать цвет +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=Следующий цвет = ЛКМ\nПредыдущий цвет = ПКМ +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Сохранять поисковый запрос: ВЫКЛ. +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=Интерфейс рюкзака или хранилища очистит поисковый запрос при закрытии и отобразит все неотфильтрованные предметы при повторном открытии +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Сохранять поисковый запрос: ВКЛ. +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=Интерфейс рюкзака или хранилища сохранит и удержит поисковый запрос, а также отфильтрует результат при повторном открытии +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Держать вкладку открытой: ВЫКЛ. +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=Интерфейс рюкзака или хранилища закроет последнюю открытую вкладку улучшения при выходе из настроек и будет держать все вкладки свёрнутыми при повторном открытии +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Держать вкладку открытой: ВКЛ. +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=Интерфейс рюкзака или хранилища запомнит последнюю открытую вкладку улучшения при выходе из настроек и автоматически развернёт её при повторном открытии +retro_sophisticated_backpacks.gui.settings_button.rotate=Повернуть +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=По часовой стрелке = ЛКМ\nПротив часовой стрелки = ПКМ +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Нажатие с Shift в приоритете для инвентарей +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=Стак предметов при нажатии с Shift сперва перейдёт в инвентарь игрока или хранилища, а затем — в открытую вкладку +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Нажатие с Shift в приоритете для вкладок +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=Стак предметов при нажатии c Shift сперва перейдёт в открытую вкладку, а затем — в инвентарь игрока или хранилища +retro_sophisticated_backpacks.gui.sort_by_count=По количеству +retro_sophisticated_backpacks.gui.sort_by_mod_id=По моду +retro_sophisticated_backpacks.gui.sort_by_name=По имени +retro_sophisticated_backpacks.gui.sort_by_ore_dict=По тегам +retro_sophisticated_backpacks.gui.sort_inventory=Сортировать инвентарь +retro_sophisticated_backpacks.gui.sorting_settings=Игнор. сорт. +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=That mob is blocked from capture +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=Bosses cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=Captured %s +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=Hostile mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=That mob cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=Mobs with inventories cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slot area available +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=Backpack has no Mob Catcher Upgrade +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=Only the owner can capture that mob +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=Only one Mob Catcher Upgrade is allowed per backpack +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=Mobs with passengers or vehicles cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=Players cannot be captured +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there +retro_sophisticated_backpacks.gui.status.mob_catcher_released=Released %s +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=Mob needs %s slots, more than this upgrade allows (%s) +retro_sophisticated_backpacks.gui.tooltip.stack_count=Количество предметов: %s +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Перенести всё в хранилище +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Перенести похожее в хранилище +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Зажмите Shift, чтобы перенести всё +retro_sophisticated_backpacks.gui.transfer_to_player_inv=Перенести всё в инвентарь +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Перенести похожее в инвентарь +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Зажмите Shift, чтобы перенести всё +retro_sophisticated_backpacks.gui.unlock_all_sort=Снять выделение со всех слотов +retro_sophisticated_backpacks.gui.unmemorize_all=Снять выделение со всех слотов +retro_sophisticated_backpacks.gui.whitelist=Допускать + +# Fallbacks for keys used by current code +retro_sophisticated_backpacks.key.open_backpack.desc=Opens Backpack in Inventory +retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpacks +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side +retro_sophisticated_backpacks.gui.stack_size_extra=Count: %s / %s +retro_sophisticated_backpacks.gui.not_in_effect=Not in effect +retro_sophisticated_backpacks.gui.match_ore_dict=By Ore Dictionary +retro_sophisticated_backpacks.gui.add_ore_dict_entry=Add Ore Dict. +retro_sophisticated_backpacks.gui.remove_ore_dict_entry=Remove Ore Dict. +retro_sophisticated_backpacks.gui.ore_dict_input_help=You can input ore dictionary here,\nregex is supported. +retro_sophisticated_backpacks.gui.ore_dict_input_help.pro_tip=Protip: You can hover item onto entry\n to check if the entry is applicable,\nor hover on textfield to see available entries. +retro_sophisticated_backpacks.gui.ore_dict_list_entries=Available ore dict: +retro_sophisticated_backpacks.gui.none=(None) +retro_sophisticated_backpacks.gui.craft_into_backpack=Shift Click Result Into Backpack +retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift Click Result Into Player's Inventory +retro_sophisticated_backpacks.gui.settings=Settings +retro_sophisticated_backpacks.gui.configuration_tab=Configuration Tab +retro_sophisticated_backpacks.gui.memorized_slot=Memorized Slot +retro_sophisticated_backpacks.gui.no_sorting_slot=No Sorting Slot +retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank +retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang index 71358da..64da7b6 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang @@ -48,37 +48,21 @@ retro_sophisticated_backpacks.tooltip.backpack.empty=未加装升级或物品存 retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=按<%s>查看内容 retro_sophisticated_backpacks.tooltip.backpack.shift=左Shift -retro_sophisticated_backpacks.tooltip.upgrade_base=没有任何效果!大可放进升级插槽里! -retro_sophisticated_backpacks.tooltip.stack_upgrade=堆叠上限×%d -retro_sophisticated_backpacks.tooltip.exponential_stack_upgrade=堆叠倍数将按乘算而非加算计算 -retro_sophisticated_backpacks.tooltip.crafting_upgrade=在背包旁添加额外的合成方格 -retro_sophisticated_backpacks.tooltip.inception_upgrade=可套娃存放背包 -retro_sophisticated_backpacks.tooltip.pickup_upgrade=能够让背包捡起物品 -retro_sophisticated_backpacks.tooltip.advanced_pickup_upgrade=能够让背包捡起物品,拥有更多过滤选项 -retro_sophisticated_backpacks.tooltip.feeding_upgrade=能够让背包自动喂食玩家 -retro_sophisticated_backpacks.tooltip.advanced_feeding_upgrade=能够让背包自动喂食玩家,拥有更多过滤选项 -retro_sophisticated_backpacks.tooltip.deposit_upgrade=手持背包,潜行右击容器以卸载物品 -retro_sophisticated_backpacks.tooltip.advanced_deposit_upgrade=手持背包,潜行右击容器以卸载物品,拥有更多过滤选项 -retro_sophisticated_backpacks.tooltip.restock_upgrade=手持背包,潜行右击容器以提取物品 -retro_sophisticated_backpacks.tooltip.advanced_restock_upgrade=手持背包,潜行右击容器以提取物品,拥有更多过滤选项 -retro_sophisticated_backpacks.tooltip.filter_upgrade=放置在世界中时,过滤输入/输出背包的物品 -retro_sophisticated_backpacks.tooltip.advanced_filter_upgrade=放置在世界中时,过滤输入/输出背包的物品,拥有更多配置项 -retro_sophisticated_backpacks.tooltip.shift_to_reveal=<按Shift显示> # Gui Elements retro_sophisticated_backpacks.container.backpack=背包 @@ -100,63 +84,59 @@ retro_sophisticated_backpacks.gui.advanced_filter_settings=高级过滤 retro_sophisticated_backpacks.gui.crafting_settings=合成 retro_sophisticated_backpacks.gui.memory_settings=记忆 -retro_sophisticated_backpacks.gui.sorting_settings=禁止整理 +retro_sophisticated_backpacks.gui.sorting_settings=忽略整理 retro_sophisticated_backpacks.gui.backpack_settings=背包设置 -retro_sophisticated_backpacks.gui.item_display_settings=物品显示设置 +retro_sophisticated_backpacks.gui.item_display_settings=物品显示 retro_sophisticated_backpacks.gui.backpack_settings.tooltip=背包设置 retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=配置背包行为\n打开标签页以修改背包设置 retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=配置背包行为\n上下文=选择修改玩家设置或背包设置\n按钮用于切换 Shift 点击、标签页、搜索和访问行为 retro_sophisticated_backpacks.gui.item_display_settings.tooltip=物品显示设置 -retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=选择渲染在背包上的背包槽位\n打开标签页以修改物品显示 -retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=选择渲染在背包上的背包槽位\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=选择一个槽位,让物品得以在容器顶端显示 +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=选择一个槽位,让物品得以在容器顶端显示\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 retro_sophisticated_backpacks.gui.search=点击以搜索 -retro_sophisticated_backpacks.gui.search_detail=使用 @modid 搜索模组,使用 #文本 搜索 tooltip -retro_sophisticated_backpacks.gui.settings_button.context_player=玩家 -retro_sophisticated_backpacks.gui.settings_button.context_backpack=背包 -retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=玩家设置上下文 -retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=设置保存在玩家身上,并会跟随你使用不同背包 -retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=背包设置上下文 -retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=设置保存在该背包上,并对使用它的玩家生效 -retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift点击优先进入打开的标签页 -retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift点击使用普通行为 -retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.detail=控制升级标签页打开时 Shift 点击物品的转移目标 -retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=保持标签页打开 -retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=操作后关闭标签页 -retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.detail=控制与槽位交互后升级标签页是否保持展开 -retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=保留搜索文本 -retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=清空搜索文本 -retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.detail=控制关闭背包后是否保留搜索文本 -retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=其他玩家可打开 -retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=仅所有者可打开 -retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.detail=控制其他玩家是否能打开该背包 -retro_sophisticated_backpacks.gui.settings_button.rotate=旋转显示物品 -retro_sophisticated_backpacks.gui.settings_button.rotate_detail=左键顺时针旋转\n右键逆时针旋转 -retro_sophisticated_backpacks.gui.settings_button.item_display_color=显示颜色 -retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=左键选择下一个颜色\n右键选择上一个颜色 +retro_sophisticated_backpacks.gui.search_detail=使用前缀@以按模组名称搜索 +retro_sophisticated_backpacks.gui.settings_button.context_player=玩家设置 +retro_sophisticated_backpacks.gui.settings_button.context_backpack=背包设置 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=玩家全局设置 +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=应用于玩家的所有背包/容器,被单独覆写的除外 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=该背包的设置 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=不受到玩家全局设置影响 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift左击优先放入升级标签页 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift左击优先放入物品栏 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=保持标签页打开: 开 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=保持标签页打开: 关 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=保留搜索内容:开 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=保留搜索内容:关 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=其他玩家可以打开 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=其他玩家不可打开 +retro_sophisticated_backpacks.gui.settings_button.rotate=旋转 +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=顺时针=左击\n逆时针=右击 +retro_sophisticated_backpacks.gui.settings_button.item_display_color=更换颜色 +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=上一种=左击\n下一种=右击 retro_sophisticated_backpacks.gui.settings_button.display_side_front=显示在正面 retro_sophisticated_backpacks.gui.settings_button.display_side_left=显示在左侧 retro_sophisticated_backpacks.gui.settings_button.display_side_right=显示在右侧 retro_sophisticated_backpacks.gui.settings_button.display_side_detail=左键选择下一个侧面\n右键选择上一个侧面 retro_sophisticated_backpacks.gui.memory_settings.tooltip=槽位记忆设置 -retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=选择会记住当前物品的槽位,该槽位只接收匹配物品\n打开标签页以修改槽位设置 -retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=选择会记住当前物品的槽位,该槽位只接收匹配物品\n全选/取消全选槽位=按钮\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=使所选槽位记忆当前物品,该槽位只会接收对应物品\n打开选项卡以修改槽位设置 +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=使所选槽位记忆当前物品,该槽位只会接收对应物品\n全选槽位/取消全选槽位=按钮\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 retro_sophisticated_backpacks.gui.sorting_settings.tooltip=忽略整理设置 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=选择整理时会被忽略的槽位\n打开标签页以修改槽位设置 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=选择整理时会被忽略的槽位\n全选/取消全选槽位=按钮\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=选择忽略整理的槽位\n打开标签页以修改此设置 +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=选择忽略整理的槽位\n全选/取消全选槽位=按钮\n选择槽位=左键单击/拖动\n取消选择槽位=右键单击/拖动 # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=数量:%s / %s retro_sophisticated_backpacks.gui.not_in_effect=未生效 -retro_sophisticated_backpacks.gui.whitelist=白名单 -retro_sophisticated_backpacks.gui.blacklist=黑名单 +retro_sophisticated_backpacks.gui.whitelist=允许 +retro_sophisticated_backpacks.gui.blacklist=阻止 -retro_sophisticated_backpacks.gui.match_item=按物品 -retro_sophisticated_backpacks.gui.match_mod_id=按模组ID +retro_sophisticated_backpacks.gui.match_item=匹配物品 +retro_sophisticated_backpacks.gui.match_mod_id=匹配模组 retro_sophisticated_backpacks.gui.match_ore_dict=按矿物词典 -retro_sophisticated_backpacks.gui.match_durability=匹配耐久度 -retro_sophisticated_backpacks.gui.ignore_durability=忽略耐久度 +retro_sophisticated_backpacks.gui.match_durability=匹配耐久 +retro_sophisticated_backpacks.gui.ignore_durability=忽略耐久 retro_sophisticated_backpacks.gui.match_nbt=匹配NBT retro_sophisticated_backpacks.gui.ignore_nbt=忽略NBT @@ -176,23 +156,23 @@ retro_sophisticated_backpacks.gui.ignore_health=忽略生命值\n忽略玩家的 retro_sophisticated_backpacks.gui.consider_health=当玩家受伤时立即喂食\n在玩家未达到最大生命值前忽略饥饿值 retro_sophisticated_backpacks.gui.input_output=输入&输出 -retro_sophisticated_backpacks.gui.input=仅输入 -retro_sophisticated_backpacks.gui.output=仅输出 +retro_sophisticated_backpacks.gui.input=输入 +retro_sophisticated_backpacks.gui.output=输出 -retro_sophisticated_backpacks.gui.sort_inventory=整理背包 -retro_sophisticated_backpacks.gui.sort_by_name=按名称整理 -retro_sophisticated_backpacks.gui.sort_by_mod_id=按模组ID整理 -retro_sophisticated_backpacks.gui.sort_by_count=按数量整理 -retro_sophisticated_backpacks.gui.sort_by_ore_dict=按矿物词典整理 +retro_sophisticated_backpacks.gui.sort_inventory=整理物品栏 +retro_sophisticated_backpacks.gui.sort_by_name=按名字 +retro_sophisticated_backpacks.gui.sort_by_mod_id=按模组 +retro_sophisticated_backpacks.gui.sort_by_count=按数量 +retro_sophisticated_backpacks.gui.sort_by_ore_dict=按标签 retro_sophisticated_backpacks.gui.craft_into_backpack=Shift点击合成产物转移至背包 retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift点击合成产物转移至玩家物品栏 -retro_sophisticated_backpacks.gui.transfer_to_player_inv=转移所有物品至玩家物品栏 -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=转移匹配物品至玩家物品栏 +retro_sophisticated_backpacks.gui.transfer_to_player_inv=转移至物品栏 +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=转移匹配物品至物品栏 retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=按住Shift以转移所有物品 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=转移所有物品至背包物品栏 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=转移匹配物品至背包物品栏 +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=转移至容器 +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=转移匹配物品至容器 retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=按住Shift以转移所有物品 retro_sophisticated_backpacks.gui.settings=设置 @@ -200,12 +180,12 @@ retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=返回背包 retro_sophisticated_backpacks.gui.configuration_tab=设置标签页 retro_sophisticated_backpacks.gui.memorized_slot=被记忆的槽位 -retro_sophisticated_backpacks.gui.memorize_all=记忆所有槽位 -retro_sophisticated_backpacks.gui.unmemorize_all=遗忘所有槽位 +retro_sophisticated_backpacks.gui.memorize_all=全选槽位 +retro_sophisticated_backpacks.gui.unmemorize_all=取消全选槽位 retro_sophisticated_backpacks.gui.no_sorting_slot=禁止整理的槽位 -retro_sophisticated_backpacks.gui.lock_all_sort=禁止整理所有槽位 -retro_sophisticated_backpacks.gui.unlock_all_sort=允许整理所有槽位 +retro_sophisticated_backpacks.gui.lock_all_sort=全选槽位 +retro_sophisticated_backpacks.gui.unlock_all_sort=取消全选槽位 item.retro_sophisticated_backpacks.magnet_upgrade.name=磁铁升级 item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=高级磁铁升级 @@ -213,16 +193,8 @@ item.retro_sophisticated_backpacks.void_upgrade.name=虚空升级 item.retro_sophisticated_backpacks.advanced_void_upgrade.name=高级虚空升级 item.retro_sophisticated_backpacks.refill_upgrade.name=补货升级 item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=高级补货升级 -item.retro_sophisticated_backpacks.compacting_upgrade.name=压缩升级 -item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=高级压缩升级 -retro_sophisticated_backpacks.tooltip.magnet_upgrade=将附近物品吸入背包 -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=将附近物品吸入背包,拥有更多过滤选项 -retro_sophisticated_backpacks.tooltip.void_upgrade=在物品进入背包前销毁匹配物品 -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=在物品进入背包前销毁匹配物品,拥有更多过滤选项 -retro_sophisticated_backpacks.tooltip.refill_upgrade=从背包补充玩家物品栏中匹配的物品堆 -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=从背包补充玩家物品栏中匹配的物品堆,拥有更多过滤选项 -retro_sophisticated_backpacks.tooltip.compacting_upgrade=使用 2x2 配方压缩匹配物品 -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=使用 2x2 和 3x3 配方压缩匹配物品,拥有更多过滤选项 +item.retro_sophisticated_backpacks.compacting_upgrade.name=压制升级 +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=高级压制升级 retro_sophisticated_backpacks.gui.magnet_settings=磁铁 retro_sophisticated_backpacks.gui.advanced_magnet_settings=高级磁铁 retro_sophisticated_backpacks.gui.void_settings=虚空 @@ -232,80 +204,79 @@ retro_sophisticated_backpacks.gui.advanced_refill_settings=高级补货 retro_sophisticated_backpacks.gui.compacting_settings=压缩 retro_sophisticated_backpacks.gui.advanced_compacting_settings=高级压缩 retro_sophisticated_backpacks.gui.void_always=总是销毁 -retro_sophisticated_backpacks.gui.void_slot_overflow=槽位溢出时销毁 -retro_sophisticated_backpacks.gui.void_storage_overflow=背包满时销毁 -retro_sophisticated_backpacks.gui.compact_uncraftable_only=仅可逆配方 -retro_sophisticated_backpacks.gui.compact_any_recipe=所有压缩配方 +retro_sophisticated_backpacks.gui.void_slot_overflow=销毁槽位过量 +retro_sophisticated_backpacks.gui.void_storage_overflow=销毁存储过量 retro_sophisticated_backpacks.gui.refill_target_any=任意槽位 retro_sophisticated_backpacks.gui.refill_target_main_hand=主手 retro_sophisticated_backpacks.gui.refill_target_off_hand=副手 -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=快捷栏 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=快捷栏 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=快捷栏 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=快捷栏 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=快捷栏 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=快捷栏 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=快捷栏 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=快捷栏 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=快捷栏 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=不在GUI中工作 -retro_sophisticated_backpacks.gui.work_in_gui_enabled=在GUI中工作 +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=快捷栏1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=快捷栏2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=快捷栏3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=快捷栏4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=快捷栏5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=快捷栏6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=快捷栏7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=快捷栏8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=快捷栏9 +retro_sophisticated_backpacks.gui.allow=允许 +retro_sophisticated_backpacks.gui.block=阻止 +retro_sophisticated_backpacks.gui.match_backpack_contents=匹配背包已有物品 +retro_sophisticated_backpacks.gui.pickup_items=吸取物品 +retro_sophisticated_backpacks.gui.do_not_pickup_items=不吸取物品 +retro_sophisticated_backpacks.gui.compact_only_uncraftable=仅压缩可逆配方 +retro_sophisticated_backpacks.gui.compact_anything=压缩任意配方 +retro_sophisticated_backpacks.gui.only_automatic=仅与其他升级/自动化方式(如漏斗)配合工作 +retro_sophisticated_backpacks.gui.works_in_gui=在GUI中工作 +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=允许一个槽位填满物品\n销毁所有过量物品 +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=允许整体存储空间填满物品\n销毁所有过量物品 +retro_sophisticated_backpacks.gui.refill_target_tooltip=补充%s +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=用滚轮改变槽位 item.retro_sophisticated_backpacks.everlasting_upgrade.name=永恒升级 item.retro_sophisticated_backpacks.jukebox_upgrade.name=唱片机升级 item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=高级唱片机升级 -item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=工具切换升级 -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=高级工具切换升级 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=工具替换升级 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=高级工具替换升级 item.retro_sophisticated_backpacks.tank_upgrade.name=储罐升级 -item.retro_sophisticated_backpacks.pump_upgrade.name=泵升级 -item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=高级泵升级 +item.retro_sophisticated_backpacks.pump_upgrade.name=液泵升级 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=高级液泵升级 item.retro_sophisticated_backpacks.battery_upgrade.name=电池升级 item.retro_sophisticated_backpacks.anvil_upgrade.name=铁砧升级 -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=防止背包物品因自然消失、爆炸和方块破坏而丢失 -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=从背包播放音乐唱片 -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=从背包播放多张音乐唱片 -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=挖掘或攻击时从背包切换工具 -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=从背包切换工具,并支持额外交互 -retro_sophisticated_backpacks.tooltip.tank_upgrade=为背包添加流体存储 -retro_sophisticated_backpacks.tooltip.pump_upgrade=在背包储罐与世界或相邻储罐之间转移流体 -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=带过滤和额外交互控制的流体转移升级 -retro_sophisticated_backpacks.tooltip.battery_upgrade=为背包添加能量存储 -retro_sophisticated_backpacks.tooltip.anvil_upgrade=从背包中修复和重命名物品 retro_sophisticated_backpacks.gui.everlasting_settings=永恒 retro_sophisticated_backpacks.gui.jukebox_settings=唱片机 retro_sophisticated_backpacks.gui.advanced_jukebox_settings=唱片机 -retro_sophisticated_backpacks.gui.tool_swapper_settings=工具切换 -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=高级工具切换 +retro_sophisticated_backpacks.gui.tool_swapper_settings=工具替换 +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=工具替换 retro_sophisticated_backpacks.gui.tank_settings=储罐 -retro_sophisticated_backpacks.gui.pump_settings=泵 -retro_sophisticated_backpacks.gui.advanced_pump_settings=高级泵 +retro_sophisticated_backpacks.gui.pump_settings=液泵 +retro_sophisticated_backpacks.gui.advanced_pump_settings=高级液泵 retro_sophisticated_backpacks.gui.battery_settings=电池 retro_sophisticated_backpacks.gui.anvil_settings=铁砧 -retro_sophisticated_backpacks.gui.pump_input=泵入背包 +retro_sophisticated_backpacks.gui.pump_input=输入 retro_sophisticated_backpacks.gui.pump_input_detail=将流体抽入背包储罐 -retro_sophisticated_backpacks.gui.pump_output=泵出背包 +retro_sophisticated_backpacks.gui.pump_output=输出 retro_sophisticated_backpacks.gui.pump_output_detail=将流体从背包储罐泵出 -retro_sophisticated_backpacks.gui.pump_fluid_handlers=与储罐和管道交互 +retro_sophisticated_backpacks.gui.pump_fluid_handlers=与储罐&管道交互 retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=允许通过相邻流体处理器移动流体 -retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=不与储罐和管道交互 +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=不与与储罐&管道交互 retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=禁止通过相邻流体处理器移动流体 -retro_sophisticated_backpacks.gui.pump_world=与世界交互 +retro_sophisticated_backpacks.gui.pump_world=与世界中方块交互 retro_sophisticated_backpacks.gui.pump_world_detail=允许在世界中放置或抽取流体 -retro_sophisticated_backpacks.gui.pump_no_world=不与世界交互 +retro_sophisticated_backpacks.gui.pump_no_world=不与世界中方块交互 retro_sophisticated_backpacks.gui.pump_no_world_detail=禁止在世界中放置或抽取流体 -retro_sophisticated_backpacks.gui.pump_hand=与手持容器交互 +retro_sophisticated_backpacks.gui.pump_hand=与手持流体容器交互 retro_sophisticated_backpacks.gui.pump_hand_detail=允许填充或抽取玩家手持容器 -retro_sophisticated_backpacks.gui.pump_no_hand=不与手持容器交互 +retro_sophisticated_backpacks.gui.pump_no_hand=不与手持流体容器交互 retro_sophisticated_backpacks.gui.pump_no_hand_detail=禁止填充或抽取玩家手持容器 retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=手持流体容器点击可设置该过滤\n空手点击可清除 retro_sophisticated_backpacks.gui.anvil_no_result=无结果 retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift 点击背包存储 retro_sophisticated_backpacks.gui.jukebox_play=播放 retro_sophisticated_backpacks.gui.jukebox_stop=停止 -retro_sophisticated_backpacks.gui.jukebox_previous=上一张唱片 -retro_sophisticated_backpacks.gui.jukebox_next=下一张唱片 +retro_sophisticated_backpacks.gui.jukebox_previous=上一首 +retro_sophisticated_backpacks.gui.jukebox_next=下一首 retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=关闭随机播放 -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=开启随机播放 -retro_sophisticated_backpacks.gui.jukebox_repeat_all=列表循环 +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=启用随机播放 +retro_sophisticated_backpacks.gui.jukebox_repeat_all=全部循环 retro_sophisticated_backpacks.gui.jukebox_repeat_one=单曲循环 retro_sophisticated_backpacks.gui.jukebox_repeat_no=关闭循环 retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=不切换武器 @@ -315,24 +286,72 @@ retro_sophisticated_backpacks.gui.tool_swapper_only_tools=仅切换工具 retro_sophisticated_backpacks.gui.tool_swapper_no_swap=不自动切换工具 item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=生物捕捉升级 item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=高级生物捕捉升级 -retro_sophisticated_backpacks.tooltip.mob_catcher_upgrade=潜行右击将被动生物捕捉进背包存储槽 -retro_sophisticated_backpacks.tooltip.advanced_mob_catcher_upgrade=潜行右击将被动和敌对生物捕捉进背包存储槽 retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=点击释放 -retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=先释放已捕获生物再移除生物捕捉升级 -retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=已捕获生物需要高级生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=释放已捕捉的生物后才能移除生物捕捉升级 +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=已捕捉的生物需要高级生物捕捉升级 retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=每个背包只能安装一个生物捕捉升级 -retro_sophisticated_backpacks.gui.status.mob_catcher_captured=已捕获 %s -retro_sophisticated_backpacks.gui.status.mob_catcher_released=已释放 %s +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=已捕捉%s +retro_sophisticated_backpacks.gui.status.mob_catcher_released=已释放%s retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=背包没有生物捕捉升级 -retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=该生物无法捕捉 -retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=无法捕捉玩家 -retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=无法捕捉Boss -retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=无法捕捉有乘客或载具的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=该生物不能被捕捉 +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=不能捕捉玩家 +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=不能捕捉Boss +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=不能捕捉带有乘客或载具关系的生物 retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=该生物被禁止捕捉 -retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=只有主人能捕捉该生物 -retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=无法捕捉带物品栏的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=只有所有者可以捕捉该生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=不能捕捉带有物品栏的生物 retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=敌对生物需要高级生物捕捉升级 -retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=该生物需要 %s 个槽,超过此升级允许的 %s 个 -retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=没有可用的 %sx%s 空槽区域 -retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=无法在这里释放生物 -retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=这里没有有效释放空间 +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=该生物需要%s个槽位,超过此升级允许的上限(%s) +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=没有空余的%sx%s槽位区域 +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=无法在那里释放生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=那里没有有效的释放空间 + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=将物品压制为对应的压缩变体\n包括2x2,3x3配方以及更多的过滤选项 +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=手持背包 Shift 右击容器卸载物品\n更多的过滤选项 +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=将背包内的食物喂给玩家\n更多喂食条件选项 +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=过滤输入/输出背包的物品\n更多的过滤选项 +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=支持更多唱片的便携唱片机\n当然还有更多播放选项 +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=将更大范围内的物品吸入背包\n更多的过滤选项 +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=潜行右击可将被动和敌对生物捕捉到背包存储槽位中 +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=使背包捡起物品\n更多的过滤选项 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=在储罐升级和相邻方块之间泵送流体\n适用于手持流体容器和世界中的流体方块\n允许过滤泵送的流体 +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=使所选物品在玩家物品栏中自动补充至一组\n更精准的目标槽位选择\n可使用鼠标中键从背包中选取方块 +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=手持背包潜行右击容器提取物品\n更多的过滤选项 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=左击时自动将玩家手持物品替换为对应方块/实体的挖掘或攻击工具\n具有过滤选项和额外交互支持 +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=销毁过滤器中选定的物品\n更多的过滤选项 +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=在升级标签页中添加一个铁砧 +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=将部分背包空间替换为能量存储空间 +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=将物品压制为对应的压缩变体\n仅2x2配方 +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=在升级标签页中添加一个工作台 +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=手持背包潜行右击容器卸载物品 +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=使背包变得坚不可摧\n不会消失及掉入虚空 +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=堆叠倍数将按乘算而非加算计算 +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=将背包内的食物喂给玩家 +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=过滤输入/输出背包的物品 +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=使背包套背包成为可能 +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=便携唱片机 +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=将一定范围内的物品吸入背包 +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=潜行右击可将被动生物捕捉到背包存储槽位中 +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=能够让背包捡起物品 +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=在储罐升级和相邻方块之间泵送流体 +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=使所选物品在玩家物品栏中自动补充至一组 +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=手持背包潜行右击容器提取物品 +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=单个槽位可容纳的堆叠数乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=单个槽位可容纳的堆叠数乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=单个槽位可容纳的堆叠数乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=单个槽位可容纳的堆叠数乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=单个槽位可容纳的堆叠数乘以%s +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=将部分背包空间替换为流体存储空间 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=左击时自动将玩家手持物品替换为对应方块/实体的挖掘或攻击工具 +item.retro_sophisticated_backpacks.void_upgrade.tooltip=销毁过滤器中选定的物品 +retro_sophisticated_backpacks.gui.inception_settings=嵌套 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=即使该背包已被穿戴,其他玩家也无法通过对该玩家后背右击打开它 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=当该背包被穿戴且设置为可见时,其他玩家可以对该玩家后背右击打开它 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=关闭背包/容器GUI后将清空搜索内容,重新打开时显示所有未过滤的物品 +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=背包/容器GUI会保留搜索内容,重新打开时会自动填充并根据搜索词过滤物品 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=关闭背包/容器时关闭所有标签页 +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=关闭背包/容器时保存升级标签页的状态 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=Shift左击物品优先放入背包/容器物品栏 +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=Shift左击物品优先放入打开的升级标签页 +retro_sophisticated_backpacks.gui.tooltip.stack_count=数量:%s diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang index d3b1a5c..b29f541 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang @@ -7,24 +7,24 @@ tile.retro_sophisticated_backpacks.backpack_obsidian.name=黑曜石背包 # Items item.retro_sophisticated_backpacks.upgrade_base.name=基礎升級 -item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=初級堆疊升級 -item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=堆疊升級 T1 -item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=堆疊升級 T2 -item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=堆疊升級 T3 -item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=堆疊升級 T4 +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.name=Stack Upgrade Starter Tier +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.name=堆疊升級T1 +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.name=堆疊升級T2 +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.name=堆疊升級T3 +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.name=堆疊升級T4 item.retro_sophisticated_backpacks.exponential_stack_upgrade.name=指數堆疊升級 item.retro_sophisticated_backpacks.crafting_upgrade.name=合成升級 item.retro_sophisticated_backpacks.inception_upgrade.name=嵌套升級 item.retro_sophisticated_backpacks.pickup_upgrade.name=拾取升級 -item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=進階拾取升級 +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.name=高級拾取升級 item.retro_sophisticated_backpacks.feeding_upgrade.name=餵食升級 -item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=進階餵食升級 +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.name=高級餵食升級 item.retro_sophisticated_backpacks.deposit_upgrade.name=卸貨升級 -item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=進階卸貨升級 +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=高級卸貨升級 item.retro_sophisticated_backpacks.restock_upgrade.name=取貨升級 -item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=進階取貨升級 +item.retro_sophisticated_backpacks.advanced_restock_upgrade.name=高級取貨升級 item.retro_sophisticated_backpacks.filter_upgrade.name=過濾升級 -item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=進階過濾升級 +item.retro_sophisticated_backpacks.advanced_filter_upgrade.name=高級過濾升級 # Creative Tabs itemGroup.retro_sophisticated_backpacks.creative_tab=復古精緻背包 @@ -36,98 +36,82 @@ retro_sophisticated_backpacks.key.category=復古精緻背包 # Tooltips retro_sophisticated_backpacks.tooltip.backpack.inventory_size=背包容量: %d retro_sophisticated_backpacks.tooltip.backpack.upgrade_slots_size=升級插槽: %d -retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=堆疊倍數:%s +retro_sophisticated_backpacks.tooltip.backpack.stack_multiplier=Stack Size Multiplier: %s retro_sophisticated_backpacks.tooltip.backpack.fluid=%s mB %s -retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=空罐 +retro_sophisticated_backpacks.tooltip.backpack.fluid_empty=Empty tank retro_sophisticated_backpacks.tooltip.backpack.energy=%s FE retro_sophisticated_backpacks.tooltip.backpack.fluid_title=流體 retro_sophisticated_backpacks.tooltip.backpack.energy_title=能量 -retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=升級 -retro_sophisticated_backpacks.tooltip.backpack.inventory_title=物品 -retro_sophisticated_backpacks.tooltip.backpack.empty=未加裝升級或物品存儲 -retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=按<%s>查看內容 -retro_sophisticated_backpacks.tooltip.backpack.shift=左 Shift +retro_sophisticated_backpacks.tooltip.backpack.upgrades_title=Upgrades +retro_sophisticated_backpacks.tooltip.backpack.inventory_title=Inventory +retro_sophisticated_backpacks.tooltip.backpack.empty=No Upgrades or Inventory Contents +retro_sophisticated_backpacks.tooltip.backpack.press_for_contents=Press <%s> to View Contents +retro_sophisticated_backpacks.tooltip.backpack.shift=Left Shift -retro_sophisticated_backpacks.tooltip.upgrade_base=沒有效果!你大可放在升級插槽! -retro_sophisticated_backpacks.tooltip.stack_upgrade=提供堆疊倍率 x%d -retro_sophisticated_backpacks.tooltip.exponential_stack_upgrade=堆疊倍率會以相乘堆疊而非相加 -retro_sophisticated_backpacks.tooltip.crafting_upgrade=在背包旁增加額外的合成欄 -retro_sophisticated_backpacks.tooltip.inception_upgrade=允許將背包放入背包 -retro_sophisticated_backpacks.tooltip.pickup_upgrade=允許背包拾取並存入背包 -retro_sophisticated_backpacks.tooltip.advanced_pickup_upgrade=允許背包根據更多配置拾取並存入背包 -retro_sophisticated_backpacks.tooltip.feeding_upgrade=允許背包自動餵食玩家 -retro_sophisticated_backpacks.tooltip.advanced_feeding_upgrade=允許背包根據更多配置自動餵食玩家 -retro_sophisticated_backpacks.tooltip.deposit_upgrade=將背包物品卸貨至潛行右鍵的容器 -retro_sophisticated_backpacks.tooltip.advanced_deposit_upgrade=根據更多配置將背包物品卸貨至潛行右鍵的容器 -retro_sophisticated_backpacks.tooltip.restock_upgrade=將潛行右鍵的容器物品取貨至背包 -retro_sophisticated_backpacks.tooltip.advanced_restock_upgrade=根據更多配置將潛行右鍵的容器物品取貨至背包 -retro_sophisticated_backpacks.tooltip.filter_upgrade=當放置於世界時過濾輸入的物品 -retro_sophisticated_backpacks.tooltip.advanced_filter_upgrade=當放置於世界時根據更多配置過濾輸入的物品 -retro_sophisticated_backpacks.tooltip.shift_to_reveal=<按 Shift 顯示> # Gui Elements retro_sophisticated_backpacks.container.backpack=背包 -retro_sophisticated_backpacks.gui.pickup_settings=拾取 -retro_sophisticated_backpacks.gui.advanced_pickup_settings=進階拾取 +retro_sophisticated_backpacks.gui.pickup_settings=Pickup +retro_sophisticated_backpacks.gui.advanced_pickup_settings=Adv. Pickup -retro_sophisticated_backpacks.gui.feeding_settings=餵食 -retro_sophisticated_backpacks.gui.advanced_feeding_settings=進階餵食 +retro_sophisticated_backpacks.gui.feeding_settings=Feeding +retro_sophisticated_backpacks.gui.advanced_feeding_settings=Adv. Feeding retro_sophisticated_backpacks.gui.deposit_settings=卸貨 -retro_sophisticated_backpacks.gui.advanced_deposit_settings=進階卸貨 +retro_sophisticated_backpacks.gui.advanced_deposit_settings=高級卸貨 retro_sophisticated_backpacks.gui.restock_settings=取貨 -retro_sophisticated_backpacks.gui.advanced_restock_settings=進階取貨 +retro_sophisticated_backpacks.gui.advanced_restock_settings=高級取貨 -retro_sophisticated_backpacks.gui.filter_settings=過濾 -retro_sophisticated_backpacks.gui.advanced_filter_settings=進階過濾 +retro_sophisticated_backpacks.gui.filter_settings=Filter +retro_sophisticated_backpacks.gui.advanced_filter_settings=Adv. Filter -retro_sophisticated_backpacks.gui.crafting_settings=合成 +retro_sophisticated_backpacks.gui.crafting_settings=Craft -retro_sophisticated_backpacks.gui.memory_settings=記憶 -retro_sophisticated_backpacks.gui.sorting_settings=禁止整理 -retro_sophisticated_backpacks.gui.memory_settings.tooltip=槽位記憶設定 -retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=選擇會記住目前物品的欄位,該欄位只接收匹配物品\n開啟標籤頁以修改欄位設定 -retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=選擇會記住目前物品的欄位,該欄位只接收匹配物品\n全選/取消全選欄位=按鈕\n選擇欄位=左鍵單擊/拖曳\n取消選擇欄位=右鍵單擊/拖曳 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip=忽略整理設定 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=選擇整理時會被忽略的欄位\n開啟標籤頁以修改欄位設定 -retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=選擇整理時會被忽略的欄位\n全選/取消全選欄位=按鈕\n選擇欄位=左鍵單擊/拖曳\n取消選擇欄位=右鍵單擊/拖曳 +retro_sophisticated_backpacks.gui.memory_settings=Memory +retro_sophisticated_backpacks.gui.sorting_settings=No Sort +retro_sophisticated_backpacks.gui.memory_settings.tooltip=Slot Memory Settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.memory_settings.tooltip_open_detail=Allows selecting slots that remember their contents and only allow matching stacks in them\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings +retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag # Gui Tooltips retro_sophisticated_backpacks.gui.stack_size_extra=數量: %s / %s retro_sophisticated_backpacks.gui.not_in_effect=未生效 -retro_sophisticated_backpacks.gui.whitelist=白名單 -retro_sophisticated_backpacks.gui.blacklist=黑名單 +retro_sophisticated_backpacks.gui.whitelist=Allow +retro_sophisticated_backpacks.gui.blacklist=Block -retro_sophisticated_backpacks.gui.match_item=根據物品屬性 -retro_sophisticated_backpacks.gui.match_mod_id=根據模組 ID +retro_sophisticated_backpacks.gui.match_item=Match Item +retro_sophisticated_backpacks.gui.match_mod_id=Match Mod retro_sophisticated_backpacks.gui.match_ore_dict=根據礦物詞典 retro_sophisticated_backpacks.gui.craft_into_backpack=Shift 點擊合成結果轉移至背包 retro_sophisticated_backpacks.gui.craft_into_player_inventory=Shift 點擊合成結果轉移至玩家物品欄 -retro_sophisticated_backpacks.gui.match_durability=考慮耐久 -retro_sophisticated_backpacks.gui.ignore_durability=無視耐久 +retro_sophisticated_backpacks.gui.match_durability=Match Durability +retro_sophisticated_backpacks.gui.ignore_durability=Ignore Durability -retro_sophisticated_backpacks.gui.match_nbt=考慮 NBT -retro_sophisticated_backpacks.gui.ignore_nbt=無視 NBT +retro_sophisticated_backpacks.gui.match_nbt=Match NBT +retro_sophisticated_backpacks.gui.ignore_nbt=Ignore NBT retro_sophisticated_backpacks.gui.add_ore_dict_entry=新增礦物詞典 retro_sophisticated_backpacks.gui.remove_ore_dict_entry=移除礦物詞典 @@ -136,132 +120,241 @@ retro_sophisticated_backpacks.gui.ore_dict_input_help.pro_tip=提示:你可以 retro_sophisticated_backpacks.gui.ore_dict_list_entries=可用的礦物詞典: retro_sophisticated_backpacks.gui.none=(無) -retro_sophisticated_backpacks.gui.complete_hunger=只在玩家夠餓時餵食\n不會浪費食物提供的任何飢餓值 -retro_sophisticated_backpacks.gui.half_hunger=只在玩家夠餓時餵食\n最多浪費食物提供的一半飢餓值 -retro_sophisticated_backpacks.gui.immediate_hunger=當玩家飢餓時立即餵食\n浪費食物提供的大部分飢餓值 +retro_sophisticated_backpacks.gui.complete_hunger=Only feed when player is hungry enough\nto not waste any hunger points of the food at all +retro_sophisticated_backpacks.gui.half_hunger=Only feed when player is hungry enough\nto only waste half hunger points of the food at most +retro_sophisticated_backpacks.gui.immediate_hunger=Feed as soon as player is tiny bit hungry\nwastes quite a few hunger points of the food -retro_sophisticated_backpacks.gui.ignore_health=忽略生命值\n忽略玩家的生命值,僅基於飢餓值設定餵食玩家 -retro_sophisticated_backpacks.gui.consider_health=當玩家受傷時立即餵食\n在玩家生命值未滿時忽略飢餓值設定 +retro_sophisticated_backpacks.gui.ignore_health=Do not consider health\nIgnores player's health and only feeds based on hunger setting +retro_sophisticated_backpacks.gui.consider_health=Feed player immediately when hurt\nIgnores hunger setting when player is not at max health -retro_sophisticated_backpacks.gui.input_output=輸入 & 輸出 -retro_sophisticated_backpacks.gui.input=僅限輸入 -retro_sophisticated_backpacks.gui.output=僅限輸出 +retro_sophisticated_backpacks.gui.input_output=Input & Output +retro_sophisticated_backpacks.gui.input=Input +retro_sophisticated_backpacks.gui.output=Output -retro_sophisticated_backpacks.gui.sort_inventory=整理背包 -retro_sophisticated_backpacks.gui.sort_by_name=根據名稱整理 -retro_sophisticated_backpacks.gui.sort_by_mod_id=根據模組 ID 整理 -retro_sophisticated_backpacks.gui.sort_by_count=根據數量整理 -retro_sophisticated_backpacks.gui.sort_by_ore_dict=根據礦物詞典整理 +retro_sophisticated_backpacks.gui.sort_inventory=Sort Inventory +retro_sophisticated_backpacks.gui.sort_by_name=By Name +retro_sophisticated_backpacks.gui.sort_by_mod_id=By Mod +retro_sophisticated_backpacks.gui.sort_by_count=By Count +retro_sophisticated_backpacks.gui.sort_by_ore_dict=By Tags -retro_sophisticated_backpacks.gui.transfer_to_player_inv=轉移所有物品至玩家物品欄 -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=轉移對應物品至玩家物品欄 -retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift 以轉移全部 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=轉移所有物品至背包物品欄 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=轉移對應物品至背包物品欄 -retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift 以轉移全部 +retro_sophisticated_backpacks.gui.transfer_to_player_inv=Transfer to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_1=Transfer Matching to Inventory +retro_sophisticated_backpacks.gui.transfer_to_player_inv_matched_2=Shift To Transfer All +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv=Transfer to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_1=Transfer Matching to Storage +retro_sophisticated_backpacks.gui.transfer_to_backpack_inv_matched_2=Shift To Transfer All retro_sophisticated_backpacks.gui.settings=設定 retro_sophisticated_backpacks.gui.back_to_backpack.tooltip=返回背包 retro_sophisticated_backpacks.gui.configuration_tab=設定介面 retro_sophisticated_backpacks.gui.memorized_slot=記憶欄位 -retro_sophisticated_backpacks.gui.memorize_all=記憶所有欄位 -retro_sophisticated_backpacks.gui.unmemorize_all=遺忘所有欄位 +retro_sophisticated_backpacks.gui.memorize_all=Select All Slots +retro_sophisticated_backpacks.gui.unmemorize_all=Unselect All Slots retro_sophisticated_backpacks.gui.no_sorting_slot=禁止整理欄位 -retro_sophisticated_backpacks.gui.lock_all_sort=禁止整理所有欄位 -retro_sophisticated_backpacks.gui.unlock_all_sort=允許整理所有欄位 - -item.retro_sophisticated_backpacks.magnet_upgrade.name=Magnet Upgrade -item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=Advanced Magnet Upgrade -item.retro_sophisticated_backpacks.void_upgrade.name=Void Upgrade -item.retro_sophisticated_backpacks.advanced_void_upgrade.name=Advanced Void Upgrade -item.retro_sophisticated_backpacks.refill_upgrade.name=Refill Upgrade -item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=Advanced Refill Upgrade -item.retro_sophisticated_backpacks.compacting_upgrade.name=Compacting Upgrade -item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=Advanced Compacting Upgrade -retro_sophisticated_backpacks.tooltip.magnet_upgrade=Pulls nearby items into the backpack -retro_sophisticated_backpacks.tooltip.advanced_magnet_upgrade=Pulls nearby items into the backpack with more configurations -retro_sophisticated_backpacks.tooltip.void_upgrade=Voids matching items before they enter the backpack -retro_sophisticated_backpacks.tooltip.advanced_void_upgrade=Voids matching items before they enter the backpack with more configurations -retro_sophisticated_backpacks.tooltip.refill_upgrade=Refills matching player inventory stacks from the backpack -retro_sophisticated_backpacks.tooltip.advanced_refill_upgrade=Refills matching player inventory stacks from the backpack with more configurations -retro_sophisticated_backpacks.tooltip.compacting_upgrade=Compacts matching items using 2x2 recipes -retro_sophisticated_backpacks.tooltip.advanced_compacting_upgrade=Compacts matching items using 2x2 and 3x3 recipes with more configurations -retro_sophisticated_backpacks.gui.magnet_settings=磁鐵 -retro_sophisticated_backpacks.gui.advanced_magnet_settings=進階磁鐵 -retro_sophisticated_backpacks.gui.void_settings=虛空 -retro_sophisticated_backpacks.gui.advanced_void_settings=進階虛空 +retro_sophisticated_backpacks.gui.lock_all_sort=Select All Slots +retro_sophisticated_backpacks.gui.unlock_all_sort=Unselect All Slots + +item.retro_sophisticated_backpacks.magnet_upgrade.name=磁鐵升級 +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.name=高級磁鐵升級 +item.retro_sophisticated_backpacks.void_upgrade.name=虛空升級 +item.retro_sophisticated_backpacks.advanced_void_upgrade.name=高級虛空升級 +item.retro_sophisticated_backpacks.refill_upgrade.name=補貨升級 +item.retro_sophisticated_backpacks.advanced_refill_upgrade.name=高級補貨升級 +item.retro_sophisticated_backpacks.compacting_upgrade.name=壓縮升級 +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.name=高級壓縮升級 +retro_sophisticated_backpacks.gui.magnet_settings=Magnet +retro_sophisticated_backpacks.gui.advanced_magnet_settings=Adv. Magnet +retro_sophisticated_backpacks.gui.void_settings=Void +retro_sophisticated_backpacks.gui.advanced_void_settings=Adv. Void retro_sophisticated_backpacks.gui.refill_settings=補貨 -retro_sophisticated_backpacks.gui.advanced_refill_settings=進階補貨 -retro_sophisticated_backpacks.gui.compacting_settings=壓縮 -retro_sophisticated_backpacks.gui.advanced_compacting_settings=進階壓縮 +retro_sophisticated_backpacks.gui.advanced_refill_settings=高級補貨 +retro_sophisticated_backpacks.gui.compacting_settings=Compa... +retro_sophisticated_backpacks.gui.advanced_compacting_settings=Adv. Compacting retro_sophisticated_backpacks.gui.void_always=Void Always retro_sophisticated_backpacks.gui.void_slot_overflow=Void Slot Overflow retro_sophisticated_backpacks.gui.void_storage_overflow=Void Storage Overflow -retro_sophisticated_backpacks.gui.compact_uncraftable_only=Only Reversible Recipes -retro_sophisticated_backpacks.gui.compact_any_recipe=All Compacting Recipes -retro_sophisticated_backpacks.gui.refill_target_any=Any Slot -retro_sophisticated_backpacks.gui.refill_target_main_hand=Main Hand -retro_sophisticated_backpacks.gui.refill_target_off_hand=Off Hand -retro_sophisticated_backpacks.gui.refill_target_hotbar_1=Hotbar 1 -retro_sophisticated_backpacks.gui.refill_target_hotbar_2=Hotbar 2 -retro_sophisticated_backpacks.gui.refill_target_hotbar_3=Hotbar 3 -retro_sophisticated_backpacks.gui.refill_target_hotbar_4=Hotbar 4 -retro_sophisticated_backpacks.gui.refill_target_hotbar_5=Hotbar 5 -retro_sophisticated_backpacks.gui.refill_target_hotbar_6=Hotbar 6 -retro_sophisticated_backpacks.gui.refill_target_hotbar_7=Hotbar 7 -retro_sophisticated_backpacks.gui.refill_target_hotbar_8=Hotbar 8 -retro_sophisticated_backpacks.gui.refill_target_hotbar_9=Hotbar 9 -retro_sophisticated_backpacks.gui.work_in_gui_disabled=Do not work in GUI -retro_sophisticated_backpacks.gui.work_in_gui_enabled=Work in GUI -item.retro_sophisticated_backpacks.everlasting_upgrade.name=Everlasting Upgrade -item.retro_sophisticated_backpacks.jukebox_upgrade.name=Jukebox Upgrade +retro_sophisticated_backpacks.gui.refill_target_any=任何插槽 +retro_sophisticated_backpacks.gui.refill_target_main_hand=主手 +retro_sophisticated_backpacks.gui.refill_target_off_hand=副手 +retro_sophisticated_backpacks.gui.refill_target_hotbar_1=快捷欄插槽 1 +retro_sophisticated_backpacks.gui.refill_target_hotbar_2=快捷欄插槽 2 +retro_sophisticated_backpacks.gui.refill_target_hotbar_3=快捷欄插槽 3 +retro_sophisticated_backpacks.gui.refill_target_hotbar_4=快捷欄插槽 4 +retro_sophisticated_backpacks.gui.refill_target_hotbar_5=快捷欄插槽 5 +retro_sophisticated_backpacks.gui.refill_target_hotbar_6=快捷欄插槽 6 +retro_sophisticated_backpacks.gui.refill_target_hotbar_7=快捷欄插槽 7 +retro_sophisticated_backpacks.gui.refill_target_hotbar_8=快捷欄插槽 8 +retro_sophisticated_backpacks.gui.refill_target_hotbar_9=快捷欄插槽 9 +retro_sophisticated_backpacks.gui.allow=Allow +retro_sophisticated_backpacks.gui.block=Block +retro_sophisticated_backpacks.gui.match_backpack_contents=依照背包已有物品取出 +retro_sophisticated_backpacks.gui.pickup_items=Pickup Items +retro_sophisticated_backpacks.gui.do_not_pickup_items=Do Not Pickup Items +retro_sophisticated_backpacks.gui.compact_only_uncraftable=Compact Only Uncraftable +retro_sophisticated_backpacks.gui.compact_anything=Compact Anything +retro_sophisticated_backpacks.gui.only_automatic=Only works with other upgrades/automation +retro_sophisticated_backpacks.gui.works_in_gui=Works in GUI as well +retro_sophisticated_backpacks.gui.void_slot_overflow_detail=Allows single slot to be filled with the item\nand voids anything that overflows +retro_sophisticated_backpacks.gui.void_storage_overflow_detail=Allows whole storage to be filled with the item\n and voids anything that overflows +retro_sophisticated_backpacks.gui.refill_target_tooltip=補貨 %s +retro_sophisticated_backpacks.gui.refill_scroll_tooltip=滾動以更改目標插槽 +item.retro_sophisticated_backpacks.everlasting_upgrade.name=永恆升級 +item.retro_sophisticated_backpacks.jukebox_upgrade.name=唱片機升級 item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.name=Advanced Jukebox Upgrade -item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=Tool Swapper Upgrade -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=Advanced Tool Swapper Upgrade -item.retro_sophisticated_backpacks.tank_upgrade.name=Tank Upgrade -item.retro_sophisticated_backpacks.pump_upgrade.name=泵升級 -item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=進階泵升級 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.name=工具替換升級 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.name=高級工具替換升級 +item.retro_sophisticated_backpacks.tank_upgrade.name=儲罐升級 +item.retro_sophisticated_backpacks.pump_upgrade.name=液泵升級 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.name=高級液泵升級 item.retro_sophisticated_backpacks.battery_upgrade.name=電池升級 -item.retro_sophisticated_backpacks.anvil_upgrade.name=鐵砧升級 -retro_sophisticated_backpacks.tooltip.everlasting_upgrade=Prevents backpack item loss from despawning, explosions and block destruction -retro_sophisticated_backpacks.tooltip.jukebox_upgrade=Plays music discs from the backpack -retro_sophisticated_backpacks.tooltip.advanced_jukebox_upgrade=Plays multiple music discs from the backpack -retro_sophisticated_backpacks.tooltip.tool_swapper_upgrade=Swaps tools from the backpack when mining or attacking -retro_sophisticated_backpacks.tooltip.advanced_tool_swapper_upgrade=Swaps tools from the backpack with extra interaction support -retro_sophisticated_backpacks.tooltip.tank_upgrade=Adds fluid storage to the backpack -retro_sophisticated_backpacks.tooltip.pump_upgrade=在背包儲罐與世界或相鄰儲罐之間轉移流體 -retro_sophisticated_backpacks.tooltip.advanced_pump_upgrade=帶過濾和額外交互控制的流體轉移升級 -retro_sophisticated_backpacks.tooltip.battery_upgrade=為背包加入能量儲存 -retro_sophisticated_backpacks.tooltip.anvil_upgrade=從背包中修復和重新命名物品 +item.retro_sophisticated_backpacks.anvil_upgrade.name=Anvil Upgrade retro_sophisticated_backpacks.gui.everlasting_settings=永恆 -retro_sophisticated_backpacks.gui.jukebox_settings=唱片機 -retro_sophisticated_backpacks.gui.advanced_jukebox_settings=唱片機 -retro_sophisticated_backpacks.gui.tool_swapper_settings=工具切換 -retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=進階工具切換 -retro_sophisticated_backpacks.gui.tank_settings=儲罐 -retro_sophisticated_backpacks.gui.pump_settings=泵 -retro_sophisticated_backpacks.gui.advanced_pump_settings=進階泵 -retro_sophisticated_backpacks.gui.battery_settings=電池 -retro_sophisticated_backpacks.gui.anvil_settings=鐵砧 -retro_sophisticated_backpacks.gui.pump_input=輸入 -retro_sophisticated_backpacks.gui.pump_fluid_handlers=流體處理器 -retro_sophisticated_backpacks.gui.pump_world=世界 -retro_sophisticated_backpacks.gui.pump_hand=手持容器 +retro_sophisticated_backpacks.gui.jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.advanced_jukebox_settings=Jukebox +retro_sophisticated_backpacks.gui.tool_swapper_settings=工具替換 +retro_sophisticated_backpacks.gui.advanced_tool_swapper_settings=工具替換 +retro_sophisticated_backpacks.gui.tank_settings=Tank +retro_sophisticated_backpacks.gui.pump_settings=Pump +retro_sophisticated_backpacks.gui.advanced_pump_settings=Adv. Pump +retro_sophisticated_backpacks.gui.battery_settings=Batt. +retro_sophisticated_backpacks.gui.anvil_settings=Anvil +retro_sophisticated_backpacks.gui.pump_input=Input +retro_sophisticated_backpacks.gui.pump_fluid_handlers=Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_world=Interact With World +retro_sophisticated_backpacks.gui.pump_hand=Interact With\nFluid Container in Hand retro_sophisticated_backpacks.gui.anvil_no_result=無結果 retro_sophisticated_backpacks.gui.anvil_shift_click_storage=Shift 點擊背包儲存 retro_sophisticated_backpacks.gui.jukebox_play=Play retro_sophisticated_backpacks.gui.jukebox_stop=Stop -retro_sophisticated_backpacks.gui.jukebox_previous=Previous Disc -retro_sophisticated_backpacks.gui.jukebox_next=Next Disc -retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Off -retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle On +retro_sophisticated_backpacks.gui.jukebox_previous=Previous +retro_sophisticated_backpacks.gui.jukebox_next=Next +retro_sophisticated_backpacks.gui.jukebox_shuffle_disabled=Shuffle Disabled +retro_sophisticated_backpacks.gui.jukebox_shuffle_enabled=Shuffle Enabled retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One -retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Off +retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Disabled retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools + +# Upstream-aligned tooltips and GUI text +item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=將物品壓縮為對應的壓縮變體\n包括2x2,3x3配方以及更多的過濾選項 +item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=手持背包 Shift 右擊容器卸載物品\n更多的過濾選項 +item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=將背包內的食物餵給玩家\n更多的過濾選項 +item.retro_sophisticated_backpacks.advanced_filter_upgrade.tooltip=過濾輸入/輸出背包的物品\n更多的過濾選項 +item.retro_sophisticated_backpacks.advanced_jukebox_upgrade.tooltip=Portable Jukebox with support for more music discs\nAlso more playback options +item.retro_sophisticated_backpacks.advanced_magnet_upgrade.tooltip=將更大範圍內的物品吸入背包\n更多的過濾選項 +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=高級生物捕捉升級 +item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.tooltip=潛行右擊可將被動和敵對生物捕捉到背包儲存槽位中 +item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=使背包撿起物品\n更多的過濾選項 +item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=在儲罐升級和相鄰方塊之間泵送流體\n適用於手持流體容器和世界中的流體方塊\n允許過濾泵送的流體 +item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=不斷補充玩家物品欄中選定物品的堆疊\n允許更精確的目標槽選擇\n還允許中鍵點擊從背包中拾取方塊 +item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=手持背包潛行右擊容器提取物品\n更多的過濾選項 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=左擊時自動將玩家手持物品替換為對應方塊/實體的挖掘或攻擊工具\n具有過濾選項和額外交互支援 +item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=銷毀篩檢程式中選定的物品\n更多的過濾選項 +item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=Anvil in an upgrade tab +item.retro_sophisticated_backpacks.battery_upgrade.tooltip=將部分背包空間替換為能量存儲空間 +item.retro_sophisticated_backpacks.compacting_upgrade.tooltip=將物品壓縮為對應的壓縮變體\n僅2x2配方 +item.retro_sophisticated_backpacks.crafting_upgrade.tooltip=在升級標籤頁中添加一個合成台 +item.retro_sophisticated_backpacks.deposit_upgrade.tooltip=手持背包潛行右擊容器卸載物品 +item.retro_sophisticated_backpacks.everlasting_upgrade.tooltip=使背包變得堅不可摧\n不會消失及掉入虛空 +item.retro_sophisticated_backpacks.exponential_stack_upgrade.tooltip=堆疊倍率會以相乘堆疊而非相加 +item.retro_sophisticated_backpacks.feeding_upgrade.tooltip=將背包內的食物餵給玩家 +item.retro_sophisticated_backpacks.filter_upgrade.tooltip=過濾輸入/輸出背包的物品 +item.retro_sophisticated_backpacks.inception_upgrade.tooltip=使背包套背包成為可能 +item.retro_sophisticated_backpacks.jukebox_upgrade.tooltip=便攜式唱片機 +item.retro_sophisticated_backpacks.magnet_upgrade.tooltip=將一定範圍內的物品吸入背包 +item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=生物捕捉升級 +item.retro_sophisticated_backpacks.mob_catcher_upgrade.tooltip=潛行右擊可將被動生物捕捉到背包儲存槽位中 +item.retro_sophisticated_backpacks.pickup_upgrade.tooltip=使背包撿起物品 +item.retro_sophisticated_backpacks.pump_upgrade.tooltip=在儲罐升級和相鄰方塊之間泵送流體 +item.retro_sophisticated_backpacks.refill_upgrade.tooltip=使所選物品在玩家物品欄中自動補充至一組 +item.retro_sophisticated_backpacks.restock_upgrade.tooltip=手持背包潛行右擊容器提取物品 +item.retro_sophisticated_backpacks.stack_upgrade_starter_tier.tooltip=單個槽位可容納的堆疊數乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_1.tooltip=單個槽位可容納的堆疊數乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_2.tooltip=單個槽位可容納的堆疊數乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_3.tooltip=單個槽位可容納的堆疊數乘以%s +item.retro_sophisticated_backpacks.stack_upgrade_tier_4.tooltip=單個槽位可容納的堆疊數乘以%s +item.retro_sophisticated_backpacks.tank_upgrade.tooltip=將部分背包空間替換為流體存儲空間 +item.retro_sophisticated_backpacks.tool_swapper_upgrade.tooltip=左擊時自動將玩家手持物品替換為對應方塊/實體的挖掘或攻擊工具 +item.retro_sophisticated_backpacks.void_upgrade.tooltip=銷毀篩檢程式中選定的物品 +retro_sophisticated_backpacks.gui.backpack_settings=背包設置 +retro_sophisticated_backpacks.gui.backpack_settings.tooltip=背包設置 +retro_sophisticated_backpacks.gui.inception_settings=嵌套 +retro_sophisticated_backpacks.gui.item_display_settings=Item Disp. +retro_sophisticated_backpacks.gui.item_display_settings.tooltip=Item Display Settings +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_detail=Allows selecting a slot that will be used to show its item on top of storage +retro_sophisticated_backpacks.gui.item_display_settings.tooltip_open_detail=Allows selecting a slot that will be used to show its item on top of storage\nSelect slot = left click/drag\nUnselect slot = right click/drag +retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=點擊釋放 +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers=Do Not Interact With Tanks & Pipes +retro_sophisticated_backpacks.gui.pump_no_hand=Do Not Interact With\nFluid Container in Hand +retro_sophisticated_backpacks.gui.pump_no_world=Do Not Interact With World +retro_sophisticated_backpacks.gui.pump_output=Output +retro_sophisticated_backpacks.gui.search=Click to search +retro_sophisticated_backpacks.gui.search_detail=@ prefix to search by mod name +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off=其他玩家不可打開 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.off.tooltip=即使該背包已被穿戴,其他玩家也無法通過對該玩家後背右擊打開它 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on=其他玩家可以打開 +retro_sophisticated_backpacks.gui.settings_button.another_player_can_open.on.tooltip=當該背包被穿戴且設置為可見時,其他玩家可以對該玩家後背右擊打開它 +retro_sophisticated_backpacks.gui.settings_button.context_backpack=背包設置 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip=該背包的設置 +retro_sophisticated_backpacks.gui.settings_button.context_backpack.tooltip_detail=不受到玩家全局設置影響 +retro_sophisticated_backpacks.gui.settings_button.context_player=Player +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip=Player level settings +retro_sophisticated_backpacks.gui.settings_button.context_player.tooltip_detail=Apply to all backpacks/storages unless overriden +retro_sophisticated_backpacks.gui.settings_button.display_side_front=Show on Front +retro_sophisticated_backpacks.gui.settings_button.display_side_left=Show on Left side +retro_sophisticated_backpacks.gui.settings_button.display_side_right=Show on Right side +retro_sophisticated_backpacks.gui.settings_button.item_display_color=Toggle Color +retro_sophisticated_backpacks.gui.settings_button.item_display_color_detail=Next = Left Click\nPrevious = Right Click +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off=Keep Search Phrase: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.off.tooltip=Backpack / Storage gui clears the search phrase when closed and shows all unfiltered item when open again +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on=Keep Search Phrase: ON +retro_sophisticated_backpacks.gui.settings_button.keep_search_phrase.on.tooltip=Backpack / Storage gui keeps the search phrase and prefills it / filters by it when open again +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off=Keep Tab Open: OFF +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.off.tooltip=Open upgrade tab gets closed when the backpack/storage gui is closed and when the gui is next open all of the tabs are closed +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on=Keep Tab Open: ON +retro_sophisticated_backpacks.gui.settings_button.keep_tab_open.on.tooltip=On close of its gui the backpack/storage records which upgrade tab was last open and opens it when the gui is open next time +retro_sophisticated_backpacks.gui.settings_button.rotate=Rotate +retro_sophisticated_backpacks.gui.settings_button.rotate_detail=Clockwise = Left Click\nCounter-Clockwise = Right Click +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off=Shift Click Into Inventory First +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.off.tooltip=Shift click from storage/inventory will first try to put the stack in inventory/storage and only then into an open tab. +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on=Shift Click Into Open Tab First +retro_sophisticated_backpacks.gui.settings_button.shift_click_open_tab.on.tooltip=Shift click from storage/inventory will first try to put the stack in an open tab and only then into inventory/storage. +retro_sophisticated_backpacks.gui.status.mob_catcher_blocklisted=該生物被禁止捕捉 +retro_sophisticated_backpacks.gui.status.mob_catcher_boss_blocked=不能捕捉Boss +retro_sophisticated_backpacks.gui.status.mob_catcher_captured=已捕捉%s +retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=釋放已捕捉的生物後才能移除生物捕捉升級 +retro_sophisticated_backpacks.gui.status.mob_catcher_hostile_needs_advanced=敵對生物需要高級生物捕捉升級 +retro_sophisticated_backpacks.gui.status.mob_catcher_invalid_entity=該生物不能被捕捉 +retro_sophisticated_backpacks.gui.status.mob_catcher_inventory_blocked=不能捕捉帶有物品欄的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=已捕捉的生物需要高級生物捕捉升級 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=那裡沒有有效的釋放空間 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=沒有空餘的%sx%s槽位區域 +retro_sophisticated_backpacks.gui.status.mob_catcher_no_upgrade=背包沒有生物捕捉升級 +retro_sophisticated_backpacks.gui.status.mob_catcher_not_owner=只有所有者可以捕捉該生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_only_one_allowed=每個背包只能安裝一個生物捕捉升級 +retro_sophisticated_backpacks.gui.status.mob_catcher_passengers_blocked=不能捕捉帶有乘客或載具關係的生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_players_blocked=不能捕捉玩家 +retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=無法在那裡釋放生物 +retro_sophisticated_backpacks.gui.status.mob_catcher_released=已釋放%s +retro_sophisticated_backpacks.gui.status.mob_catcher_too_large=該生物需要%s個槽位,超過此升級允許的上限(%s) +retro_sophisticated_backpacks.gui.tooltip.stack_count=Count: %s + +# Fallbacks for keys used by current code +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_detail=Allows configuring backpack behavior\nOpen tab to modify backpack settings +retro_sophisticated_backpacks.gui.backpack_settings.tooltip_open_detail=Allows configuring backpack behavior\nContext = choose whether changes apply to player or backpack\nToggle buttons change shift-click, tab, search, and access behavior +retro_sophisticated_backpacks.gui.settings_button.display_side_detail=Left click selects next side\nRight click selects previous side +retro_sophisticated_backpacks.gui.pump_input_detail=Pull fluids into the backpack tank +retro_sophisticated_backpacks.gui.pump_output_detail=Push fluids out of the backpack tank +retro_sophisticated_backpacks.gui.pump_fluid_handlers_detail=Allows moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_no_fluid_handlers_detail=Prevents moving fluid through adjacent fluid handlers +retro_sophisticated_backpacks.gui.pump_world_detail=Allows placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_no_world_detail=Prevents placing or draining fluids in the world +retro_sophisticated_backpacks.gui.pump_hand_detail=Allows filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_no_hand_detail=Prevents filling or draining containers held by the player +retro_sophisticated_backpacks.gui.pump_fluid_filter_detail=Click with a fluid container to set this filter\nClick with an empty cursor to clear it From d846d6947283f034fa78bab1aee7295da30560fa Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Fri, 12 Jun 2026 21:43:09 +0800 Subject: [PATCH 09/10] Fix tool swapper behavior and improve GUI - Rework tool swapper selection, manual swap packets, and advanced filter handling - Fix backpack scrollbar width and storage GUI right-edge alignment --- .../capability/BackpackWrapper.kt | 14 +- .../capability/upgrade/IToolSwapperUpgrade.kt | 2 + .../upgrade/ToolSwapperUpgradeWrapper.kt | 167 +++++++++++++++--- .../client/gui/BackpackPanel.kt | 46 ++--- .../client/gui/RSBTextures.kt | 5 + .../widgets/BackpackInventoryScrollWidget.kt | 2 +- .../gui/widgets/BackpackMainSettingsWidget.kt | 23 ++- .../client/gui/widgets/ExpandedTabWidget.kt | 7 +- .../gui/widgets/ItemDisplaySettingsWidget.kt | 1 + .../client/gui/widgets/MemorySettingWidget.kt | 1 + .../gui/widgets/SortingSettingWidget.kt | 1 + .../client/gui/widgets/TabWidget.kt | 2 +- .../client/gui/widgets/slot/BackpackSlot.kt | 3 +- .../upgrade/AdvancedExpandedTabWidget.kt | 3 +- .../widgets/upgrade/AdvancedFilterWidget.kt | 89 +++++----- .../widgets/upgrade/BasicExpandedTabWidget.kt | 13 +- .../gui/widgets/upgrade/BasicFilterWidget.kt | 17 +- .../upgrade/CompactingUpgradeWidget.kt | 10 +- .../widgets/upgrade/MagnetUpgradeWidget.kt | 10 +- .../widgets/upgrade/RefillUpgradeWidget.kt | 2 - .../upgrade/ToolSwapperUpgradeWidget.kt | 44 ++++- .../gui/widgets/upgrade/VoidUpgradeWidget.kt | 14 +- .../common/gui/BackpackContainer.kt | 4 + .../handler/EntityEventHandler.kt | 24 --- .../handler/KeyInputHandler.kt | 27 +++ .../handler/NetworkHandler.kt | 14 ++ .../inventory/BackpackItemStackHandler.kt | 5 + .../network/C2SToolSwapBlockPacket.kt | 77 ++++++++ .../network/C2SToolSwapEntityPacket.kt | 49 +++++ .../proxy/RSBProxy.kt | 8 +- .../lang/en_us.lang | 20 ++- .../lang/es_es.lang | 2 +- .../lang/ja_jp.lang | 2 +- .../lang/ko_kr.lang | 2 +- .../lang/pl_pl.lang | 2 +- .../lang/ru_ru.lang | 2 +- .../lang/zh_cn.lang | 20 ++- .../lang/zh_tw.lang | 2 +- 38 files changed, 527 insertions(+), 209 deletions(-) create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapBlockPacket.kt create mode 100644 src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapEntityPacket.kt diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt index ba246f6..38f4bdd 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/BackpackWrapper.kt @@ -264,7 +264,7 @@ class BackpackWrapper( fun onSlotChanged(slotIndex: Int, fromGui: Boolean = false) { val stack = getStackInSlot(slotIndex) - if (!fromGui || shouldVoidInGui(stack)) { + if (!fromGui || shouldVoidInGui(slotIndex, stack)) { slotsToVoid.add(slotIndex) } if (!fromGui || shouldCompactInGui()) { @@ -364,7 +364,7 @@ class BackpackWrapper( if (slotsToVoid.isNotEmpty()) { for (slot in slotsToVoid.toSet()) { val stack = getStackInSlot(slot) - if (!stack.isEmpty && shouldVoidInGui(stack)) { + if (!stack.isEmpty && shouldVoidInGui(slot, stack)) { extractItem(slot, stack.count, false) } } @@ -538,11 +538,11 @@ class BackpackWrapper( } } - private fun shouldVoidInGui(stack: ItemStack): Boolean = + private fun shouldVoidInGui(slotIndex: Int, stack: ItemStack): Boolean = gatherCapabilityUpgrades(Capabilities.IVOID_UPGRADE_CAPABILITY).any { when (it) { - is VoidUpgradeWrapper -> it.shouldWorkInGui && it.shouldVoid(stack) - is AdvancedVoidUpgradeWrapper -> it.shouldWorkInGui && it.shouldVoid(stack) + is VoidUpgradeWrapper -> it.shouldWorkInGui && it.shouldVoidOverflow(stack, false, hasMatchingStack(slotIndex, stack)) + is AdvancedVoidUpgradeWrapper -> it.shouldWorkInGui && it.shouldVoidOverflow(stack, false, hasMatchingStack(slotIndex, stack)) else -> false } } @@ -559,6 +559,10 @@ class BackpackWrapper( private fun hasMatchingStack(stack: ItemStack): Boolean = backpackItemStackHandler.inventory.any { !it.isEmpty && ItemHandlerHelper.canItemStacksStack(it, stack) } + private fun hasMatchingStack(changedSlot: Int, stack: ItemStack): Boolean = + backpackItemStackHandler.inventory.withIndex() + .any { (slot, storedStack) -> slot != changedSlot && !storedStack.isEmpty && ItemHandlerHelper.canItemStacksStack(storedStack, stack) } + fun matchesStorageContents(stack: ItemStack, matcher: (ItemStack, ItemStack) -> Boolean): Boolean = (0 until slots).any { val storedStack = getStackInSlot(it) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt index 0f008b1..16ef9ec 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/IToolSwapperUpgrade.kt @@ -16,7 +16,9 @@ import net.minecraftforge.common.util.INBTSerializable interface IToolSwapperUpgrade : ISidelessCapabilityProvider, INBTSerializable { fun onBlockClick(player: EntityPlayer, wrapper: BackpackWrapper, pos: BlockPos, state: IBlockState): Boolean = false fun onAttackEntity(player: EntityPlayer, wrapper: BackpackWrapper): Boolean = false + fun canProcessBlockInteract(): Boolean = false fun onBlockInteract(player: EntityPlayer, wrapper: BackpackWrapper, world: World, pos: BlockPos, state: IBlockState): Boolean = false + fun canProcessEntityInteract(): Boolean = false fun onEntityInteract(player: EntityPlayer, wrapper: BackpackWrapper, entity: Entity): Boolean = false override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt index 8ff380e..1265a8e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/capability/upgrade/ToolSwapperUpgradeWrapper.kt @@ -12,44 +12,67 @@ import net.minecraft.block.material.Material import net.minecraft.block.state.IBlockState import net.minecraft.entity.Entity import net.minecraft.entity.SharedMonsterAttributes +import net.minecraft.entity.passive.EntityAnimal +import net.minecraft.entity.passive.EntityCow import net.minecraft.entity.player.EntityPlayer import net.minecraft.init.Blocks +import net.minecraft.init.Items import net.minecraft.item.ItemAxe +import net.minecraft.item.ItemHoe +import net.minecraft.item.ItemPickaxe +import net.minecraft.item.ItemSpade import net.minecraft.item.ItemShears import net.minecraft.item.ItemStack import net.minecraft.item.ItemSword import net.minecraft.nbt.NBTTagCompound +import net.minecraft.nbt.NBTTagList +import net.minecraft.nbt.NBTTagString import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumHand import net.minecraft.util.math.BlockPos import net.minecraft.world.World import net.minecraftforge.common.IShearable import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.Constants import java.util.LinkedList open class ToolSwapperUpgradeWrapper( private val hasSettingsTab: Boolean = false, private val swapToolOnKeyPress: Boolean = false, ) : BasicUpgradeWrapper(Config.toolSwapperUpgrade.filterSlots, Config.toolSwapperUpgrade.slotsInRow), - IToolSwapperUpgrade { + IToolSwapperUpgrade, IAdvancedFilterable { companion object { private const val SHOULD_SWAP_WEAPON_TAG = "ShouldSwapWeapon" private const val TOOL_SWAP_MODE_TAG = "ToolSwapMode" } + protected open val exposesAdvancedFilter = false override val settingsLangKey = "gui.tool_swapper_settings".asTranslationKey() var shouldSwapWeapon = true var toolSwapMode = ToolSwapMode.ANY + override var matchType = IAdvancedFilterable.MatchType.ITEM + override var oreDictEntries = mutableListOf() + override var ignoreDurability = true + override var ignoreNBT = true private var lastMinedBlock: Block = Blocks.AIR private var toolCacheFor: String? = null private val toolCache = LinkedList() + init { + filterType = IBasicFilterable.FilterType.BLACKLIST + } + + override fun checkFilter(stack: ItemStack): Boolean = + if (exposesAdvancedFilter) enabled && super.checkFilter(stack) + else super.checkFilter(stack) + override fun onBlockClick(player: EntityPlayer, wrapper: BackpackWrapper, pos: BlockPos, state: IBlockState): Boolean { if (!enabled || player.isCreative || player.isSpectator || toolSwapMode == ToolSwapMode.NO_SWAP || state.material == Material.AIR) { return false } val held = player.heldItemMainhand - if (held.item is BackpackItem || (toolSwapMode == ToolSwapMode.ONLY_TOOLS && isWeapon(held, player)) || (!isWeapon(held, player) && isNotTool(held)) || !matchesAllowEmpty(held)) { + if (held.item is BackpackItem || (toolSwapMode == ToolSwapMode.ONLY_TOOLS && isSword(held)) || (!isSword(held) && isNotTool(held)) || !matchesAllowEmpty(held)) { return false } @@ -70,26 +93,30 @@ open class ToolSwapperUpgradeWrapper( } val held = player.heldItemMainhand - if (isWeapon(held, player)) { + if (isSword(held)) { return true } if (held.item is BackpackItem || isNotTool(held) || !matchesAllowEmpty(held)) { return false } - val selectedSlot = findBestWeaponSlot(wrapper, player) ?: return false + val selectedSlot = findBestWeaponSlot(wrapper, player, held) ?: return false return swapMainHandWithBackpackSlot(player, wrapper, selectedSlot) } + override fun canProcessBlockInteract(): Boolean = swapToolOnKeyPress + override fun onBlockInteract(player: EntityPlayer, wrapper: BackpackWrapper, world: World, pos: BlockPos, state: IBlockState): Boolean { if (!enabled || !swapToolOnKeyPress || player.heldItemMainhand.item is BackpackItem) { return false } return tryToSwapTool(player, wrapper, state.block.registryName?.toString()) { - itemWorksOnBlock(world, pos, state, player, it) + itemWorksOnBlock(world, pos, state, it) } } + override fun canProcessEntityInteract(): Boolean = swapToolOnKeyPress + override fun onEntityInteract(player: EntityPlayer, wrapper: BackpackWrapper, entity: Entity): Boolean { if (!enabled || !swapToolOnKeyPress || player.heldItemMainhand.item is BackpackItem) { return false @@ -102,11 +129,17 @@ open class ToolSwapperUpgradeWrapper( var bestSpeed = heldSpeed for (slot in 0 until wrapper.slots) { val stack = wrapper.getStackInSlot(slot) - if (stack.isEmpty || !matchesAllowEmpty(stack) || !isGoodAtBreaking(player, pos, state, stack)) { + if (stack.isEmpty || !matchesAllowEmpty(stack)) { continue } + if (!canHarvestDropsWith(state, stack)) continue + val destroyProgress = getDestroyProgressWith(player, pos, state, stack) val speed = stack.getDestroySpeed(state) - if (speed > bestSpeed || state.getPlayerRelativeBlockHardness(player, player.world, pos) >= 1f) { + if (speed <= 1.5f && destroyProgress < 1f) continue + if (destroyProgress >= 1f) { + return slot + } + if (speed > bestSpeed) { bestSpeed = speed bestSlot = slot } @@ -114,21 +147,28 @@ open class ToolSwapperUpgradeWrapper( return bestSlot } - private fun findBestWeaponSlot(wrapper: BackpackWrapper, player: EntityPlayer): Int? { - var bestSlot: Int? = null - var bestDamage = getAttackDamage(player.heldItemMainhand, player) + private fun findBestWeaponSlot(wrapper: BackpackWrapper, player: EntityPlayer, held: ItemStack): Int? { + var bestSwordSlot: Int? = null + var bestSwordDamage = if (isSword(held)) getAttackDamage(held, player) else 0.0 + var bestAxeSlot: Int? = null + var bestAxeDamage = if (isAxe(held)) getAttackDamage(held, player) else 0.0 for (slot in 0 until wrapper.slots) { val stack = wrapper.getStackInSlot(slot) - if (stack.isEmpty || !matchesAllowEmpty(stack) || !isWeapon(stack, player)) { + if (stack.isEmpty || !matchesAllowEmpty(stack)) { continue } val damage = getAttackDamage(stack, player) - if (damage > bestDamage) { - bestDamage = damage - bestSlot = slot + if (isSword(stack)) { + if (damage > bestSwordDamage) { + bestSwordDamage = damage + bestSwordSlot = slot + } + } else if (isAxe(stack) && damage > bestAxeDamage) { + bestAxeDamage = damage + bestAxeSlot = slot } } - return bestSlot + return bestSwordSlot ?: bestAxeSlot } private fun tryToSwapTool( @@ -192,27 +232,61 @@ open class ToolSwapperUpgradeWrapper( private fun swapMainHandWithBackpackSlot(player: EntityPlayer, wrapper: BackpackWrapper, slot: Int): Boolean { val held = player.heldItemMainhand + val selectedStack = wrapper.getStackInSlot(slot) val tool = wrapper.extractItem(slot, 1, true) - if (tool.isEmpty || (!held.isEmpty && !wrapper.insertStack(held.copy(), true).isEmpty && tool.count != 1)) { + if (tool.isEmpty) { return false } + val canStoreHeld = held.isEmpty || + wrapper.insertStack(held.copy(), true).isEmpty || + (selectedStack.count == 1 && wrapper.backpackItemStackHandler.isItemValid(slot, held)) + if (!canStoreHeld) return false + + val extractedTool = wrapper.extractItem(slot, 1, false) + if (extractedTool.isEmpty) return false - player.setHeldItem(net.minecraft.util.EnumHand.MAIN_HAND, wrapper.extractItem(slot, 1, false)) + player.setHeldItem(EnumHand.MAIN_HAND, extractedTool) + player.inventoryContainer.detectAndSendChanges() if (!held.isEmpty) { - wrapper.insertStack(held.copy(), false) + val remaining = wrapper.insertStack(held.copy(), false) + if (!remaining.isEmpty) { + wrapper.insertItem(slot, remaining, false) + } } return true } private fun isGoodAtBreaking(player: EntityPlayer, pos: BlockPos, state: IBlockState, stack: ItemStack): Boolean = - stack.getDestroySpeed(state) > 1.5f || state.getPlayerRelativeBlockHardness(player, player.world, pos) >= 1f + canHarvestDropsWith(state, stack) && (stack.getDestroySpeed(state) > 1.5f || getDestroyProgressWith(player, pos, state, stack) >= 1f) + + private fun canHarvestDropsWith(state: IBlockState, stack: ItemStack): Boolean = + state.material.isToolNotRequired || stack.canHarvestBlock(state) + + private fun getDestroyProgressWith(player: EntityPlayer, pos: BlockPos, state: IBlockState, stack: ItemStack): Float { + val held = player.heldItemMainhand + player.setHeldItem(EnumHand.MAIN_HAND, stack) + return try { + state.getPlayerRelativeBlockHardness(player, player.world, pos) + } finally { + player.setHeldItem(EnumHand.MAIN_HAND, held) + } + } private fun isNotTool(stack: ItemStack): Boolean = - stack.isEmpty || stack.getDestroySpeed(Blocks.STONE.defaultState) <= 1f && stack.getDestroySpeed(Blocks.DIRT.defaultState) <= 1f && - stack.getDestroySpeed(Blocks.LOG.defaultState) <= 1f && stack.item !is ItemShears && stack.item !is ItemAxe + stack.isEmpty || !isTool(stack) + + private fun isTool(stack: ItemStack): Boolean = + stack.item is ItemAxe || stack.item is ItemHoe || stack.item is ItemPickaxe || stack.item is ItemSpade || + stack.item is ItemShears || stack.item.getToolClasses(stack).isNotEmpty() || + stack.getDestroySpeed(Blocks.STONE.defaultState) > 1f || + stack.getDestroySpeed(Blocks.DIRT.defaultState) > 1f || + stack.getDestroySpeed(Blocks.LOG.defaultState) > 1f + + private fun isSword(stack: ItemStack): Boolean = + stack.item is ItemSword - private fun isWeapon(stack: ItemStack, player: EntityPlayer): Boolean = - stack.item is ItemSword || getAttackDamage(stack, player) > getAttackDamage(ItemStack.EMPTY, player) + private fun isAxe(stack: ItemStack): Boolean = + stack.item is ItemAxe || "axe" in stack.item.getToolClasses(stack) private fun getAttackDamage(stack: ItemStack, player: EntityPlayer): Double { if (stack.isEmpty) { @@ -224,31 +298,69 @@ open class ToolSwapperUpgradeWrapper( return damage } - private fun itemWorksOnBlock(world: World, pos: BlockPos, state: IBlockState, player: EntityPlayer, stack: ItemStack): Boolean { + private fun itemWorksOnBlock(world: World, pos: BlockPos, state: IBlockState, stack: ItemStack): Boolean { if (stack.item is ItemShears && state.block is IShearable) { return (state.block as IShearable).isShearable(stack, world, pos) } - return isGoodAtBreaking(player, pos, state, stack) + if (stack.item is ItemSpade && state.block == Blocks.GRASS && world.isAirBlock(pos.up())) { + return true + } + val harvestTool = state.block.getHarvestTool(state) + return harvestTool != null && harvestTool in stack.item.getToolClasses(stack) } private fun itemWorksOnEntity(entity: Entity, stack: ItemStack): Boolean = - stack.item is ItemShears && entity is IShearable && entity.isShearable(stack, entity.world, entity.position) + stack.item is ItemShears && entity is IShearable && entity.isShearable(stack, entity.world, entity.position) || + entity is EntityCow && stack.item == Items.BUCKET || + entity is EntityAnimal && stack.item == Items.LEAD override fun serializeNBT(): NBTTagCompound { val nbt = super.serializeNBT() nbt.setBoolean(SHOULD_SWAP_WEAPON_TAG, shouldSwapWeapon) nbt.setByte(TOOL_SWAP_MODE_TAG, toolSwapMode.ordinal.toByte()) + if (exposesAdvancedFilter) { + nbt.setByte(IAdvancedFilterable.MATCH_TYPE_TAG, matchType.ordinal.toByte()) + nbt.setBoolean(IAdvancedFilterable.IGNORE_DURABILITY_TAG, ignoreDurability) + nbt.setBoolean(IAdvancedFilterable.IGNORE_NBT_TAG, ignoreNBT) + val oreDictList = NBTTagList() + for (entry in oreDictEntries) { + oreDictList.appendTag(NBTTagString(entry)) + } + nbt.setTag(IAdvancedFilterable.ORE_DICT_LIST_TAG, oreDictList) + } return nbt } override fun deserializeNBT(nbt: NBTTagCompound) { super.deserializeNBT(nbt) + if (filterItems.inventory.all(ItemStack::isEmpty) && filterType == IBasicFilterable.FilterType.WHITELIST) { + filterType = IBasicFilterable.FilterType.BLACKLIST + } shouldSwapWeapon = !nbt.hasKey(SHOULD_SWAP_WEAPON_TAG) || nbt.getBoolean(SHOULD_SWAP_WEAPON_TAG) - toolSwapMode = ToolSwapMode.entries.getOrElse(nbt.getByte(TOOL_SWAP_MODE_TAG).toInt()) { ToolSwapMode.ANY } + if (nbt.hasKey(TOOL_SWAP_MODE_TAG)) { + toolSwapMode = ToolSwapMode.entries.getOrElse(nbt.getByte(TOOL_SWAP_MODE_TAG).toInt()) { ToolSwapMode.ANY } + } + if (nbt.hasKey(IAdvancedFilterable.MATCH_TYPE_TAG)) { + matchType = IAdvancedFilterable.MatchType.entries.getOrElse(nbt.getByte(IAdvancedFilterable.MATCH_TYPE_TAG).toInt()) { matchType } + } + if (nbt.hasKey(IAdvancedFilterable.IGNORE_DURABILITY_TAG)) { + ignoreDurability = nbt.getBoolean(IAdvancedFilterable.IGNORE_DURABILITY_TAG) + } + if (nbt.hasKey(IAdvancedFilterable.IGNORE_NBT_TAG)) { + ignoreNBT = nbt.getBoolean(IAdvancedFilterable.IGNORE_NBT_TAG) + } + if (nbt.hasKey(IAdvancedFilterable.ORE_DICT_LIST_TAG)) { + val oreDictList = nbt.getTagList(IAdvancedFilterable.ORE_DICT_LIST_TAG, Constants.NBT.TAG_STRING) + oreDictEntries.clear() + for (stringNBT in oreDictList) { + oreDictEntries.add((stringNBT as NBTTagString).string) + } + } } override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = capability == Capabilities.TOOL_SWAPPER_UPGRADE_CAPABILITY || + exposesAdvancedFilter && capability == Capabilities.ADVANCED_FILTERABLE_CAPABILITY || capability == Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY || super.hasCapability(capability, facing) @@ -256,6 +368,7 @@ open class ToolSwapperUpgradeWrapper( } class AdvancedToolSwapperUpgradeWrapper : ToolSwapperUpgradeWrapper(true, true) { + override val exposesAdvancedFilter = true override val settingsLangKey = "gui.advanced_tool_swapper_settings".asTranslationKey() override fun hasCapability(capability: Capability<*>, facing: EnumFacing?): Boolean = diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt index 71a18b1..e70e3ca 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/BackpackPanel.kt @@ -167,6 +167,8 @@ class BackpackPanel( var isItemDisplaySettingTabOpened: Boolean = false var currentItemDisplaySelectedSlot: Int = -1 private set + internal val isSlotSettingTabOpened: Boolean + get() = isMemorySettingTabOpened || isSortingSettingTabOpened || isItemDisplaySettingTabOpened private lateinit var backpackSettingTabWidget: TabWidget private lateinit var memorySettingTabWidget: TabWidget private lateinit var sortingSettingTabWidget: TabWidget @@ -187,7 +189,6 @@ class BackpackPanel( field = value if (value) { - resetTabState() closeUpgradeTabs(syncToServer = true) tabWidgets.forEach { it.isEnabled = false } closeSettingTabs() @@ -693,21 +694,18 @@ class BackpackPanel( override fun draw(context: ModularGuiContext, widgetTheme: WidgetThemeEntry<*>) { currentTheme = widgetTheme.theme - } - - override fun drawForeground(context: ModularGuiContext) { if (isSettingMode) { return } GlStateManager.color(1f, 1f, 1f, 1f) val visualWidth = visualWidth() - val visualX = area.x + area.width - visualWidth - Gui.drawRect(visualX, area.y, visualX + visualWidth, area.y + area.height, 0xFF777777.toInt()) + val visualX = visualX() + Gui.drawRect(visualX, 0, visualX + visualWidth, area.height, 0xFF777777.toInt()) if (!isFocused() && textField.text.isEmpty()) { RSBTextures.SEARCH_ICON.draw( context, visualX, - area.y, + 0, SEARCH_BOX_MIN_WIDTH, SEARCH_BOX_HEIGHT, currentTheme @@ -716,7 +714,6 @@ class BackpackPanel( drawTextField() } GlStateManager.color(1f, 1f, 1f, 1f) - super.drawForeground(context) } override fun onMousePressed(mouseButton: Int): Interactable.Result { @@ -777,17 +774,17 @@ class BackpackPanel( private fun visualX(): Int = area.width - visualWidth() - override fun textFieldX(): Int = area.x + visualX() + 1 + override fun textFieldX(): Int = visualX() + 1 - override fun textFieldY(): Int = area.y + 1 + override fun textFieldY(): Int = 1 override fun textFieldWidth(): Int = visualWidth() - 6 override fun textFieldHeight(): Int = SEARCH_BOX_HEIGHT - override fun mouseXForTextField(): Int = area.x + context.mouseX + override fun mouseXForTextField(): Int = context.mouseX - override fun mouseYForTextField(): Int = area.y + context.mouseY + override fun mouseYForTextField(): Int = context.mouseY private fun animateWidth() { val target = if (isFocused() || textField.text.isNotEmpty()) area.width else SEARCH_BOX_MIN_WIDTH @@ -813,6 +810,7 @@ class BackpackPanel( val inventoryArea = SlotGroupWidget().disableSortButtons() .size(inventoryAreaWidth, storageInventoryHeight) .pos(STORAGE_INVENTORY_X, STORAGE_INVENTORY_Y) + .setEnabledIf { !isSettingMode || isSlotSettingTabOpened } inventoryArea.child( if (inventoryScrollbarWidth > 0) BackpackInventoryScrollWidget(this).pos(0, 0) @@ -882,7 +880,7 @@ class BackpackPanel( val backToBackpackTab = BackToBackpackTabWidget() .setEnabledIfAndEnabled({ isSettingMode }, false) - backpackSettingTabWidget = TabWidget(1).name("backpack_setting_tab") + backpackSettingTabWidget = TabWidget(2).name("backpack_setting_tab") backpackSettingTabWidget.isEnabled = false backpackSettingTabWidget.expandedWidget = BackpackMainSettingsWidget(this, backpackSettingTabWidget) backpackSettingTabWidget.tabIcon = RSBTextures.BACKPACK_SETTINGS_ICON @@ -899,7 +897,7 @@ class BackpackPanel( .pos(RichTooltip.Pos.NEXT_TO_MOUSE) } - sortingSettingTabWidget = TabWidget(2).name("sorting_setting_tab") + sortingSettingTabWidget = TabWidget(3).name("sorting_setting_tab") sortingSettingTabWidget.isEnabled = false sortingSettingTabWidget.expandedWidget = SortingSettingWidget(this, sortingSettingTabWidget) sortingSettingTabWidget.tabIcon = RSBTextures.NO_SORT_ICON @@ -916,7 +914,7 @@ class BackpackPanel( .pos(RichTooltip.Pos.NEXT_TO_MOUSE) } - memorySettingTabWidget = TabWidget(3).name("memory_setting_tab") + memorySettingTabWidget = TabWidget(4).name("memory_setting_tab") memorySettingTabWidget.isEnabled = false memorySettingTabWidget.expandedWidget = MemorySettingWidget(this, memorySettingTabWidget) memorySettingTabWidget.tabIcon = RSBTextures.BRAIN_ICON @@ -933,7 +931,7 @@ class BackpackPanel( .pos(RichTooltip.Pos.NEXT_TO_MOUSE) } - itemDisplaySettingTabWidget = TabWidget(4).name("item_display_setting_tab") + itemDisplaySettingTabWidget = TabWidget(5).name("item_display_setting_tab") itemDisplaySettingTabWidget.isEnabled = false itemDisplaySettingTabWidget.expandedWidget = ItemDisplaySettingsWidget(this, itemDisplaySettingTabWidget) itemDisplaySettingTabWidget.tabIcon = RSBTextures.ITEM_DISPLAY_SETTINGS_ICON @@ -1156,8 +1154,6 @@ class BackpackPanel( var tabIndex = 0 var openedTabIndex: Int? = null - resetTabState() - for (slotIndex in 0 until backpackWrapper.upgradeSlotsSize()) { val stack: ItemStack = backpackWrapper.upgradeItemStackHandler.getStackInSlot(slotIndex) val item = stack.item @@ -1364,7 +1360,7 @@ class BackpackPanel( } is AdvancedToolSwapperUpgradeWrapper -> { - upgradeSlotGroup.updateFilterDelegate(wrapper) + upgradeSlotGroup.updateAdvancedFilterDelegate(wrapper) if (updateAndCheckRecreation( tabWidget.expandedWidget, wrapper @@ -1444,7 +1440,6 @@ class BackpackPanel( } } - tabWidget.expandedWidget?.let { context.recipeViewerSettings.addExclusionArea(it) } tabIndex++ tabDisplayIndex++ } @@ -1466,17 +1461,6 @@ class BackpackPanel( scheduleResize() } - private fun resetTabState() { - if (!isValid) - return - - for (tabWidget in tabWidgets) { - if (tabWidget.expandedWidget != null) { - context.recipeViewerSettings.removeExclusionArea(tabWidget.expandedWidget) - } - } - } - private fun disableUnusedTabWidgets(startTabIndex: Int) { for (i in startTabIndex until backpackWrapper.upgradeSlotsSize()) { clearUpgradeTab(tabWidgets[i]) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt index 6afcc51..461020a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/RSBTextures.kt @@ -63,6 +63,11 @@ object RSBTextures { val JUKEBOX_NO_REPEAT_ICON = icon("jukebox_no_repeat", 160, 80) val JUKEBOX_NEXT_ICON = icon("jukebox_next", 32, 96) val JUKEBOX_PREVIOUS_ICON = icon("jukebox_previous", 48, 96) + val TOOL_SWAPPER_SWAP_WEAPON_ICON = icon("tool_swapper_swap_weapon", 32, 64) + val TOOL_SWAPPER_DO_NOT_SWAP_WEAPON_ICON = icon("tool_swapper_do_not_swap_weapon", 48, 64) + val TOOL_SWAPPER_SWAP_TOOLS_ICON = icon("tool_swapper_swap_tools", 64, 64) + val TOOL_SWAPPER_ONLY_TOOLS_ICON = icon("tool_swapper_only_tools", 80, 64) + val TOOL_SWAPPER_NO_SWAP_ICON = icon("tool_swapper_no_swap", 96, 64) val ANVIL_NAME_BACKGROUND = controlIcon(28, 99, 100, 16) val ANVIL_NAME_BACKGROUND_DISABLED = controlIcon(28, 115, 100, 16) val ANVIL_PLUS_SIGN = controlIcon(113, 203, 13, 13) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt index 3f5dbd3..d9e219c 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackInventoryScrollWidget.kt @@ -38,7 +38,7 @@ class BackpackInventoryScrollWidget(panel: BackpackPanel) : } companion object { - const val SCROLLBAR_WIDTH = 4 + const val SCROLLBAR_WIDTH = 6 private const val SLOT_SIZE = 18 fun createSlots(panel: BackpackPanel, visibleRows: Int): SlotGroupWidget { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt index f91e112..c35d479 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/BackpackMainSettingsWidget.kt @@ -25,7 +25,8 @@ class BackpackMainSettingsWidget( 3, RSBTextures.BACKPACK_SETTINGS_ICON, "gui.backpack_settings".asTranslationKey(), - width = 93, + width = if (Config.allowOpeningOtherPlayerBackpacks) 81 else 75, + tabHeight = 70, expandDirection = ExpandDirection.RIGHT ) { private val contextButton = ContextButtonWidget(panel.backpackWrapper) @@ -50,7 +51,7 @@ class BackpackMainSettingsWidget( private val shiftClickButton = toggleButton( 4, - 52, + 46, { panel.backpackWrapper.shiftClickIntoOpenTab }, RSBTextures.SHIFT_CLICK_OPEN_TAB_ON, RSBTextures.SHIFT_CLICK_OPEN_TAB_OFF, @@ -59,8 +60,8 @@ class BackpackMainSettingsWidget( panel.backpackWrapper::toggleShiftClickIntoOpenTab ) private val keepTabOpenButton = toggleButton( - 26, - 52, + 22, + 46, { panel.backpackWrapper.keepTabOpen }, RSBTextures.KEEP_TAB_OPEN_ON, RSBTextures.KEEP_TAB_OPEN_OFF, @@ -69,8 +70,8 @@ class BackpackMainSettingsWidget( panel.backpackWrapper::toggleKeepTabOpen ) private val keepSearchPhraseButton = toggleButton( - 48, - 52, + 40, + 46, { panel.backpackWrapper.keepSearchPhrase }, RSBTextures.KEEP_SEARCH_PHRASE_ON, RSBTextures.KEEP_SEARCH_PHRASE_OFF, @@ -79,8 +80,8 @@ class BackpackMainSettingsWidget( panel.backpackWrapper::toggleKeepSearchPhrase ) private val otherPlayerButton = toggleButton( - 70, - 52, + 58, + 46, { panel.backpackWrapper.anotherPlayerCanOpen }, RSBTextures.ANOTHER_PLAYER_CAN_OPEN_ON, RSBTextures.ANOTHER_PLAYER_CAN_OPEN_OFF, @@ -136,7 +137,7 @@ class BackpackMainSettingsWidget( private class ContextButtonWidget(private val wrapper: BackpackWrapper) : ButtonWidget() { init { - size(84, 18) + size(62, 18) } override fun drawBackground(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { @@ -148,9 +149,7 @@ class BackpackMainSettingsWidget( left.draw(context, 0, 0, 16, 18, theme) middle.draw(context, 16, 0, 14, 18, theme) middle.draw(context, 30, 0, 14, 18, theme) - middle.draw(context, 44, 0, 14, 18, theme) - middle.draw(context, 58, 0, 14, 18, theme) - right.draw(context, 68, 0, 16, 18, theme) + right.draw(context, 44, 0, 16, 18, theme) } override fun drawOverlay(context: ModularGuiContext?, widgetTheme: WidgetThemeEntry<*>?) { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt index fea6da0..527de44 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ExpandedTabWidget.kt @@ -17,6 +17,7 @@ abstract class ExpandedTabWidget( delegatedIcon: IDrawable, titleKey: String, width: Int = 75, + tabHeight: Int = coveredTabSize * 30, private val expandDirection: ExpandDirection = ExpandDirection.RIGHT ) : ParentWidget() { companion object { @@ -58,13 +59,17 @@ abstract class ExpandedTabWidget( } width(width) - .height(coveredTabSize * 30) + .height(tabHeight) .background(TAB_TEXTURE) child(upperTabRow) } abstract fun updateTabState() + override fun onInit() { + context.recipeViewerSettings.addExclusionArea(this) + } + override fun dispose() { if (isValid) context.recipeViewerSettings.removeExclusionArea(this) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt index b1ad863..91a13f0 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/ItemDisplaySettingsWidget.kt @@ -23,6 +23,7 @@ class ItemDisplaySettingsWidget( RSBTextures.ITEM_DISPLAY_SETTINGS_ICON, "gui.item_display_settings".asTranslationKey(), width = 75, + tabHeight = 48, expandDirection = ExpandDirection.RIGHT ) { private val rotateButton = DynamicIconButtonWidget({ RSBTextures.ITEM_DISPLAY_ROTATE_ICON }) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt index b8825b5..276b1f4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/MemorySettingWidget.kt @@ -17,6 +17,7 @@ class MemorySettingWidget( RSBTextures.BRAIN_ICON, "gui.memory_settings".asTranslationKey(), width = 75, + tabHeight = 48, expandDirection = ExpandDirection.RIGHT ) { companion object { diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt index d9426a3..e122101 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/SortingSettingWidget.kt @@ -18,6 +18,7 @@ class SortingSettingWidget( RSBTextures.NO_SORT_ICON, "gui.sorting_settings".asTranslationKey(), width = 75, + tabHeight = 48, expandDirection = ExpandDirection.RIGHT ) { private val lockAllButton: ButtonWidget<*> = ButtonWidget() diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt index 8fbca00..46166aa 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/TabWidget.kt @@ -20,7 +20,7 @@ class TabWidget( SingleChildWidget(), Interactable { companion object { val TAB_TEXTURE: TabTexture = GuiTextures.TAB_RIGHT - const val TAB_TOP_OFFSET = 4 + const val TAB_TOP_OFFSET = 0 const val TAB_VERTICAL_SPACE = 1 } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt index ae91681..f44401e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/slot/BackpackSlot.kt @@ -227,7 +227,8 @@ class BackpackSlot(private val panel: BackpackPanel, private val wrapper: Backpa val widgetTheme = widgetThemeEntry?.theme ?: WidgetTheme.getDefault().theme if (isInSettingMode) { - drawSettingStack(context, widgetTheme) + if (panel.isSlotSettingTabOpened) + drawSettingStack(context, widgetTheme) drawSettingOverlays(it, widgetTheme) } else { val slot = slot as? ModularBackpackSlot ?: return diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt index a433460..56b358b 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedExpandedTabWidget.kt @@ -14,7 +14,6 @@ open class AdvancedExpandedTabWidget( filterSyncKey: String = "adv_common_filter", coveredTabSize: Int = 5, width: Int = 100, - upstreamLayout: Boolean = false, contentX: Int = 8, contentY: Int = 28, contentWidth: Int = 88, @@ -25,7 +24,7 @@ open class AdvancedExpandedTabWidget( protected val startingRow: Row = Row() .height(0) .name("starting_row") as Row - protected val filterWidget: AdvancedFilterWidget = AdvancedFilterWidget(slotIndex, wrap, filterSyncKey, upstreamLayout) + protected val filterWidget: AdvancedFilterWidget = AdvancedFilterWidget(slotIndex, wrap, filterSyncKey) .width(filterWidth) .coverChildrenHeight() .name("adv_filter_widget") diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt index aa2b3ff..085061b 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/AdvancedFilterWidget.kt @@ -35,7 +35,6 @@ class AdvancedFilterWidget( slotIndex: Int, var filterableWrapper: IAdvancedFilterable, syncKey: String = "adv_common_filter", - private val upstreamLayout: Boolean = false, ) : ParentWidget() { companion object { private val FILTER_TYPE_VARIANTS = listOf( @@ -108,10 +107,10 @@ class AdvancedFilterWidget( filterTypeButton = CyclicVariantButtonWidget( if (filterableWrapper is IContentsFilterable) CONTENTS_FILTER_TYPE_VARIANTS else FILTER_TYPE_VARIANTS, filterButtonIndex(), - iconOffset = if (upstreamLayout) 1 else 2, - buttonWidth = if (upstreamLayout) 18 else 20, - buttonHeight = if (upstreamLayout) 18 else 20, - hasCustomTexture = upstreamLayout + iconOffset = 1, + buttonWidth = 18, + buttonHeight = 18, + hasCustomTexture = true ) { index -> updateFilterType(index) } @@ -119,10 +118,10 @@ class AdvancedFilterWidget( matchTypeButton = CyclicVariantButtonWidget( MATCH_TYPE_VARIANTS, filterableWrapper.matchType.ordinal, - iconOffset = if (upstreamLayout) 1 else 2, - buttonWidth = if (upstreamLayout) 18 else 20, - buttonHeight = if (upstreamLayout) 18 else 20, - hasCustomTexture = upstreamLayout + iconOffset = 1, + buttonWidth = 18, + buttonHeight = 18, + hasCustomTexture = true ) { filterableWrapper.matchType = IAdvancedFilterable.MatchType.entries[it] if (filterableWrapper.matchType == IAdvancedFilterable.MatchType.ORE_DICT) { @@ -142,10 +141,10 @@ class AdvancedFilterWidget( ignoreDurabilityButton = CyclicVariantButtonWidget( IGNORE_DURABILITY_VARIANTS, if (filterableWrapper.ignoreDurability) 1 else 0, - iconOffset = if (upstreamLayout) 1 else 2, - buttonWidth = if (upstreamLayout) 18 else 20, - buttonHeight = if (upstreamLayout) 18 else 20, - hasCustomTexture = upstreamLayout + iconOffset = 1, + buttonWidth = 18, + buttonHeight = 18, + hasCustomTexture = true ) { filterableWrapper.ignoreDurability = it == 1 updateWrapper() @@ -155,35 +154,38 @@ class AdvancedFilterWidget( ignoreNBTButton = CyclicVariantButtonWidget( IGNORE_NBT_VARIANTS, if (filterableWrapper.ignoreNBT) 1 else 0, - iconOffset = if (upstreamLayout) 1 else 2, - buttonWidth = if (upstreamLayout) 18 else 20, - buttonHeight = if (upstreamLayout) 18 else 20, - hasCustomTexture = upstreamLayout + iconOffset = 1, + buttonWidth = 18, + buttonHeight = 18, + hasCustomTexture = true ) { filterableWrapper.ignoreNBT = it == 1 updateWrapper() } ignoreNBTButton.inEffect = inEffect + val filterSlotCount = filterableWrapper.filterItems.slots + val slotsInRow = if (filterSlotCount > 0) filterableWrapper.slotsInRow.coerceIn(1, filterSlotCount) else 1 + val filterRows = if (filterSlotCount > 0) (filterSlotCount + slotsInRow - 1) / slotsInRow else 1 + val filterWidth = slotsInRow * 18 + val filterHeight = filterRows * 18 + // Buttons val buttonRow = Row() - .size(if (upstreamLayout) 72 else 88, if (upstreamLayout) 18 else 20) - .childPadding(if (upstreamLayout) 0 else 2) - if (!upstreamLayout) { - buttonRow.leftRel(0.5f) - } + .size(filterWidth, 18) + .childPadding(0) val itemBasedConfigButtonRow = Row() - .childPadding(if (upstreamLayout) 0 else 2) - .size(if (upstreamLayout) 36 else 44, if (upstreamLayout) 18 else 20) - .left(if (upstreamLayout) 36 else 44) + .childPadding(0) + .size(36, 18) + .left(36) .child(ignoreDurabilityButton) .child(ignoreNBTButton) .setEnabledIfAndEnabled { filterableWrapper.matchType == IAdvancedFilterable.MatchType.ITEM } .name("item_based_button_list") val addOreDictEntryButton = ButtonWidget() - .size(if (upstreamLayout) 18 else 20, if (upstreamLayout) 18 else 20) + .size(18, 18) .overlay(RSBTextures.ADD_ICON) .onMousePressed { val oreName = oreDictTextField.text @@ -192,7 +194,7 @@ class AdvancedFilterWidget( return@onMousePressed false filterableWrapper.oreDictEntries.add(oreName) - oreDictList.child(OreDictEntryWidget(this, oreName, 77)) + oreDictList.child(OreDictEntryWidget(this, oreName, filterWidth - 11)) oreDictTextField.text = "" updateWrapper() oreDictList.scheduleResize() @@ -206,7 +208,7 @@ class AdvancedFilterWidget( .name("add_ore_dict_button") val removeOreDictEntryButton = ButtonWidget() - .size(if (upstreamLayout) 18 else 20, if (upstreamLayout) 18 else 20) + .size(18, 18) .overlay(RSBTextures.REMOVE_ICON) .onMousePressed { val focusedOreDictEntry = focusedOreDictEntry @@ -226,9 +228,9 @@ class AdvancedFilterWidget( } val oreDictBasedConfigButtonRow = Row() - .size(if (upstreamLayout) 36 else 44, if (upstreamLayout) 18 else 20) - .childPadding(if (upstreamLayout) 0 else 2) - .left(if (upstreamLayout) 36 else 44) + .size(36, 18) + .childPadding(0) + .left(36) .child(addOreDictEntryButton) .child(removeOreDictEntryButton) .setEnabledIfAndEnabled { filterableWrapper.matchType == IAdvancedFilterable.MatchType.ORE_DICT } @@ -244,17 +246,12 @@ class AdvancedFilterWidget( // Item-based configuration widgets val slotGroup = SlotGroupWidget().name("${syncKey}s") slotGroup.coverChildren() - if (!upstreamLayout) { - slotGroup.leftRel(0.5f) - } slotGroup.disableSortButtons() slotGroup.setEnabledIfAndEnabled { (filterableWrapper as? IContentsFilterable)?.contentsFilterType != IContentsFilterable.ContentsFilterType.STORAGE } filterSlots = mutableListOf() - val filterSlotCount = filterableWrapper.filterItems.slots - val slotsInRow = if (filterSlotCount > 0) filterableWrapper.slotsInRow.coerceIn(1, filterSlotCount) else 1 for (i in 0 until filterSlotCount) { val slot = PhantomItemSlot().syncHandler("${syncKey}_$slotIndex", i).pos(i % slotsInRow * 18, i / slotsInRow * 18) as PhantomItemSlot @@ -264,18 +261,15 @@ class AdvancedFilterWidget( } itemBasedConfigurationGroup = Column() - .size(if (upstreamLayout) 72 else 88, 85) - .top(if (upstreamLayout) 21 else 24) + .size(filterWidth, filterHeight) + .top(21) .child(slotGroup) .setEnabledIfAndEnabled { filterableWrapper.matchType != IAdvancedFilterable.MatchType.ORE_DICT } .name("item_based_config_group") as Column - if (!upstreamLayout) { - itemBasedConfigurationGroup.leftRel(0.5f) - } // Ore-dict-based configuration widgets oreDictTextField = TextFieldWidget() - .size(88, 15) + .size(filterWidth, 15) .leftRel(0.5f) .bottom(3) .tooltipDynamic { @@ -304,21 +298,18 @@ class AdvancedFilterWidget( .tooltipAutoUpdate(true) oreDictList = OreDictRegexListWidget() - .size(82, 65) + .size(filterWidth - 6, maxOf(18, filterHeight - 20)) for (entry in filterableWrapper.oreDictEntries) - oreDictList.child(OreDictEntryWidget(this, entry, 77)) + oreDictList.child(OreDictEntryWidget(this, entry, filterWidth - 11)) oreDictBasedConfigurationGroup = Column() - .size(88, 85) - .top(if (upstreamLayout) 21 else 24) + .size(filterWidth, filterHeight) + .top(21) .child(oreDictList) .child(oreDictTextField) .setEnabledIfAndEnabled { filterableWrapper.matchType == IAdvancedFilterable.MatchType.ORE_DICT } .name("ore_dict_based_config_group") as Column - if (!upstreamLayout) { - oreDictBasedConfigurationGroup.leftRel(0.5f) - } child(buttonRow) .child(itemBasedConfigurationGroup) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt index 46f1b88..26cfbd7 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicExpandedTabWidget.kt @@ -16,7 +16,6 @@ open class BasicExpandedTabWidget( filterSyncKey: String = "common_filter", coveredTabSize: Int = 4, width: Int = 75, - upstreamLayout: Boolean = false, contentX: Int = 8, contentY: Int = 28, contentWidth: Int = 64, @@ -29,7 +28,7 @@ open class BasicExpandedTabWidget( protected val startingRow: Row = Row() .height(0) .name("starting_row") as Row - protected val filterWidget: BasicFilterWidget = BasicFilterWidget(wrap, slotIndex, filterSyncKey, upstreamLayout, showFilterButton, slotFactory) + protected val filterWidget: BasicFilterWidget = BasicFilterWidget(wrap, slotIndex, filterSyncKey, showFilterButton, slotFactory) .width(filterWidth) .coverChildrenHeight() .name("filter_widget") @@ -50,3 +49,13 @@ open class BasicExpandedTabWidget( child(column) } } + +internal fun filterTabWidth(slotsInRow: Int): Int = + maxOf(75, 3 + slotsInRow.coerceAtLeast(1) * 18 + 6) + +internal fun filterTabSize(filterSlots: Int, slotsInRow: Int, hasTopButtonRow: Boolean = true, hasFilterButtonRow: Boolean = true): Int { + val columns = slotsInRow.coerceAtLeast(1) + val rows = ((filterSlots.coerceAtLeast(1) + columns - 1) / columns).coerceAtLeast(1) + val bottom = 24 + (if (hasTopButtonRow) 20 else 0) + (if (hasFilterButtonRow) 21 else 0) + rows * 18 + 6 + return ((bottom + 29) / 30).coerceAtLeast(3) +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt index 456a866..429436a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/BasicFilterWidget.kt @@ -17,7 +17,6 @@ class BasicFilterWidget( var filterableWrapper: IBasicFilterable, slotIndex: Int, syncKey: String = "common_filter", - private val upstreamLayout: Boolean = false, private val showFilterButton: Boolean = true, private val slotFactory: (Int, () -> UpgradeSlotSH?) -> PhantomItemSlot = { _, _ -> PhantomItemSlot() } ) : @@ -45,21 +44,17 @@ class BasicFilterWidget( filterTypeButton = CyclicVariantButtonWidget( if (filterableWrapper is IContentsFilterable) CONTENTS_FILTER_TYPE_VARIANTS else FILTER_TYPE_VARIANTS, filterButtonIndex(), - iconOffset = if (upstreamLayout) 1 else 2, - buttonWidth = if (upstreamLayout) 18 else 20, - buttonHeight = if (upstreamLayout) 18 else 20, - hasCustomTexture = upstreamLayout + iconOffset = 1, + buttonWidth = 18, + buttonHeight = 18, + hasCustomTexture = true ) { index -> updateFilterType(index) } - .size(if (upstreamLayout) 18 else 20, if (upstreamLayout) 18 else 20) + .size(18, 18) val slotGroup = SlotGroupWidget().name("${syncKey}s") - slotGroup.coverChildren().top(if (showFilterButton) { - if (upstreamLayout) 21 else 26 - } else { - 0 - }) + slotGroup.coverChildren().top(if (showFilterButton) 21 else 0) slotGroup.disableSortButtons() slotGroup.setEnabledIfAndEnabled { (filterableWrapper as? IContentsFilterable)?.contentsFilterType != IContentsFilterable.ContentsFilterType.STORAGE diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt index 2a798bd..0e384e6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/CompactingUpgradeWidget.kt @@ -15,7 +15,8 @@ class CompactingUpgradeWidget(slotIndex: Int, wrapper: CompactingUpgradeWrapper, wrapper, stack, wrapper.settingsLangKey, - upstreamLayout = true, + coveredTabSize = filterTabSize(wrapper.filterItems.slots, wrapper.slotsInRow), + width = filterTabWidth(wrapper.slotsInRow), contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, @@ -33,7 +34,7 @@ class CompactingUpgradeWidget(slotIndex: Int, wrapper: CompactingUpgradeWrapper, } private fun createCompactModeButton(compactNonUncraftable: Boolean): CyclicVariantButtonWidget = - upstreamButton(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { + tabIconButton(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { wrapper.compactNonUncraftable = !wrapper.compactNonUncraftable slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_NON_UNCRAFTABLE) {} } @@ -45,7 +46,8 @@ class AdvancedCompactingUpgradeWidget(slotIndex: Int, wrapper: AdvancedCompactin wrapper, stack, wrapper.settingsLangKey, - upstreamLayout = true, + coveredTabSize = filterTabSize(wrapper.filterItems.slots, wrapper.slotsInRow), + width = filterTabWidth(wrapper.slotsInRow), contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, @@ -63,7 +65,7 @@ class AdvancedCompactingUpgradeWidget(slotIndex: Int, wrapper: AdvancedCompactin } private fun createCompactModeButton(compactNonUncraftable: Boolean): CyclicVariantButtonWidget = - upstreamButton(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { + tabIconButton(COMPACT_MODE_VARIANTS, if (compactNonUncraftable) 1 else 0) { wrapper.compactNonUncraftable = !wrapper.compactNonUncraftable slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_COMPACT_NON_UNCRAFTABLE) {} } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt index b6ec033..5e61e0a 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/MagnetUpgradeWidget.kt @@ -15,7 +15,8 @@ class MagnetUpgradeWidget(slotIndex: Int, wrapper: MagnetUpgradeWrapper, stack: wrapper, stack, wrapper.settingsLangKey, - upstreamLayout = true, + coveredTabSize = filterTabSize(wrapper.filterItems.slots, wrapper.slotsInRow), + width = filterTabWidth(wrapper.slotsInRow), contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, @@ -29,7 +30,7 @@ class MagnetUpgradeWidget(slotIndex: Int, wrapper: MagnetUpgradeWrapper, stack: } private fun createPickupItemsButton(pickupItems: Boolean): CyclicVariantButtonWidget = - upstreamButton(PICKUP_ITEMS_VARIANTS, if (pickupItems) 0 else 1) { + tabIconButton(PICKUP_ITEMS_VARIANTS, if (pickupItems) 0 else 1) { wrapper.pickupItems = !wrapper.pickupItems slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_MAGNET_PICKUP_ITEMS) {} } @@ -41,7 +42,8 @@ class AdvancedMagnetUpgradeWidget(slotIndex: Int, wrapper: AdvancedMagnetUpgrade wrapper, stack, wrapper.settingsLangKey, - upstreamLayout = true, + coveredTabSize = filterTabSize(wrapper.filterItems.slots, wrapper.slotsInRow), + width = filterTabWidth(wrapper.slotsInRow), contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, @@ -55,7 +57,7 @@ class AdvancedMagnetUpgradeWidget(slotIndex: Int, wrapper: AdvancedMagnetUpgrade } private fun createPickupItemsButton(pickupItems: Boolean): CyclicVariantButtonWidget = - upstreamButton(PICKUP_ITEMS_VARIANTS, if (pickupItems) 0 else 1) { + tabIconButton(PICKUP_ITEMS_VARIANTS, if (pickupItems) 0 else 1) { wrapper.pickupItems = !wrapper.pickupItems slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_MAGNET_PICKUP_ITEMS) {} } diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt index 7948965..402014e 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/RefillUpgradeWidget.kt @@ -24,7 +24,6 @@ class RefillUpgradeWidget(slotIndex: Int, wrapper: RefillUpgradeWrapper, stack: wrapper.settingsLangKey, coveredTabSize = refillCoveredTabSize(wrapper), width = refillTabWidth(wrapper), - upstreamLayout = true, contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, @@ -46,7 +45,6 @@ class AdvancedRefillUpgradeWidget(slotIndex: Int, wrapper: AdvancedRefillUpgrade filterSyncKey = "adv_common_filter", coveredTabSize = refillCoveredTabSize(wrapper), width = refillTabWidth(wrapper), - upstreamLayout = true, contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt index 4eac723..9c1d6e6 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/ToolSwapperUpgradeWidget.kt @@ -10,12 +10,18 @@ import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.item.ItemStack class AdvancedToolSwapperUpgradeWidget(slotIndex: Int, wrapper: AdvancedToolSwapperUpgradeWrapper, stack: ItemStack) : - BasicExpandedTabWidget( + AdvancedExpandedTabWidget( slotIndex, wrapper, stack, wrapper.settingsLangKey, - coveredTabSize = 4 + coveredTabSize = filterTabSize(wrapper.filterItems.slots, wrapper.slotsInRow), + width = filterTabWidth(wrapper.slotsInRow), + contentX = 3, + contentY = 24, + contentWidth = wrapper.slotsInRow * 18, + contentPadding = 0, + filterWidth = wrapper.slotsInRow * 18 ) { init { startingRow @@ -25,13 +31,13 @@ class AdvancedToolSwapperUpgradeWidget(slotIndex: Int, wrapper: AdvancedToolSwap } private fun createSwapWeaponButton(): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(SWAP_WEAPON_VARIANTS, if (wrapper.shouldSwapWeapon) 1 else 0) { + tabIconButton(SWAP_WEAPON_VARIANTS, if (wrapper.shouldSwapWeapon) 1 else 0) { wrapper.shouldSwapWeapon = !wrapper.shouldSwapWeapon slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_TOOL_SWAPPER_SWAP_WEAPON) {} } private fun createToolSwapModeButton(): CyclicVariantButtonWidget = - CyclicVariantButtonWidget(TOOL_SWAP_MODE_VARIANTS, wrapper.toolSwapMode.ordinal) { + tabIconButton(TOOL_SWAP_MODE_VARIANTS, wrapper.toolSwapMode.ordinal) { wrapper.toolSwapMode = ToolSwapMode.entries[it] slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_TOOL_SWAPPER_MODE) { it.writeEnumValue(wrapper.toolSwapMode) @@ -40,12 +46,32 @@ class AdvancedToolSwapperUpgradeWidget(slotIndex: Int, wrapper: AdvancedToolSwap } private val SWAP_WEAPON_VARIANTS = listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_swap_weapon_disabled".asTranslationKey()), RSBTextures.CROSS_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_swap_weapon_enabled".asTranslationKey()), RSBTextures.CHECK_ICON), + CyclicVariantButtonWidget.Variant( + IKey.lang("gui.tool_swapper_swap_weapon_disabled".asTranslationKey()), + RSBTextures.TOOL_SWAPPER_DO_NOT_SWAP_WEAPON_ICON, + listOf(IKey.lang("gui.tool_swapper_swap_weapon_disabled.detail".asTranslationKey()).style(IKey.GRAY)) + ), + CyclicVariantButtonWidget.Variant( + IKey.lang("gui.tool_swapper_swap_weapon_enabled".asTranslationKey()), + RSBTextures.TOOL_SWAPPER_SWAP_WEAPON_ICON, + listOf(IKey.lang("gui.tool_swapper_swap_weapon_enabled.detail".asTranslationKey()).style(IKey.GRAY)) + ), ) private val TOOL_SWAP_MODE_VARIANTS = listOf( - CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_any".asTranslationKey()), RSBTextures.IN_OUT_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_only_tools".asTranslationKey()), RSBTextures.SOLID_UP_ARROW_ICON), - CyclicVariantButtonWidget.Variant(IKey.lang("gui.tool_swapper_no_swap".asTranslationKey()), RSBTextures.CROSS_ICON), + CyclicVariantButtonWidget.Variant( + IKey.lang("gui.tool_swapper_any".asTranslationKey()), + RSBTextures.TOOL_SWAPPER_SWAP_TOOLS_ICON, + listOf(IKey.lang("gui.tool_swapper_any.detail".asTranslationKey()).style(IKey.GRAY)) + ), + CyclicVariantButtonWidget.Variant( + IKey.lang("gui.tool_swapper_only_tools".asTranslationKey()), + RSBTextures.TOOL_SWAPPER_ONLY_TOOLS_ICON, + listOf(IKey.lang("gui.tool_swapper_only_tools.detail".asTranslationKey()).style(IKey.GRAY)) + ), + CyclicVariantButtonWidget.Variant( + IKey.lang("gui.tool_swapper_no_swap".asTranslationKey()), + RSBTextures.TOOL_SWAPPER_NO_SWAP_ICON, + listOf(IKey.lang("gui.tool_swapper_no_swap.detail".asTranslationKey()).style(IKey.GRAY)) + ), ) diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt index b834185..554c9a4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/client/gui/widgets/upgrade/VoidUpgradeWidget.kt @@ -18,7 +18,8 @@ class VoidUpgradeWidget(slotIndex: Int, wrapper: VoidUpgradeWrapper, stack: Item wrapper, stack, wrapper.settingsLangKey, - upstreamLayout = true, + coveredTabSize = filterTabSize(wrapper.filterItems.slots, wrapper.slotsInRow), + width = filterTabWidth(wrapper.slotsInRow), contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, @@ -37,7 +38,7 @@ class VoidUpgradeWidget(slotIndex: Int, wrapper: VoidUpgradeWrapper, stack: Item private fun createVoidTypeButton(current: VoidType, alwaysEnabled: Boolean): CyclicVariantButtonWidget { val voidTypes = allowedVoidTypes(alwaysEnabled) - return upstreamButton(voidTypes.map(::voidVariant), voidTypes.indexOf(current).coerceAtLeast(0)) { index -> + return tabIconButton(voidTypes.map(::voidVariant), voidTypes.indexOf(current).coerceAtLeast(0)) { index -> wrapper.voidType = voidTypes[index] slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_TYPE) { it.writeEnumValue(voidTypes[index]) @@ -52,7 +53,8 @@ class AdvancedVoidUpgradeWidget(slotIndex: Int, wrapper: AdvancedVoidUpgradeWrap wrapper, stack, wrapper.settingsLangKey, - upstreamLayout = true, + coveredTabSize = filterTabSize(wrapper.filterItems.slots, wrapper.slotsInRow), + width = filterTabWidth(wrapper.slotsInRow), contentX = 3, contentY = 24, contentWidth = wrapper.slotsInRow * 18, @@ -71,7 +73,7 @@ class AdvancedVoidUpgradeWidget(slotIndex: Int, wrapper: AdvancedVoidUpgradeWrap private fun createVoidTypeButton(current: VoidType, alwaysEnabled: Boolean): CyclicVariantButtonWidget { val voidTypes = allowedVoidTypes(alwaysEnabled) - return upstreamButton(voidTypes.map(::voidVariant), voidTypes.indexOf(current).coerceAtLeast(0)) { index -> + return tabIconButton(voidTypes.map(::voidVariant), voidTypes.indexOf(current).coerceAtLeast(0)) { index -> wrapper.voidType = voidTypes[index] slotSyncHandler?.syncToServer(UpgradeSlotSH.UPDATE_VOID_TYPE) { it.writeEnumValue(voidTypes[index]) @@ -81,11 +83,11 @@ class AdvancedVoidUpgradeWidget(slotIndex: Int, wrapper: AdvancedVoidUpgradeWrap } internal fun createWorkInGuiButton(shouldWorkInGui: Boolean, toggle: () -> Unit): CyclicVariantButtonWidget = - upstreamButton(WORK_IN_GUI_VARIANTS, if (shouldWorkInGui) 1 else 0) { + tabIconButton(WORK_IN_GUI_VARIANTS, if (shouldWorkInGui) 1 else 0) { toggle() } -internal fun upstreamButton( +internal fun tabIconButton( variants: List, index: Int, updater: CyclicVariantButtonWidget.(Int) -> Unit diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt index 5d72a9f..85f2ba4 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/common/gui/BackpackContainer.kt @@ -101,6 +101,10 @@ class BackpackContainer( } override fun slotClick(slotId: Int, mouseButton: Int, clickTypeIn: ClickType, player: EntityPlayer): ItemStack { + if (slotId >= inventorySlots.size) { + return ItemStack.EMPTY + } + backpackWrapper.isGuiInteractionInProgress = true try { val playerInventory = player.inventory diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt index cc3ccab..07f5a18 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/EntityEventHandler.kt @@ -7,7 +7,6 @@ import com.cleanroommc.retrosophisticatedbackpacks.backpack.BackpackInventoryHel import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.EverlastingUpgradeWrapper -import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IToolSwapperUpgrade import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.mobcatcher.MobCatcherHandler import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiFactory @@ -248,29 +247,6 @@ object EntityEventHandler { } } - if (!player.world.isRemote && forEachBackpack(player) { wrapper -> - wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY) - .filterIsInstance() - .any { it.onEntityInteract(player, wrapper, entity) } - }) { - player.inventoryContainer.detectAndSendChanges() - } - } - - @SubscribeEvent - @JvmStatic - fun onRightClickBlock(event: PlayerInteractEvent.RightClickBlock) { - if (event.world.isRemote) { - return - } - val state = event.world.getBlockState(event.pos) - if (forEachBackpack(event.entityPlayer) { wrapper -> - wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY) - .filterIsInstance() - .any { it.onBlockInteract(event.entityPlayer, wrapper, event.world, event.pos, state) } - }) { - event.entityPlayer.inventoryContainer.detectAndSendChanges() - } } @SubscribeEvent diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt index a52945f..6d52376 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/KeyInputHandler.kt @@ -8,14 +8,19 @@ import com.cleanroommc.retrosophisticatedbackpacks.Tags import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.AdvancedRefillUpgradeWrapper import com.cleanroommc.retrosophisticatedbackpacks.common.gui.PlayerInventoryGuiData +import com.cleanroommc.retrosophisticatedbackpacks.item.BackpackItem import com.cleanroommc.retrosophisticatedbackpacks.network.C2SOpenBackpackPacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SRefillBlockPickPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SToolSwapBlockPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SToolSwapEntityPacket import com.cleanroommc.retrosophisticatedbackpacks.proxy.RSBProxy +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey import net.minecraft.client.Minecraft import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.inventory.IInventory import net.minecraft.item.ItemStack import net.minecraft.util.math.RayTraceResult +import net.minecraft.util.text.TextComponentTranslation import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.gameevent.InputEvent @@ -72,6 +77,10 @@ object KeyInputHandler { } } + if (RSBProxy.ClientProxy.TOOL_SWAP_KEYBIND.isPressed) { + sendToolSwapPacket(mc) + } + if (mc.gameSettings.keyBindPickBlock.isPressed) { sendRefillBlockPickPacket(mc) } @@ -81,11 +90,29 @@ object KeyInputHandler { @JvmStatic fun onMouseInput(event: InputEvent.MouseInputEvent) { val mc = Minecraft.getMinecraft() + if (RSBProxy.ClientProxy.TOOL_SWAP_KEYBIND.isPressed) { + sendToolSwapPacket(mc) + } if (mc.gameSettings.keyBindPickBlock.isPressed) { sendRefillBlockPickPacket(mc) } } + private fun sendToolSwapPacket(mc: Minecraft) { + val player = mc.player ?: return + val target = mc.objectMouseOver ?: return + if (player.heldItemMainhand.item is BackpackItem) { + player.sendStatusMessage(TextComponentTranslation("gui.status.unable_to_swap_tool_for_backpack".asTranslationKey()), true) + return + } + + when (target.typeOfHit) { + RayTraceResult.Type.BLOCK -> NetworkHandler.INSTANCE.sendToServer(C2SToolSwapBlockPacket(target.blockPos)) + RayTraceResult.Type.ENTITY -> target.entityHit?.let { NetworkHandler.INSTANCE.sendToServer(C2SToolSwapEntityPacket(it.entityId)) } + else -> Unit + } + } + private fun sendRefillBlockPickPacket(mc: Minecraft) { val player = mc.player ?: return val target = mc.objectMouseOver ?: return diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt index 29af868..2db3625 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/handler/NetworkHandler.kt @@ -4,6 +4,8 @@ import com.cleanroommc.retrosophisticatedbackpacks.network.C2SOpenBackpackPacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SMobCatcherReleasePacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SRefillBlockPickPacket import com.cleanroommc.retrosophisticatedbackpacks.network.C2SStashToBackpackPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SToolSwapBlockPacket +import com.cleanroommc.retrosophisticatedbackpacks.network.C2SToolSwapEntityPacket import com.cleanroommc.retrosophisticatedbackpacks.network.S2CMobCatcherContentsPacket import net.minecraftforge.fml.common.network.NetworkRegistry import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper @@ -39,6 +41,18 @@ object NetworkHandler { idGenerator.next(), Side.SERVER ) + INSTANCE.registerMessage( + C2SToolSwapBlockPacket.Handler::class.java, + C2SToolSwapBlockPacket::class.java, + idGenerator.next(), + Side.SERVER + ) + INSTANCE.registerMessage( + C2SToolSwapEntityPacket.Handler::class.java, + C2SToolSwapEntityPacket::class.java, + idGenerator.next(), + Side.SERVER + ) INSTANCE.registerMessage( C2SMobCatcherReleasePacket.Handler::class.java, C2SMobCatcherReleasePacket::class.java, diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt index 8553034..3bbcace 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/inventory/BackpackItemStackHandler.kt @@ -23,6 +23,11 @@ class BackpackItemStackHandler(size: Int, private val wrapper: BackpackWrapper) override fun getStackLimit(slotIndex: Int, stack: ItemStack): Int = wrapper.getStackLimit(stack) + override fun setStackInSlot(slot: Int, stack: ItemStack) { + super.setStackInSlot(slot, stack) + if (wrapper.shouldHandleSlotChangeFromGui()) wrapper.onGuiSlotChanged(slot) + } + /** * Prioritize insertion by tries inserting on memorized slot first. * diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapBlockPacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapBlockPacket.kt new file mode 100644 index 0000000..7a170c4 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapBlockPacket.kt @@ -0,0 +1,77 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import baubles.api.BaublesApi +import com.cleanroommc.retrosophisticatedbackpacks.RetroSophisticatedBackpacks +import com.cleanroommc.retrosophisticatedbackpacks.capability.BackpackWrapper +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IToolSwapperUpgrade +import com.cleanroommc.retrosophisticatedbackpacks.util.Utils.asTranslationKey +import io.netty.buffer.ByteBuf +import net.minecraft.entity.player.EntityPlayerMP +import net.minecraft.util.math.BlockPos +import net.minecraft.util.text.TextComponentTranslation +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext +import net.minecraftforge.items.IItemHandler +import net.minecraftforge.items.wrapper.InvWrapper + +class C2SToolSwapBlockPacket() : IRefinedMessage { + private var pos = BlockPos.ORIGIN + + constructor(pos: BlockPos) : this() { + this.pos = pos.toImmutable() + } + + override fun toBytes(buf: ByteBuf) { + buf.writeLong(pos.toLong()) + } + + override fun fromBytes(buf: ByteBuf) { + pos = BlockPos.fromLong(buf.readLong()) + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: C2SToolSwapBlockPacket, ctx: MessageContext): IRefinedMessage? { + val player = ctx.serverHandler.player + player.serverWorld.addScheduledTask { + val state = player.world.getBlockState(message.pos) + var anyUpgradeCanInteract = false + var result = false + + ToolSwapPacketHelper.runOnBackpacks(player) { wrapper -> + for (upgrade in wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY).filterIsInstance()) { + if (!upgrade.canProcessBlockInteract() || result) continue + anyUpgradeCanInteract = true + result = upgrade.onBlockInteract(player, wrapper, player.world, message.pos, state) + } + result + } + + when { + !anyUpgradeCanInteract -> ToolSwapPacketHelper.sendStatus(player, "gui.status.no_tool_swap_upgrade_present") + !result -> ToolSwapPacketHelper.sendStatus(player, "gui.status.no_tool_found_for_block") + else -> player.inventoryContainer.detectAndSendChanges() + } + } + return null + } + } +} + +internal object ToolSwapPacketHelper { + fun runOnBackpacks(player: EntityPlayerMP, action: (BackpackWrapper) -> Boolean): Boolean { + if (runOnBackpacksIn(InvWrapper(player.inventory), action)) return true + return RetroSophisticatedBackpacks.baublesLoaded && runOnBackpacksIn(BaublesApi.getBaublesHandler(player), action) + } + + fun sendStatus(player: EntityPlayerMP, langKey: String) { + player.sendStatusMessage(TextComponentTranslation(langKey.asTranslationKey()), true) + } + + private fun runOnBackpacksIn(inventory: IItemHandler, action: (BackpackWrapper) -> Boolean): Boolean { + for (slot in 0 until inventory.slots) { + val wrapper = inventory.getStackInSlot(slot).getCapability(Capabilities.BACKPACK_CAPABILITY, null) ?: continue + if (action(wrapper)) return true + } + return false + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapEntityPacket.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapEntityPacket.kt new file mode 100644 index 0000000..bfd3269 --- /dev/null +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/network/C2SToolSwapEntityPacket.kt @@ -0,0 +1,49 @@ +package com.cleanroommc.retrosophisticatedbackpacks.network + +import com.cleanroommc.retrosophisticatedbackpacks.capability.Capabilities +import com.cleanroommc.retrosophisticatedbackpacks.capability.upgrade.IToolSwapperUpgrade +import io.netty.buffer.ByteBuf +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext + +class C2SToolSwapEntityPacket() : IRefinedMessage { + private var entityId = -1 + + constructor(entityId: Int) : this() { + this.entityId = entityId + } + + override fun toBytes(buf: ByteBuf) { + buf.writeInt(entityId) + } + + override fun fromBytes(buf: ByteBuf) { + entityId = buf.readInt() + } + + class Handler : INoReplyMessageHandler { + override fun onMessage(message: C2SToolSwapEntityPacket, ctx: MessageContext): IRefinedMessage? { + val player = ctx.serverHandler.player + player.serverWorld.addScheduledTask { + val entity = player.world.getEntityByID(message.entityId) ?: return@addScheduledTask + var anyUpgradeCanInteract = false + var result = false + + ToolSwapPacketHelper.runOnBackpacks(player) { wrapper -> + for (upgrade in wrapper.gatherCapabilityUpgrades(Capabilities.ITOOL_SWAPPER_UPGRADE_CAPABILITY).filterIsInstance()) { + if (!upgrade.canProcessEntityInteract() || result) continue + anyUpgradeCanInteract = true + result = upgrade.onEntityInteract(player, wrapper, entity) + } + result + } + + when { + !anyUpgradeCanInteract -> ToolSwapPacketHelper.sendStatus(player, "gui.status.no_tool_swap_upgrade_present") + !result -> ToolSwapPacketHelper.sendStatus(player, "gui.status.no_tool_found_for_entity") + else -> player.inventoryContainer.detectAndSendChanges() + } + } + return null + } + } +} diff --git a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt index b306298..43f4b24 100644 --- a/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt +++ b/src/main/kotlin/com/cleanroommc/retrosophisticatedbackpacks/proxy/RSBProxy.kt @@ -61,7 +61,7 @@ abstract class RSBProxy { class ClientProxy : RSBProxy() { companion object { private val KEYBINDS: List by lazy { - listOf(OPEN_BACKPACK_KEYBIND) + listOf(OPEN_BACKPACK_KEYBIND, TOOL_SWAP_KEYBIND) } val OPEN_BACKPACK_KEYBIND = KeyBinding( @@ -69,6 +69,12 @@ abstract class RSBProxy { Keyboard.KEY_B, "key.category".asTranslationKey() ) + + val TOOL_SWAP_KEYBIND = KeyBinding( + "key.tool_swap.desc".asTranslationKey(), + Keyboard.KEY_NONE, + "key.category".asTranslationKey() + ) } diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang index 02763ff..620433a 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/en_us.lang @@ -31,6 +31,7 @@ itemGroup.retro_sophisticated_backpacks.creative_tab=Retro Sophisticated Backpac # Keybinds retro_sophisticated_backpacks.key.open_backpack.desc=Opens Backpack in Inventory +retro_sophisticated_backpacks.key.tool_swap.desc=Swap Tool Based on Current Block/Entity retro_sophisticated_backpacks.key.category=Retro Sophisticated Backpacks # Tooltips @@ -283,10 +284,19 @@ retro_sophisticated_backpacks.gui.jukebox_repeat_all=Repeat All retro_sophisticated_backpacks.gui.jukebox_repeat_one=Repeat One retro_sophisticated_backpacks.gui.jukebox_repeat_no=Repeat Disabled retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=Do Not Swap Weapons +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled.detail=Keeps the held item when attacking entities retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=Swap Weapons -retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item -retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools -retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled.detail=Swaps to the best weapon when attacking entities +retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_any.detail=Swaps an appropriate tool into hand when holding a weapon or another tool +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap For Other Tools +retro_sophisticated_backpacks.gui.tool_swapper_only_tools.detail=Swaps only when holding another tool, not when holding a weapon +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Swap Tools +retro_sophisticated_backpacks.gui.tool_swapper_no_swap.detail=Tools are never swapped into hand +retro_sophisticated_backpacks.gui.status.unable_to_swap_tool_for_backpack=Unable to swap tool with backpack in hand. Switch to a different item or empty hand. +retro_sophisticated_backpacks.gui.status.no_tool_found_for_block=No tool found that works on block +retro_sophisticated_backpacks.gui.status.no_tool_found_for_entity=No tool found that works on entity +retro_sophisticated_backpacks.gui.status.no_tool_swap_upgrade_present=No upgrade present that can swap tools on key press retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=Click to release retro_sophisticated_backpacks.gui.status.mob_catcher_contains_mobs=Release captured mobs before removing Mob Catcher Upgrade retro_sophisticated_backpacks.gui.status.mob_catcher_mobs_need_advanced=Captured mobs require Advanced Mob Catcher Upgrade @@ -307,7 +317,7 @@ retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=No empty %sx%s slo retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=Could not release mob there retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=No valid release space there -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Compacts items into their compressed variants\nBoth 2x2 and 3x3 recipes with more filtering options item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Deposits items from backpack into sneak right clicked inventory\nHas more filtering options item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=Feeds player with food from backpack's inventory\nMore options for when food gets fed to player @@ -319,7 +329,7 @@ item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=Makes backpac item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=Pumps Fluids between Tank upgrade and adjacent blocks\nWorks with fluid containers in hand and fluid blocks in world\nAllows to filter which fluids are pumped item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=Keeps refilling stack of selected items in player's inventory\nAllows for more precise target slot selection\nAlso allows middle click picking blocks from backpack item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=Restocks backpack from sneak right clicked inventory\nHas more filtering options -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=Automatically swaps item in player's hand for the one effective on the block/entity when left clicked\nHas filter options and extra interaction support +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=Automatically swaps item in player's hand for the one effective on the block/entity when left clicked\nHas filter options and supports manual swaps with the Tool Swap key item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=Voids items selected in filter\nHas more filtering options item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=Anvil in an upgrade tab item.retro_sophisticated_backpacks.battery_upgrade.tooltip=Replaces part of backpack's inventory with energy storage diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang index 350823a..9695f2d 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/es_es.lang @@ -134,7 +134,7 @@ retro_sophisticated_backpacks.gui.sorting_settings.tooltip=Configuración de ran retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Permite seleccionar ranuras que son ignoradas por el ordenamiento\nAbre la pestaña para modificar la configuración de las ranuras retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Permite seleccionar ranuras que son ignoradas por el ordenamiento\nSeleccionar todo / Deseleccionar todo = botones\nSeleccionar ranura = clic izquierdo/arrastrar\nDeseleccionar ranura = clic derecho/arrastrar -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Compacta objetos en sus variantes comprimidas\nRecetas 2x2 y 3x3 con más opciones de filtrado item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=Mejora de depósito avanzada item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Deposita objetos de la mochila en el inventario al que se le hace clic derecho agachado\nTiene más opciones de filtrado diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang index 49425fa..fd2570e 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ja_jp.lang @@ -233,7 +233,7 @@ retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=圧縮できるアイテムを自動で圧縮します。\n3x3で圧縮するアイテムにも対応。 item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=スニークで右クリックしたチェストにアイテムを収納します。\nアイテムフィルタの数が増えます。 item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=リュック内の食料を自動で食べます。\n食事のタイミングを指定可能。 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang index 360006b..6fce32e 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ko_kr.lang @@ -241,7 +241,7 @@ retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=아이템을 압축할 수 있게 됩니다.\n2x2와 3x3 제작법을 사용할 수 있고, 필터 옵션이 추가됩니다. item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=저장소에다 웅크리고 우클릭하면 배낭의 아이템을 저장소로 꺼낼 수 있게 됩니다.\n필터 옵션이 추가됩니다. item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=플레이어에게 배낭 속 음식을 먹일 수 있게 됩니다.\n설정 옵션이 추가됩니다. diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang index 3af57c8..2c7024c 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/pl_pl.lang @@ -179,7 +179,7 @@ retro_sophisticated_backpacks.gui.sorting_settings.tooltip=No Sort Slot Settings retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Allows selecting slots that are ignored by sorting\nOpen tab to modify slot settings retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Allows selecting slots that are ignored by sorting\nSelect all / Unselect all = buttons\nSelect slot = left click/drag\nUnselect slot = right click/drag -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Kompaktuje przedmioty\nzarówno crafting 2x2 jak i 3x3 z większą ilością opcji filtrujących item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=Zaawansowane ulepszenie depozytu item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Umieszcza przedmioty z plecaka do wybranego inwentarza skradając się i klikając prawy przycisk myszy, trzymając plecak w ręce\nma więcej opcji filtrowania diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang index 427b59b..df64631 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/ru_ru.lang @@ -134,7 +134,7 @@ retro_sophisticated_backpacks.gui.sorting_settings.tooltip=Настройки и retro_sophisticated_backpacks.gui.sorting_settings.tooltip_detail=Позволяют задавать слоты для их исключения из сортировки\nОткройте вкладку для дальнейшей настройки retro_sophisticated_backpacks.gui.sorting_settings.tooltip_open_detail=Позволяют задавать слоты для их исключения из сортировки\nВыделить все слоты или снять всё выделение = отдельные клавиши\nВыделить слот = нажмите или зажмите ЛКМ\nСнять выделение со слота = нажмите или зажмите ПКМ -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=Упаковывает предметы в их сжатые варианты\nПоддерживает рецепты 2×2 и 3×3, а также имеет больше настроек фильтрации item.retro_sophisticated_backpacks.advanced_deposit_upgrade.name=Продвинутое улучшение «Разгрузка» item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=Выгружает предметы из рюкзака во внешний инвентарь при нажатии Shift + ПКМ\nИмеет больше настроек фильтрации diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang index 64da7b6..077ba4f 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_cn.lang @@ -31,6 +31,7 @@ itemGroup.retro_sophisticated_backpacks.creative_tab=复古精妙背包 # Keybinds retro_sophisticated_backpacks.key.open_backpack.desc=在物品栏中打开背包 +retro_sophisticated_backpacks.key.tool_swap.desc=基于所指方块/实体替换工具 retro_sophisticated_backpacks.key.category=复古精妙背包 # Tooltips @@ -280,10 +281,19 @@ retro_sophisticated_backpacks.gui.jukebox_repeat_all=全部循环 retro_sophisticated_backpacks.gui.jukebox_repeat_one=单曲循环 retro_sophisticated_backpacks.gui.jukebox_repeat_no=关闭循环 retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled=不切换武器 +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_disabled.detail=攻击实体时保留手持物品 retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled=切换武器 -retro_sophisticated_backpacks.gui.tool_swapper_any=切换任意物品 -retro_sophisticated_backpacks.gui.tool_swapper_only_tools=仅切换工具 -retro_sophisticated_backpacks.gui.tool_swapper_no_swap=不自动切换工具 +retro_sophisticated_backpacks.gui.tool_swapper_swap_weapon_enabled.detail=攻击实体时切换为最合适的武器 +retro_sophisticated_backpacks.gui.tool_swapper_any=替换工具 +retro_sophisticated_backpacks.gui.tool_swapper_any.detail=手持武器或工具时,将合适的工具替换到手上 +retro_sophisticated_backpacks.gui.tool_swapper_only_tools=只由工具替换工具 +retro_sophisticated_backpacks.gui.tool_swapper_only_tools.detail=仅在手持工具时替换,手持武器不替换 +retro_sophisticated_backpacks.gui.tool_swapper_no_swap=不替换工具 +retro_sophisticated_backpacks.gui.tool_swapper_no_swap.detail=永远不会将工具替换到手上 +retro_sophisticated_backpacks.gui.status.unable_to_swap_tool_for_backpack=手持背包时无法替换工具。切换为空手或切换至其他物品 +retro_sophisticated_backpacks.gui.status.no_tool_found_for_block=没有适用于该方块的工具 +retro_sophisticated_backpacks.gui.status.no_tool_found_for_entity=没有适用于该实体的工具 +retro_sophisticated_backpacks.gui.status.no_tool_swap_upgrade_present=当前没有可进行手动工具替换的升级卡 item.retro_sophisticated_backpacks.mob_catcher_upgrade.name=生物捕捉升级 item.retro_sophisticated_backpacks.advanced_mob_catcher_upgrade.name=高级生物捕捉升级 retro_sophisticated_backpacks.gui.mob_catcher.click_to_release=点击释放 @@ -306,7 +316,7 @@ retro_sophisticated_backpacks.gui.status.mob_catcher_no_space=没有空余的%sx retro_sophisticated_backpacks.gui.status.mob_catcher_release_failed=无法在那里释放生物 retro_sophisticated_backpacks.gui.status.mob_catcher_no_release_space=那里没有有效的释放空间 -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=将物品压制为对应的压缩变体\n包括2x2,3x3配方以及更多的过滤选项 item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=手持背包 Shift 右击容器卸载物品\n更多的过滤选项 item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=将背包内的食物喂给玩家\n更多喂食条件选项 @@ -318,7 +328,7 @@ item.retro_sophisticated_backpacks.advanced_pickup_upgrade.tooltip=使背包捡 item.retro_sophisticated_backpacks.advanced_pump_upgrade.tooltip=在储罐升级和相邻方块之间泵送流体\n适用于手持流体容器和世界中的流体方块\n允许过滤泵送的流体 item.retro_sophisticated_backpacks.advanced_refill_upgrade.tooltip=使所选物品在玩家物品栏中自动补充至一组\n更精准的目标槽位选择\n可使用鼠标中键从背包中选取方块 item.retro_sophisticated_backpacks.advanced_restock_upgrade.tooltip=手持背包潜行右击容器提取物品\n更多的过滤选项 -item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=左击时自动将玩家手持物品替换为对应方块/实体的挖掘或攻击工具\n具有过滤选项和额外交互支持 +item.retro_sophisticated_backpacks.advanced_tool_swapper_upgrade.tooltip=左击时自动将玩家手持物品替换为对应方块/实体的挖掘或攻击工具\n具有过滤选项,并可使用工具替换按键手动替换 item.retro_sophisticated_backpacks.advanced_void_upgrade.tooltip=销毁过滤器中选定的物品\n更多的过滤选项 item.retro_sophisticated_backpacks.anvil_upgrade.tooltip=在升级标签页中添加一个铁砧 item.retro_sophisticated_backpacks.battery_upgrade.tooltip=将部分背包空间替换为能量存储空间 diff --git a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang index b29f541..d1c66c8 100644 --- a/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang +++ b/src/main/resources/assets/retro_sophisticated_backpacks/lang/zh_tw.lang @@ -241,7 +241,7 @@ retro_sophisticated_backpacks.gui.tool_swapper_any=Swap Any Item retro_sophisticated_backpacks.gui.tool_swapper_only_tools=Only Swap Tools retro_sophisticated_backpacks.gui.tool_swapper_no_swap=Do Not Auto Swap Tools -# Upstream-aligned tooltips and GUI text +# Tooltips and GUI text item.retro_sophisticated_backpacks.advanced_compacting_upgrade.tooltip=將物品壓縮為對應的壓縮變體\n包括2x2,3x3配方以及更多的過濾選項 item.retro_sophisticated_backpacks.advanced_deposit_upgrade.tooltip=手持背包 Shift 右擊容器卸載物品\n更多的過濾選項 item.retro_sophisticated_backpacks.advanced_feeding_upgrade.tooltip=將背包內的食物餵給玩家\n更多的過濾選項 From 6f0796890635256d9e5b1202fd0a087703aebae0 Mon Sep 17 00:00:00 2001 From: zzhalex233 Date: Fri, 12 Jun 2026 22:07:02 +0800 Subject: [PATCH 10/10] README.md --- README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2607f1a..683aa86 100644 --- a/README.md +++ b/README.md @@ -41,11 +41,18 @@ Here is a list of implemented feature and considered features to be implemented: - [x] deposit upgrade (b/a) - [x] restock upgrade (b/a) - [x] filter upgrade (b/a) -- [ ] magnet upgrade (b/a) -- [ ] void upgrade (b/a) +- [x] magnet upgrade (b/a) +- [x] void upgrade (b/a) +- [x] refill_upgrade (b/a) +- [x] compacting_upgrade (b/a) - [x] crafting upgrade -- [ ] everlasting upgrade -- [ ] jukebox upgrade (low priority) +- [x] everlasting upgrade +- [x] tool_swapper_upgrade (b/a) +- [x] jukebox upgrade (low priority) +- [x] tank_upgrade +- [x] pump_upgrade (b/a) +- [x] battery_upgrade +- [x] mob_catcher_upgrade (b/a) ## Disclaimer