diff --git a/src/generated/resources/assets/ae2/lang/en_us.json b/src/generated/resources/assets/ae2/lang/en_us.json index 9397f882fa1..fefdb63003d 100644 --- a/src/generated/resources/assets/ae2/lang/en_us.json +++ b/src/generated/resources/assets/ae2/lang/en_us.json @@ -217,6 +217,7 @@ "chat.ae2.ClickToTeleport": "Click to teleport into plot", "chat.ae2.CommunicationError": "Error Communicating with Network.", "chat.ae2.CompassTestSection": "Section [y=%d-%d] %d: %b", + "chat.ae2.CraftingCpuBusy": "This crafting CPU is busy!", "chat.ae2.DeviceNotLinked": "Device is not linked.", "chat.ae2.DeviceNotPowered": "Device is low on power.", "chat.ae2.InvalidMachine": "Could not load configuration from an incompatible device.", diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_16k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_16k.json new file mode 100644 index 00000000000..45c4d4faa60 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_16k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:fluid_storage_cell_16k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_16k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_1k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_1k.json new file mode 100644 index 00000000000..62e5d604eae --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_1k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:fluid_storage_cell_1k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_1k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_256k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_256k.json new file mode 100644 index 00000000000..49c718d0849 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_256k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:fluid_storage_cell_256k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_256k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_4k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_4k.json new file mode 100644 index 00000000000..8b92896d118 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_4k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:fluid_storage_cell_4k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_4k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_64k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_64k.json new file mode 100644 index 00000000000..5f4f1bbd7ce --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/fluid_storage_cell_64k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:fluid_storage_cell_64k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_64k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_16k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_16k.json new file mode 100644 index 00000000000..e5e28753f8f --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_16k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:item_storage_cell_16k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_16k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_1k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_1k.json new file mode 100644 index 00000000000..2b0ba63cc13 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_1k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:item_storage_cell_1k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_1k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_256k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_256k.json new file mode 100644 index 00000000000..228808191fc --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_256k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:item_storage_cell_256k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_256k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_4k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_4k.json new file mode 100644 index 00000000000..869e71f2882 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_4k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:item_storage_cell_4k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_4k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_64k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_64k.json new file mode 100644 index 00000000000..e967ba4c375 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/item_storage_cell_64k.json @@ -0,0 +1,14 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:item_storage_cell_64k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_64k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_16k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_16k.json new file mode 100644 index 00000000000..a85f4d2f7fc --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_16k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_fluid_cell_16k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_16k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_1k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_1k.json new file mode 100644 index 00000000000..66bf3bf7f4b --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_1k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_fluid_cell_1k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_1k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_256k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_256k.json new file mode 100644 index 00000000000..5b9136abe55 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_256k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_fluid_cell_256k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_256k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_4k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_4k.json new file mode 100644 index 00000000000..6c3521b4a82 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_4k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_fluid_cell_4k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_4k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_64k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_64k.json new file mode 100644 index 00000000000..f19c86d6589 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_fluid_cell_64k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_fluid_cell_64k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:fluid_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_64k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_16k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_16k.json new file mode 100644 index 00000000000..eabc28743ca --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_16k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_item_cell_16k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_16k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_1k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_1k.json new file mode 100644 index 00000000000..f15662511e5 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_1k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_item_cell_1k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_1k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_256k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_256k.json new file mode 100644 index 00000000000..aea549c09ea --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_256k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_item_cell_256k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_256k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_4k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_4k.json new file mode 100644 index 00000000000..11f8e8c487f --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_4k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_item_cell_4k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_4k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_64k.json b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_64k.json new file mode 100644 index 00000000000..d8d31f28547 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/cell_upgrade/portable_item_cell_64k.json @@ -0,0 +1,22 @@ +{ + "type": "ae2:storage_cell_disassembly", + "cell": "ae2:portable_item_cell_64k", + "cell_disassembly_items": [ + { + "count": 1, + "id": "ae2:chest" + }, + { + "count": 1, + "id": "ae2:energy_cell" + }, + { + "count": 1, + "id": "ae2:item_cell_housing" + }, + { + "count": 1, + "id": "ae2:cell_component_64k" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/16k_crafting_storage.json b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/16k_crafting_storage.json new file mode 100644 index 00000000000..6d3438470de --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/16k_crafting_storage.json @@ -0,0 +1,5 @@ +{ + "type": "ae2:crafting_unit_transform", + "upgrade_item": "ae2:cell_component_16k", + "upgraded_block": "ae2:16k_crafting_storage" +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/1k_crafting_storage.json b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/1k_crafting_storage.json new file mode 100644 index 00000000000..4c2d0de81b5 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/1k_crafting_storage.json @@ -0,0 +1,5 @@ +{ + "type": "ae2:crafting_unit_transform", + "upgrade_item": "ae2:cell_component_1k", + "upgraded_block": "ae2:1k_crafting_storage" +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/256k_crafting_storage.json b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/256k_crafting_storage.json new file mode 100644 index 00000000000..1dd3d7d70a7 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/256k_crafting_storage.json @@ -0,0 +1,5 @@ +{ + "type": "ae2:crafting_unit_transform", + "upgrade_item": "ae2:cell_component_256k", + "upgraded_block": "ae2:256k_crafting_storage" +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/4k_crafting_storage.json b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/4k_crafting_storage.json new file mode 100644 index 00000000000..3bdadc7117a --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/4k_crafting_storage.json @@ -0,0 +1,5 @@ +{ + "type": "ae2:crafting_unit_transform", + "upgrade_item": "ae2:cell_component_4k", + "upgraded_block": "ae2:4k_crafting_storage" +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/64k_crafting_storage.json b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/64k_crafting_storage.json new file mode 100644 index 00000000000..ef693cd28a3 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/64k_crafting_storage.json @@ -0,0 +1,5 @@ +{ + "type": "ae2:crafting_unit_transform", + "upgrade_item": "ae2:cell_component_64k", + "upgraded_block": "ae2:64k_crafting_storage" +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/crafting_accelerator.json b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/crafting_accelerator.json new file mode 100644 index 00000000000..226c76d1cd1 --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/crafting_accelerator.json @@ -0,0 +1,5 @@ +{ + "type": "ae2:crafting_unit_transform", + "upgrade_item": "ae2:engineering_processor", + "upgraded_block": "ae2:crafting_accelerator" +} \ No newline at end of file diff --git a/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/crafting_monitor.json b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/crafting_monitor.json new file mode 100644 index 00000000000..586c1a5f52c --- /dev/null +++ b/src/generated/resources/data/ae2/recipe/crafting_unit_upgrade/crafting_monitor.json @@ -0,0 +1,5 @@ +{ + "type": "ae2:crafting_unit_transform", + "upgrade_item": "ae2:storage_monitor", + "upgraded_block": "ae2:crafting_monitor" +} \ No newline at end of file diff --git a/src/main/java/appeng/block/crafting/AbstractCraftingUnitBlock.java b/src/main/java/appeng/block/crafting/AbstractCraftingUnitBlock.java index 83a18903c85..341e7029b21 100644 --- a/src/main/java/appeng/block/crafting/AbstractCraftingUnitBlock.java +++ b/src/main/java/appeng/block/crafting/AbstractCraftingUnitBlock.java @@ -18,26 +18,41 @@ package appeng.block.crafting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; +import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.phys.BlockHitResult; import appeng.block.AEBaseEntityBlock; import appeng.blockentity.crafting.CraftingBlockEntity; +import appeng.core.definitions.AEBlocks; +import appeng.core.localization.PlayerMessages; import appeng.menu.MenuOpener; import appeng.menu.locator.MenuLocators; import appeng.menu.me.crafting.CraftingCPUMenu; +import appeng.recipes.game.CraftingUnitTransformRecipe; +import appeng.util.InteractionUtil; public abstract class AbstractCraftingUnitBlock extends AEBaseEntityBlock { + private static final Logger LOG = LoggerFactory.getLogger(AbstractCraftingUnitBlock.class); + public static final BooleanProperty FORMED = BooleanProperty.create("formed"); public static final BooleanProperty POWERED = BooleanProperty.create("powered"); @@ -92,6 +107,12 @@ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState new @Override protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + if (InteractionUtil.isInAlternateUseMode(player)) { + var result = this.removeUpgrade(level, player, pos, AEBlocks.CRAFTING_UNIT.block().defaultBlockState()); + if (result != InteractionResult.FAIL) + return result; + } + if (level.getBlockEntity(pos) instanceof CraftingBlockEntity be && be.isFormed() && be.isActive()) { if (!level.isClientSide()) { MenuOpener.open(CraftingCPUMenu.TYPE, player, MenuLocators.forBlockEntity(be)); @@ -102,4 +123,98 @@ protected InteractionResult useWithoutItem(BlockState state, Level level, BlockP return super.useWithoutItem(state, level, pos, player, hitResult); } + + @Override + protected ItemInteractionResult useItemOn(ItemStack heldItem, BlockState state, Level level, BlockPos pos, + Player player, InteractionHand hand, BlockHitResult hit) { + if (this.upgrade(heldItem, state, level, pos, player, hit)) + return ItemInteractionResult.sidedSuccess(level.isClientSide()); + return super.useItemOn(heldItem, state, level, pos, player, hand, hit); + } + + public boolean upgrade(ItemStack heldItem, BlockState state, Level level, BlockPos pos, Player player, + BlockHitResult hit) { + if (heldItem.isEmpty()) { + return false; + } + + var upgradedBlock = CraftingUnitTransformRecipe.getUpgradedBlock(level, heldItem); + if (upgradedBlock == null) { + return false; + } + + if (!(upgradedBlock instanceof AbstractCraftingUnitBlock)) { + LOG.warn("Upgraded block for crafting unit upgrade with {} is not a crafting block: {}", + heldItem, upgradedBlock); + return false; + } + + if (upgradedBlock == state.getBlock()) { + return false; + } + + // If Upgrading is possible - but disassembly isn't, this will still make the hand animation play. + if (level.isClientSide()) { + return true; + } + + var newState = upgradedBlock.defaultBlockState(); + + // Makes sure Crafting Monitors are looking at the player. + newState = newState.trySetValue(BlockStateProperties.FACING, hit.getDirection()); + + // Crafting Unit doesn't have a disassembly recipe, so we can ignore the drops. + InteractionResult result = state.getBlock() == AEBlocks.CRAFTING_UNIT.block() + ? this.transform(level, pos, newState) ? InteractionResult.SUCCESS : InteractionResult.FAIL + : this.removeUpgrade(level, player, pos, newState); + + if (result == InteractionResult.FAIL) + return false; + // Pass => Crafting Unit is busy! + if (result == InteractionResult.PASS) + return true; + heldItem.consume(1, player); + return true; + } + + public InteractionResult removeUpgrade(Level level, Player player, BlockPos pos, BlockState newState) { + if (this.type == CraftingUnitType.UNIT || level.isClientSide()) + return InteractionResult.FAIL; + + var removedUpgrade = CraftingUnitTransformRecipe.getRemovedUpgrade(level, this); + if (removedUpgrade.isEmpty()) { + return InteractionResult.FAIL; + } + + var cb = this.getBlockEntity(level, pos); + if (cb != null && cb.getCluster() != null && cb.getCluster().isBusy()) { + player.displayClientMessage(PlayerMessages.CraftingCpuBusy.text().withColor(0xFF1F1F), true); + return InteractionResult.PASS; + } + + if (!this.transform(level, pos, newState)) { + return InteractionResult.FAIL; + } + + player.getInventory().placeItemBackInInventory(removedUpgrade); + + return InteractionResult.SUCCESS; + } + + private boolean transform(Level level, BlockPos pos, BlockState state) { + if (level.isClientSide() || !level.removeBlock(pos, false) || !level.setBlock(pos, state, UPDATE_ALL)) { + return false; + } + + level.playSound( + null, + pos.getX(), + pos.getY(), + pos.getZ(), + SoundEvents.ITEM_FRAME_REMOVE_ITEM, + SoundSource.BLOCKS, + 0.5f, + 1f); + return true; + } } diff --git a/src/main/java/appeng/block/crafting/CraftingBlockItem.java b/src/main/java/appeng/block/crafting/CraftingBlockItem.java index 13d6e4b800a..8a4c5c70fec 100644 --- a/src/main/java/appeng/block/crafting/CraftingBlockItem.java +++ b/src/main/java/appeng/block/crafting/CraftingBlockItem.java @@ -18,49 +18,46 @@ package appeng.block.crafting; -import java.util.function.Supplier; - import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import appeng.block.AEBaseBlockItem; -import appeng.core.AEConfig; import appeng.core.definitions.AEBlocks; +import appeng.recipes.game.CraftingUnitTransformRecipe; import appeng.util.InteractionUtil; /** * Item that allows uncrafting CPU parts by disassembling them back into the crafting unit and the extra item. */ public class CraftingBlockItem extends AEBaseBlockItem { - /** - * This can be retrieved when disassembling the crafting unit. - */ - protected final Supplier disassemblyExtra; - - public CraftingBlockItem(Block id, Properties props, Supplier disassemblyExtra) { + public CraftingBlockItem(Block id, Properties props) { super(id, props); - this.disassemblyExtra = disassemblyExtra; } @Override public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { - if (AEConfig.instance().isDisassemblyCraftingEnabled() && InteractionUtil.isInAlternateUseMode(player)) { - int itemCount = player.getItemInHand(hand).getCount(); + if (InteractionUtil.isInAlternateUseMode(player)) { + ItemStack stack = player.getItemInHand(hand); + + var removedUpgrade = CraftingUnitTransformRecipe.getRemovedUpgrade(level, getBlock()); + if (removedUpgrade.isEmpty()) { + return super.use(level, player, hand); + } + + int itemCount = stack.getCount(); player.setItemInHand(hand, ItemStack.EMPTY); - player.getInventory().placeItemBackInInventory(AEBlocks.CRAFTING_UNIT.stack(itemCount)); - player.getInventory().placeItemBackInInventory(new ItemStack(disassemblyExtra.get(), itemCount)); + var inv = player.getInventory(); + inv.placeItemBackInInventory(removedUpgrade.copyWithCount(removedUpgrade.getCount() * itemCount)); + // This is hard-coded, as this is always a base block. + inv.placeItemBackInInventory(AEBlocks.CRAFTING_UNIT.stack(itemCount)); return InteractionResultHolder.sidedSuccess(player.getItemInHand(hand), level.isClientSide()); } return super.use(level, player, hand); } - - private void disassemble(ItemStack stack, Player player) { - } } diff --git a/src/main/java/appeng/core/AEConfig.java b/src/main/java/appeng/core/AEConfig.java index 8efbca6da60..4ff15161955 100644 --- a/src/main/java/appeng/core/AEConfig.java +++ b/src/main/java/appeng/core/AEConfig.java @@ -299,10 +299,6 @@ public boolean isTinyTntBlockDamageEnabled() { return common.tinyTntBlockDamage.get(); } - public boolean isDisassemblyCraftingEnabled() { - return common.disassemblyCrafting.get(); - } - public int getGrowthAcceleratorSpeed() { return common.growthAcceleratorSpeed.get(); } @@ -341,10 +337,6 @@ public boolean isPlacementPreviewEnabled() { return client.showPlacementPreview.get(); } - public boolean isPortableCellDisassemblyEnabled() { - return common.portableCellDisassembly.get(); - } - // Tooltip settings /** @@ -534,7 +526,6 @@ private static class CommonConfig { public final IntValue pathfindingStepsPerTick; public final BooleanValue spatialAnchorEnableRandomTicks; - public final BooleanValue disassemblyCrafting; public final IntValue growthAcceleratorSpeed; public final BooleanValue annihilationPlaneSkyDustGeneration; @@ -571,9 +562,6 @@ private static class CommonConfig { public final DoubleValue wirelessBoosterExp; public final DoubleValue wirelessHighWirelessCount; - // Portable Cells - public final BooleanValue portableCellDisassembly; - // Power Ratios public final DoubleValue powerRatioForgeEnergy; public final DoubleValue powerUsageMultiplier; @@ -624,8 +612,6 @@ public CommonConfig() { builder.pop(); builder.push("crafting"); - disassemblyCrafting = define(builder, "disassemblyCrafting", true, - "Enable shift-clicking with the crafting units in hand to disassemble them."); growthAcceleratorSpeed = define(builder, "growthAccelerator", 10, 1, 100, "Number of ticks between two crystal growth accelerator ticks"); annihilationPlaneSkyDustGeneration = define(builder, "annihilationPlaneSkyDustGeneration", true, @@ -673,11 +659,6 @@ public CommonConfig() { this.wirelessTerminalDrainMultiplier = define(builder, "wirelessTerminalDrainMultiplier", 1.0); builder.pop(); - builder.push("portableCells"); - portableCellDisassembly = define(builder, "allowDisassembly", true, - "Allow disassembly of portable cells into the recipe ingredients using shift+right-click"); - builder.pop(); - builder.push("powerRatios"); powerRatioForgeEnergy = define(builder, "forgeEnergy", DEFAULT_FE_EXCHANGE); powerUsageMultiplier = define(builder, "usageMultiplier", 1.0, 0.01, Double.MAX_VALUE); diff --git a/src/main/java/appeng/core/definitions/AEBlocks.java b/src/main/java/appeng/core/definitions/AEBlocks.java index 1795c37ec0c..7e41dc3fb88 100644 --- a/src/main/java/appeng/core/definitions/AEBlocks.java +++ b/src/main/java/appeng/core/definitions/AEBlocks.java @@ -37,7 +37,6 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; -import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.RotatedPillarBlock; @@ -187,16 +186,16 @@ public final class AEBlocks { public static final BlockDefinition CREATIVE_ENERGY_CELL = block("Creative Energy Cell", AEBlockIds.CREATIVE_ENERGY_CELL, CreativeEnergyCellBlock::new); public static final BlockDefinition CRAFTING_UNIT = block("Crafting Unit", AEBlockIds.CRAFTING_UNIT, () -> new CraftingUnitBlock(CraftingUnitType.UNIT)); - public static final BlockDefinition CRAFTING_ACCELERATOR = craftingBlock("Crafting Co-Processing Unit", AEBlockIds.CRAFTING_ACCELERATOR, () -> new CraftingUnitBlock(CraftingUnitType.ACCELERATOR), () -> AEItems.ENGINEERING_PROCESSOR); - public static final BlockDefinition CRAFTING_STORAGE_1K = craftingBlock("1k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_1K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_1K), () -> AEItems.CELL_COMPONENT_1K); - public static final BlockDefinition CRAFTING_STORAGE_4K = craftingBlock("4k Crafting Storage",AEBlockIds.CRAFTING_STORAGE_4K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_4K), () -> AEItems.CELL_COMPONENT_4K); - public static final BlockDefinition CRAFTING_STORAGE_16K = craftingBlock("16k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_16K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_16K), () -> AEItems.CELL_COMPONENT_16K); - public static final BlockDefinition CRAFTING_STORAGE_64K = craftingBlock("64k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_64K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_64K), () -> AEItems.CELL_COMPONENT_64K); - public static final BlockDefinition CRAFTING_STORAGE_256K = craftingBlock("256k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_256K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_256K), () -> AEItems.CELL_COMPONENT_256K); - public static final BlockDefinition CRAFTING_MONITOR = craftingBlock("Crafting Monitor",AEBlockIds.CRAFTING_MONITOR, () -> new CraftingMonitorBlock(CraftingUnitType.MONITOR), () -> AEParts.STORAGE_MONITOR); - - private static BlockDefinition craftingBlock(String englishName, ResourceLocation id, Supplier blockSupplier, Supplier disassemblyExtra) { - return block(englishName, id, blockSupplier, (block, props) -> new CraftingBlockItem(block, props, disassemblyExtra)); + public static final BlockDefinition CRAFTING_ACCELERATOR = craftingBlock("Crafting Co-Processing Unit", AEBlockIds.CRAFTING_ACCELERATOR, () -> new CraftingUnitBlock(CraftingUnitType.ACCELERATOR)); + public static final BlockDefinition CRAFTING_STORAGE_1K = craftingBlock("1k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_1K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_1K)); + public static final BlockDefinition CRAFTING_STORAGE_4K = craftingBlock("4k Crafting Storage",AEBlockIds.CRAFTING_STORAGE_4K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_4K)); + public static final BlockDefinition CRAFTING_STORAGE_16K = craftingBlock("16k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_16K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_16K)); + public static final BlockDefinition CRAFTING_STORAGE_64K = craftingBlock("64k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_64K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_64K)); + public static final BlockDefinition CRAFTING_STORAGE_256K = craftingBlock("256k Crafting Storage", AEBlockIds.CRAFTING_STORAGE_256K, () -> new CraftingUnitBlock(CraftingUnitType.STORAGE_256K)); + public static final BlockDefinition CRAFTING_MONITOR = craftingBlock("Crafting Monitor",AEBlockIds.CRAFTING_MONITOR, () -> new CraftingMonitorBlock(CraftingUnitType.MONITOR)); + + private static BlockDefinition craftingBlock(String englishName, ResourceLocation id, Supplier blockSupplier) { + return block(englishName, id, blockSupplier, CraftingBlockItem::new); } public static final BlockDefinition PATTERN_PROVIDER = block("ME Pattern Provider", AEBlockIds.PATTERN_PROVIDER, PatternProviderBlock::new); diff --git a/src/main/java/appeng/core/definitions/AEItems.java b/src/main/java/appeng/core/definitions/AEItems.java index 1decad2dd31..06962eeed84 100644 --- a/src/main/java/appeng/core/definitions/AEItems.java +++ b/src/main/java/appeng/core/definitions/AEItems.java @@ -257,17 +257,17 @@ private static ItemDefinition makePortableFluidCell(ResourceLo public static final ItemDefinition CREATIVE_CELL = item("Creative ME Storage Cell", AEItemIds.CREATIVE_CELL, p -> new CreativeCellItem(p.stacksTo(1).rarity(Rarity.EPIC))); public static final ItemDefinition VIEW_CELL = item("View Cell", AEItemIds.VIEW_CELL, p -> new ViewCellItem(p.stacksTo(1))); - public static final ItemDefinition ITEM_CELL_1K = item("1k ME Item Storage Cell", AEItemIds.ITEM_CELL_1K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_1K, ITEM_CELL_HOUSING, 0.5f, 1, 8, 63, AEKeyType.items())); - public static final ItemDefinition ITEM_CELL_4K = item("4k ME Item Storage Cell", AEItemIds.ITEM_CELL_4K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_4K, ITEM_CELL_HOUSING, 1.0f, 4, 32, 63, AEKeyType.items())); - public static final ItemDefinition ITEM_CELL_16K = item("16k ME Item Storage Cell", AEItemIds.ITEM_CELL_16K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_16K, ITEM_CELL_HOUSING, 1.5f, 16, 128, 63, AEKeyType.items())); - public static final ItemDefinition ITEM_CELL_64K = item("64k ME Item Storage Cell", AEItemIds.ITEM_CELL_64K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_64K, ITEM_CELL_HOUSING, 2.0f, 64, 512, 63, AEKeyType.items())); - public static final ItemDefinition ITEM_CELL_256K = item("256k ME Item Storage Cell", AEItemIds.ITEM_CELL_256K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_256K, ITEM_CELL_HOUSING, 2.5f, 256, 2048, 63, AEKeyType.items())); - - public static final ItemDefinition FLUID_CELL_1K = item("1k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_1K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_1K, FLUID_CELL_HOUSING, 0.5f, 1, 8, 18, AEKeyType.fluids())); - public static final ItemDefinition FLUID_CELL_4K = item("4k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_4K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_4K, FLUID_CELL_HOUSING, 1.0f, 4, 32, 18, AEKeyType.fluids())); - public static final ItemDefinition FLUID_CELL_16K = item("16k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_16K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_16K, FLUID_CELL_HOUSING, 1.5f, 16, 128, 18, AEKeyType.fluids())); - public static final ItemDefinition FLUID_CELL_64K = item("64k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_64K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_64K, FLUID_CELL_HOUSING, 2.0f, 64, 512, 18, AEKeyType.fluids())); - public static final ItemDefinition FLUID_CELL_256K = item("256k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_256K, p -> new BasicStorageCell(p.stacksTo(1), CELL_COMPONENT_256K, FLUID_CELL_HOUSING, 2.5f, 256, 2048, 18, AEKeyType.fluids())); + public static final ItemDefinition ITEM_CELL_1K = item("1k ME Item Storage Cell", AEItemIds.ITEM_CELL_1K, p -> new BasicStorageCell(p.stacksTo(1), 0.5f, 1, 8, 63, AEKeyType.items())); + public static final ItemDefinition ITEM_CELL_4K = item("4k ME Item Storage Cell", AEItemIds.ITEM_CELL_4K, p -> new BasicStorageCell(p.stacksTo(1), 1.0f, 4, 32, 63, AEKeyType.items())); + public static final ItemDefinition ITEM_CELL_16K = item("16k ME Item Storage Cell", AEItemIds.ITEM_CELL_16K, p -> new BasicStorageCell(p.stacksTo(1), 1.5f, 16, 128, 63, AEKeyType.items())); + public static final ItemDefinition ITEM_CELL_64K = item("64k ME Item Storage Cell", AEItemIds.ITEM_CELL_64K, p -> new BasicStorageCell(p.stacksTo(1), 2.0f, 64, 512, 63, AEKeyType.items())); + public static final ItemDefinition ITEM_CELL_256K = item("256k ME Item Storage Cell", AEItemIds.ITEM_CELL_256K, p -> new BasicStorageCell(p.stacksTo(1), 2.5f, 256, 2048, 63, AEKeyType.items())); + + public static final ItemDefinition FLUID_CELL_1K = item("1k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_1K, p -> new BasicStorageCell(p.stacksTo(1), 0.5f, 1, 8, 18, AEKeyType.fluids())); + public static final ItemDefinition FLUID_CELL_4K = item("4k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_4K, p -> new BasicStorageCell(p.stacksTo(1), 1.0f, 4, 32, 18, AEKeyType.fluids())); + public static final ItemDefinition FLUID_CELL_16K = item("16k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_16K, p -> new BasicStorageCell(p.stacksTo(1), 1.5f, 16, 128, 18, AEKeyType.fluids())); + public static final ItemDefinition FLUID_CELL_64K = item("64k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_64K, p -> new BasicStorageCell(p.stacksTo(1), 2.0f, 64, 512, 18, AEKeyType.fluids())); + public static final ItemDefinition FLUID_CELL_256K = item("256k ME Fluid Storage Cell", AEItemIds.FLUID_CELL_256K, p -> new BasicStorageCell(p.stacksTo(1), 2.5f, 256, 2048, 18, AEKeyType.fluids())); public static final ItemDefinition SPATIAL_CELL2 = item("2³ Spatial Storage Cell", AEItemIds.SPATIAL_CELL_2, p -> new SpatialStorageCellItem(p.stacksTo(1), 2)); public static final ItemDefinition SPATIAL_CELL16 = item("16³ Spatial Storage Cell", AEItemIds.SPATIAL_CELL_16, p -> new SpatialStorageCellItem(p.stacksTo(1), 16)); diff --git a/src/main/java/appeng/core/localization/PlayerMessages.java b/src/main/java/appeng/core/localization/PlayerMessages.java index c49c2342e82..8c19fe16228 100644 --- a/src/main/java/appeng/core/localization/PlayerMessages.java +++ b/src/main/java/appeng/core/localization/PlayerMessages.java @@ -26,6 +26,7 @@ public enum PlayerMessages implements LocalizationEnum { ClickToShowDetails("Click to show details"), ClickToTeleport("Click to teleport into plot"), CommunicationError("Error Communicating with Network."), + CraftingCpuBusy("This crafting CPU is busy!"), DeviceNotLinked("Device is not linked."), LinkedNetworkNotFound("Linked network cannot be found"), DeviceNotPowered("Device is low on power."), diff --git a/src/main/java/appeng/datagen/AE2DataGenerators.java b/src/main/java/appeng/datagen/AE2DataGenerators.java index 211edc4a6b6..1748fe1a022 100644 --- a/src/main/java/appeng/datagen/AE2DataGenerators.java +++ b/src/main/java/appeng/datagen/AE2DataGenerators.java @@ -55,6 +55,7 @@ import appeng.datagen.providers.recipes.SmeltingRecipes; import appeng.datagen.providers.recipes.SmithingRecipes; import appeng.datagen.providers.recipes.TransformRecipes; +import appeng.datagen.providers.recipes.UpgradeRecipes; import appeng.datagen.providers.tags.BiomeTagsProvider; import appeng.datagen.providers.tags.BlockTagsProvider; import appeng.datagen.providers.tags.DataComponentTypeTagProvider; @@ -118,6 +119,7 @@ public static void onGatherData(GatherDataEvent event) { pack.addProvider(bindRegistries(TransformRecipes::new, registries)); pack.addProvider(bindRegistries(ChargerRecipes::new, registries)); pack.addProvider(bindRegistries(QuartzCuttingRecipesProvider::new, registries)); + pack.addProvider(bindRegistries(UpgradeRecipes::new, registries)); // Must run last pack.addProvider(packOutput -> localization); diff --git a/src/main/java/appeng/datagen/providers/recipes/CraftingRecipes.java b/src/main/java/appeng/datagen/providers/recipes/CraftingRecipes.java index cfe828951c5..d0fef710960 100644 --- a/src/main/java/appeng/datagen/providers/recipes/CraftingRecipes.java +++ b/src/main/java/appeng/datagen/providers/recipes/CraftingRecipes.java @@ -1,7 +1,6 @@ package appeng.datagen.providers.recipes; -import java.util.List; import java.util.concurrent.CompletableFuture; import net.minecraft.core.HolderLookup; @@ -27,9 +26,6 @@ import appeng.core.definitions.ItemDefinition; import appeng.datagen.providers.tags.ConventionTags; import appeng.items.tools.powered.PortableCellItem; -import appeng.recipes.game.AddItemUpgradeRecipe; -import appeng.recipes.game.RemoveItemUpgradeRecipe; -import appeng.recipes.game.StorageCellUpgradeRecipe; public class CraftingRecipes extends AE2RecipeProvider { public CraftingRecipes(PackOutput output, CompletableFuture registries) { @@ -44,10 +40,6 @@ public String getName() { @Override protected void buildRecipes(RecipeOutput consumer) { - storageCellUpgradeRecipes(consumer); - - itemUpgradeRecipe(consumer); - // ==================================================== // Basic Cards // ==================================================== @@ -902,66 +894,6 @@ protected void buildRecipes(RecipeOutput consumer) { } - record CellUpgradeTier(String suffix, ItemDefinition cell, ItemLike component) { - } - - private void storageCellUpgradeRecipes(RecipeOutput output) { - storageCellUpgradeRecipes(output, List.of( - new CellUpgradeTier("1k", AEItems.ITEM_CELL_1K, AEItems.CELL_COMPONENT_1K), - new CellUpgradeTier("4k", AEItems.ITEM_CELL_4K, AEItems.CELL_COMPONENT_4K), - new CellUpgradeTier("16k", AEItems.ITEM_CELL_16K, AEItems.CELL_COMPONENT_16K), - new CellUpgradeTier("64k", AEItems.ITEM_CELL_64K, AEItems.CELL_COMPONENT_64K), - new CellUpgradeTier("256k", AEItems.ITEM_CELL_256K, AEItems.CELL_COMPONENT_256K))); - storageCellUpgradeRecipes(output, List.of( - new CellUpgradeTier("1k", AEItems.FLUID_CELL_1K, AEItems.CELL_COMPONENT_1K), - new CellUpgradeTier("4k", AEItems.FLUID_CELL_4K, AEItems.CELL_COMPONENT_4K), - new CellUpgradeTier("16k", AEItems.FLUID_CELL_16K, AEItems.CELL_COMPONENT_16K), - new CellUpgradeTier("64k", AEItems.FLUID_CELL_64K, AEItems.CELL_COMPONENT_64K), - new CellUpgradeTier("256k", AEItems.FLUID_CELL_256K, AEItems.CELL_COMPONENT_256K))); - storageCellUpgradeRecipes(output, List.of( - new CellUpgradeTier("1k", AEItems.PORTABLE_ITEM_CELL1K, AEItems.CELL_COMPONENT_1K), - new CellUpgradeTier("4k", AEItems.PORTABLE_ITEM_CELL4K, AEItems.CELL_COMPONENT_4K), - new CellUpgradeTier("16k", AEItems.PORTABLE_ITEM_CELL16K, AEItems.CELL_COMPONENT_16K), - new CellUpgradeTier("64k", AEItems.PORTABLE_ITEM_CELL64K, AEItems.CELL_COMPONENT_64K), - new CellUpgradeTier("256k", AEItems.PORTABLE_ITEM_CELL256K, AEItems.CELL_COMPONENT_256K))); - storageCellUpgradeRecipes(output, List.of( - new CellUpgradeTier("1k", AEItems.PORTABLE_FLUID_CELL1K, AEItems.CELL_COMPONENT_1K), - new CellUpgradeTier("4k", AEItems.PORTABLE_FLUID_CELL4K, AEItems.CELL_COMPONENT_4K), - new CellUpgradeTier("16k", AEItems.PORTABLE_FLUID_CELL16K, AEItems.CELL_COMPONENT_16K), - new CellUpgradeTier("64k", AEItems.PORTABLE_FLUID_CELL64K, AEItems.CELL_COMPONENT_64K), - new CellUpgradeTier("256k", AEItems.PORTABLE_FLUID_CELL256K, AEItems.CELL_COMPONENT_256K))); - } - - private void storageCellUpgradeRecipes(RecipeOutput output, List tiers) { - for (int i = 0; i < tiers.size(); i++) { - var fromTier = tiers.get(i); - var inputCell = fromTier.cell().asItem(); - var inputId = fromTier.cell().id(); - var resultComponent = fromTier.component().asItem(); - - // Allow a direct upgrade to any higher tier - for (int j = i + 1; j < tiers.size(); j++) { - var toTier = tiers.get(j); - var resultCell = toTier.cell().asItem(); - var inputComponent = toTier.component().asItem(); - - var recipeId = inputId.withPath(path -> "upgrade/" + path + "_to_" + toTier.suffix); - - output.accept( - recipeId, - new StorageCellUpgradeRecipe( - inputCell, inputComponent, - resultCell, resultComponent), - null); - } - } - } - - private void itemUpgradeRecipe(RecipeOutput output) { - output.accept(AppEng.makeId("add_item_upgrade"), AddItemUpgradeRecipe.INSTANCE, null); - output.accept(AppEng.makeId("remove_item_upgrade"), RemoveItemUpgradeRecipe.INSTANCE, null); - } - private void portableCell(RecipeOutput consumer, ItemDefinition cell) { ItemDefinition housing; if (cell.get().getKeyType() == AEKeyType.items()) { diff --git a/src/main/java/appeng/datagen/providers/recipes/UpgradeRecipes.java b/src/main/java/appeng/datagen/providers/recipes/UpgradeRecipes.java new file mode 100644 index 00000000000..202f4192670 --- /dev/null +++ b/src/main/java/appeng/datagen/providers/recipes/UpgradeRecipes.java @@ -0,0 +1,159 @@ +package appeng.datagen.providers.recipes; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import net.minecraft.core.HolderLookup; +import net.minecraft.data.PackOutput; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; + +import appeng.core.AppEng; +import appeng.core.definitions.AEBlocks; +import appeng.core.definitions.AEItems; +import appeng.core.definitions.AEParts; +import appeng.core.definitions.BlockDefinition; +import appeng.core.definitions.ItemDefinition; +import appeng.recipes.game.AddItemUpgradeRecipe; +import appeng.recipes.game.CraftingUnitTransformRecipe; +import appeng.recipes.game.RemoveItemUpgradeRecipe; +import appeng.recipes.game.StorageCellDisassemblyRecipe; +import appeng.recipes.game.StorageCellUpgradeRecipe; + +public class UpgradeRecipes extends AE2RecipeProvider { + public UpgradeRecipes(PackOutput output, CompletableFuture registries) { + super(output, registries); + } + + // Defaults will always be Cell Component for upgrade/disassembly. Additional options are for modpack developers. + record UnitTransformTier(BlockDefinition baseBlock, ItemDefinition upgradeItem) { + } + + record CellDisassemblyTier(ItemDefinition cell, ItemDefinition component) { + } + + record CellUpgradeTier(String suffix, ItemDefinition cell, ItemLike component) { + } + + @Override + public void buildRecipes(RecipeOutput consumer) { + itemUpgradeRecipe(consumer); + + // Crafting Unit Transformation + craftingUnitTransform(consumer, List.of( + new UnitTransformTier(AEBlocks.CRAFTING_STORAGE_1K, AEItems.CELL_COMPONENT_1K), + new UnitTransformTier(AEBlocks.CRAFTING_STORAGE_4K, AEItems.CELL_COMPONENT_4K), + new UnitTransformTier(AEBlocks.CRAFTING_STORAGE_16K, AEItems.CELL_COMPONENT_16K), + new UnitTransformTier(AEBlocks.CRAFTING_STORAGE_64K, AEItems.CELL_COMPONENT_64K), + new UnitTransformTier(AEBlocks.CRAFTING_STORAGE_256K, AEItems.CELL_COMPONENT_256K), + new UnitTransformTier(AEBlocks.CRAFTING_ACCELERATOR, AEItems.ENGINEERING_PROCESSOR), + new UnitTransformTier(AEBlocks.CRAFTING_MONITOR, AEParts.STORAGE_MONITOR))); + + storageCellUpgradeRecipes(consumer); + } + + private void storageCellUpgradeRecipes(RecipeOutput output) { + storageCellUpgradeRecipes( + output, + List.of( + new CellUpgradeTier("1k", AEItems.ITEM_CELL_1K, AEItems.CELL_COMPONENT_1K), + new CellUpgradeTier("4k", AEItems.ITEM_CELL_4K, AEItems.CELL_COMPONENT_4K), + new CellUpgradeTier("16k", AEItems.ITEM_CELL_16K, AEItems.CELL_COMPONENT_16K), + new CellUpgradeTier("64k", AEItems.ITEM_CELL_64K, AEItems.CELL_COMPONENT_64K), + new CellUpgradeTier("256k", AEItems.ITEM_CELL_256K, AEItems.CELL_COMPONENT_256K)), + List.of(AEItems.ITEM_CELL_HOUSING)); + storageCellUpgradeRecipes( + output, + List.of( + new CellUpgradeTier("1k", AEItems.FLUID_CELL_1K, AEItems.CELL_COMPONENT_1K), + new CellUpgradeTier("4k", AEItems.FLUID_CELL_4K, AEItems.CELL_COMPONENT_4K), + new CellUpgradeTier("16k", AEItems.FLUID_CELL_16K, AEItems.CELL_COMPONENT_16K), + new CellUpgradeTier("64k", AEItems.FLUID_CELL_64K, AEItems.CELL_COMPONENT_64K), + new CellUpgradeTier("256k", AEItems.FLUID_CELL_256K, AEItems.CELL_COMPONENT_256K)), + List.of(AEItems.FLUID_CELL_HOUSING)); + storageCellUpgradeRecipes( + output, + List.of( + new CellUpgradeTier("1k", AEItems.PORTABLE_ITEM_CELL1K, AEItems.CELL_COMPONENT_1K), + new CellUpgradeTier("4k", AEItems.PORTABLE_ITEM_CELL4K, AEItems.CELL_COMPONENT_4K), + new CellUpgradeTier("16k", AEItems.PORTABLE_ITEM_CELL16K, AEItems.CELL_COMPONENT_16K), + new CellUpgradeTier("64k", AEItems.PORTABLE_ITEM_CELL64K, AEItems.CELL_COMPONENT_64K), + new CellUpgradeTier("256k", AEItems.PORTABLE_ITEM_CELL256K, AEItems.CELL_COMPONENT_256K)), + List.of(AEBlocks.ME_CHEST, AEBlocks.ENERGY_CELL, AEItems.ITEM_CELL_HOUSING)); + storageCellUpgradeRecipes( + output, + List.of( + new CellUpgradeTier("1k", AEItems.PORTABLE_FLUID_CELL1K, AEItems.CELL_COMPONENT_1K), + new CellUpgradeTier("4k", AEItems.PORTABLE_FLUID_CELL4K, AEItems.CELL_COMPONENT_4K), + new CellUpgradeTier("16k", AEItems.PORTABLE_FLUID_CELL16K, AEItems.CELL_COMPONENT_16K), + new CellUpgradeTier("64k", AEItems.PORTABLE_FLUID_CELL64K, AEItems.CELL_COMPONENT_64K), + new CellUpgradeTier("256k", AEItems.PORTABLE_FLUID_CELL256K, AEItems.CELL_COMPONENT_256K)), + List.of(AEBlocks.ME_CHEST, AEBlocks.ENERGY_CELL, AEItems.FLUID_CELL_HOUSING)); + } + + private void storageCellUpgradeRecipes(RecipeOutput output, List tiers, + List additionalDisassemblyItems) { + for (int i = 0; i < tiers.size(); i++) { + var fromTier = tiers.get(i); + var inputCell = fromTier.cell().asItem(); + var inputId = fromTier.cell().id(); + var resultComponent = fromTier.component().asItem(); + + cellDisassembly(output, additionalDisassemblyItems, fromTier); + + // Allow a direct upgrade to any higher tier + for (int j = i + 1; j < tiers.size(); j++) { + var toTier = tiers.get(j); + var resultCell = toTier.cell().asItem(); + var inputComponent = toTier.component().asItem(); + + var recipeId = inputId.withPath(path -> "upgrade/" + path + "_to_" + toTier.suffix); + + output.accept( + recipeId, + new StorageCellUpgradeRecipe( + inputCell, inputComponent, + resultCell, resultComponent), + null); + } + } + } + + private void itemUpgradeRecipe(RecipeOutput output) { + output.accept(AppEng.makeId("add_item_upgrade"), AddItemUpgradeRecipe.INSTANCE, null); + output.accept(AppEng.makeId("remove_item_upgrade"), RemoveItemUpgradeRecipe.INSTANCE, null); + } + + private void cellDisassembly(RecipeOutput consumer, List additionalReturn, CellUpgradeTier tier) { + List results = new ArrayList<>(); + for (var itemLike : additionalReturn) { + results.add(itemLike.asItem().getDefaultInstance()); + } + results.add(tier.component.asItem().getDefaultInstance()); + + consumer.accept( + tier.cell.id().withPrefix("cell_upgrade/"), + new StorageCellDisassemblyRecipe( + tier.cell.asItem(), + results), + null); + } + + private void craftingUnitTransform(RecipeOutput consumer, List tiers) { + for (UnitTransformTier tier : tiers) { + consumer.accept( + tier.baseBlock.id().withPrefix("crafting_unit_upgrade/"), + new CraftingUnitTransformRecipe( + tier.baseBlock.block(), + tier.upgradeItem.asItem()), + null); + } + } + + @Override + public String getName() { + return "AE2 Storage Upgrade/Disassembly Recipes"; + } +} diff --git a/src/main/java/appeng/items/storage/BasicStorageCell.java b/src/main/java/appeng/items/storage/BasicStorageCell.java index 7de8a0d0f00..6b4852daa12 100644 --- a/src/main/java/appeng/items/storage/BasicStorageCell.java +++ b/src/main/java/appeng/items/storage/BasicStorageCell.java @@ -26,13 +26,11 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; -import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; import appeng.api.config.FuzzyMode; @@ -47,16 +45,12 @@ import appeng.hooks.AEToolItem; import appeng.items.AEBaseItem; import appeng.items.contents.CellConfig; +import appeng.recipes.game.StorageCellDisassemblyRecipe; import appeng.util.ConfigInventory; import appeng.util.InteractionUtil; import appeng.util.Platform; public class BasicStorageCell extends AEBaseItem implements IBasicCellItem, AEToolItem { - /** - * This can be retrieved when disassembling the storage cell. - */ - protected final ItemLike coreItem; - protected final ItemLike housingItem; protected final double idleDrain; protected final int totalBytes; protected final int bytesPerType; @@ -64,8 +58,6 @@ public class BasicStorageCell extends AEBaseItem implements IBasicCellItem, AETo private final AEKeyType keyType; public BasicStorageCell(Properties properties, - ItemLike coreItem, - ItemLike housingItem, double idleDrain, int kilobytes, int bytesPerType, @@ -74,8 +66,6 @@ public BasicStorageCell(Properties properties, super(properties); this.idleDrain = idleDrain; this.totalBytes = kilobytes * 1024; - this.coreItem = coreItem; - this.housingItem = housingItem; this.bytesPerType = bytesPerType; this.totalTypes = totalTypes; this.keyType = keyType; @@ -149,36 +139,37 @@ public InteractionResultHolder use(Level level, Player player, Intera } private boolean disassembleDrive(ItemStack stack, Level level, Player player) { - if (InteractionUtil.isInAlternateUseMode(player)) { - if (level.isClientSide()) { - return false; - } - - final Inventory playerInventory = player.getInventory(); - var inv = StorageCells.getCellInventory(stack, null); - if (inv != null && playerInventory.getSelected() == stack) { - var list = inv.getAvailableStacks(); - if (list.isEmpty()) { - playerInventory.setItem(playerInventory.selected, ItemStack.EMPTY); - - // drop core - playerInventory.placeItemBackInInventory(new ItemStack(coreItem)); - - // drop upgrades - for (var upgrade : this.getUpgrades(stack)) { - playerInventory.placeItemBackInInventory(upgrade); - } - - // drop empty storage cell case - playerInventory.placeItemBackInInventory(new ItemStack(housingItem)); - - return true; - } else { - player.displayClientMessage(PlayerMessages.OnlyEmptyCellsCanBeDisassembled.text(), true); - } - } + if (!InteractionUtil.isInAlternateUseMode(player)) { + return false; } - return false; + + var disassembledStacks = StorageCellDisassemblyRecipe.getDisassemblyResult(level, stack.getItem()); + if (disassembledStacks.isEmpty()) { + return false; + } + + var playerInventory = player.getInventory(); + if (playerInventory.getSelected() != stack) { + return false; + } + + var inv = StorageCells.getCellInventory(stack, null); + if (inv != null && !inv.getAvailableStacks().isEmpty()) { + player.displayClientMessage(PlayerMessages.OnlyEmptyCellsCanBeDisassembled.text(), true); + return false; + } + + playerInventory.setItem(playerInventory.selected, ItemStack.EMPTY); + + // Drop items from the recipe. + for (var disassembledStack : disassembledStacks) { + playerInventory.placeItemBackInInventory(disassembledStack.copy()); + } + + // Drop upgrades + getUpgrades(stack).forEach(playerInventory::placeItemBackInInventory); + + return true; } @Override diff --git a/src/main/java/appeng/items/tools/powered/AbstractPortableCell.java b/src/main/java/appeng/items/tools/powered/AbstractPortableCell.java index 4f08df468c7..85b3af1babc 100644 --- a/src/main/java/appeng/items/tools/powered/AbstractPortableCell.java +++ b/src/main/java/appeng/items/tools/powered/AbstractPortableCell.java @@ -11,7 +11,6 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; @@ -25,12 +24,12 @@ import appeng.api.upgrades.Upgrades; import appeng.block.networking.EnergyCellBlockItem; import appeng.core.AEConfig; -import appeng.core.AELog; import appeng.core.localization.PlayerMessages; import appeng.items.contents.PortableCellMenuHost; import appeng.menu.MenuOpener; import appeng.menu.locator.ItemMenuHostLocator; import appeng.menu.locator.MenuLocators; +import appeng.recipes.game.StorageCellDisassemblyRecipe; import appeng.util.InteractionUtil; public abstract class AbstractPortableCell extends PoweredContainerItem @@ -106,55 +105,38 @@ public InteractionResultHolder use(Level level, Player player, Intera } private boolean disassembleDrive(ItemStack stack, Level level, Player player) { - if (!AEConfig.instance().isPortableCellDisassemblyEnabled()) { - return false; - } - - // We refund the crafting recipe ingredients (the first one each) - var recipe = level.getRecipeManager().byKey(getRecipeId()).orElse(null); - if (!(recipe.value() instanceof CraftingRecipe craftingRecipe)) { - AELog.debug("Cannot disassemble portable cell because it's crafting recipe doesn't exist: %s", - getRecipeId()); + var playerInventory = player.getInventory(); + var disassemblyItems = StorageCellDisassemblyRecipe.getDisassemblyResult(level, stack.getItem()); + if (disassemblyItems.isEmpty() || playerInventory.getSelected() != stack || stack.getCount() != 1) { return false; } if (level.isClientSide()) { - return true; - } - - var playerInventory = player.getInventory(); - if (playerInventory.getSelected() != stack) { - return false; + return true; // Further checks cannot be done on the client } var inv = StorageCells.getCellInventory(stack, null); - if (inv == null) { - return false; + if (inv != null && !inv.getAvailableStacks().isEmpty()) { + player.displayClientMessage(PlayerMessages.OnlyEmptyCellsCanBeDisassembled.text(), true); + return true; // Prevents the UI from opening and overlaying the error message } - if (inv.getAvailableStacks().isEmpty()) { - playerInventory.setItem(playerInventory.selected, ItemStack.EMPTY); - - var remainingEnergy = getAECurrentPower(stack); - for (var ingredient : craftingRecipe.getIngredients()) { - var ingredientStack = ingredient.getItems()[0].copy(); - - // Dump remaining energy into whatever can accept it - if (remainingEnergy > 0 && ingredientStack.getItem() instanceof EnergyCellBlockItem energyCell) { - remainingEnergy = energyCell.injectAEPower(ingredientStack, remainingEnergy, Actionable.MODULATE); - } + playerInventory.setItem(playerInventory.selected, ItemStack.EMPTY); - playerInventory.placeItemBackInInventory(ingredientStack); + double remainingEnergy = getAECurrentPower(stack); + for (var recipeStack : disassemblyItems) { + var droppedStack = recipeStack.copy(); + // Dump remaining energy into whatever can accept it + if (remainingEnergy > 0 && droppedStack.getItem() instanceof EnergyCellBlockItem energyCell) { + remainingEnergy = energyCell.injectAEPower(droppedStack, remainingEnergy, Actionable.MODULATE); } - // Drop upgrades - for (var upgrade : getUpgrades(stack)) { - playerInventory.placeItemBackInInventory(upgrade); - } - } else { - player.displayClientMessage(PlayerMessages.OnlyEmptyCellsCanBeDisassembled.text(), true); + playerInventory.placeItemBackInInventory(droppedStack); } + // Drop upgrades + getUpgrades(stack).forEach(playerInventory::placeItemBackInInventory); + return true; } diff --git a/src/main/java/appeng/recipes/AERecipeSerializers.java b/src/main/java/appeng/recipes/AERecipeSerializers.java index 8abb55b00e7..e1a355319cd 100644 --- a/src/main/java/appeng/recipes/AERecipeSerializers.java +++ b/src/main/java/appeng/recipes/AERecipeSerializers.java @@ -7,8 +7,10 @@ import appeng.core.AppEng; import appeng.recipes.entropy.EntropyRecipeSerializer; import appeng.recipes.game.AddItemUpgradeRecipeSerializer; +import appeng.recipes.game.CraftingUnitTransformRecipeSerializer; import appeng.recipes.game.FacadeRecipe; import appeng.recipes.game.RemoveItemUpgradeRecipeSerializer; +import appeng.recipes.game.StorageCellDisassemblyRecipeSerializer; import appeng.recipes.game.StorageCellUpgradeRecipeSerializer; import appeng.recipes.handlers.ChargerRecipeSerializer; import appeng.recipes.handlers.InscriberRecipeSerializer; @@ -34,6 +36,8 @@ private AERecipeSerializers() { register("add_item_upgrade", AddItemUpgradeRecipeSerializer.INSTANCE); register("remove_item_upgrade", RemoveItemUpgradeRecipeSerializer.INSTANCE); register("quartz_cutting", QuartzCuttingRecipeSerializer.INSTANCE); + register("crafting_unit_transform", CraftingUnitTransformRecipeSerializer.INSTANCE); + register("storage_cell_disassembly", StorageCellDisassemblyRecipeSerializer.INSTANCE); } private static void register(String id, RecipeSerializer serializer) { diff --git a/src/main/java/appeng/recipes/AERecipeTypes.java b/src/main/java/appeng/recipes/AERecipeTypes.java index 7ff15e1e321..827092e3f22 100644 --- a/src/main/java/appeng/recipes/AERecipeTypes.java +++ b/src/main/java/appeng/recipes/AERecipeTypes.java @@ -7,6 +7,8 @@ import appeng.core.AppEng; import appeng.recipes.entropy.EntropyRecipe; +import appeng.recipes.game.CraftingUnitTransformRecipe; +import appeng.recipes.game.StorageCellDisassemblyRecipe; import appeng.recipes.handlers.ChargerRecipe; import appeng.recipes.handlers.InscriberRecipe; import appeng.recipes.mattercannon.MatterCannonAmmo; @@ -26,6 +28,10 @@ private AERecipeTypes() { public static final RecipeType CHARGER = register("charger"); public static final RecipeType MATTER_CANNON_AMMO = register("matter_cannon"); public static final RecipeType QUARTZ_CUTTING = register("quartz_cutting"); + public static final RecipeType CRAFTING_UNIT_TRANSFORM = register( + "crafting_unit_transform"); + public static final RecipeType CELL_DISASSEMBLY = register( + "storage_cell_disassembly"); private static > RecipeType register(String id) { RecipeType type = RecipeType.simple(AppEng.makeId(id)); diff --git a/src/main/java/appeng/recipes/game/CraftingUnitTransformRecipe.java b/src/main/java/appeng/recipes/game/CraftingUnitTransformRecipe.java new file mode 100644 index 00000000000..66c1e5ed468 --- /dev/null +++ b/src/main/java/appeng/recipes/game/CraftingUnitTransformRecipe.java @@ -0,0 +1,118 @@ +package appeng.recipes.game; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; + +import appeng.recipes.AERecipeTypes; + +/** + * Used to handle upgrading and removal of upgrades for crafting units (in-world). + */ +public class CraftingUnitTransformRecipe extends CustomRecipe { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec((builder) -> builder + .group( + BuiltInRegistries.BLOCK.byNameCodec().fieldOf("upgraded_block") + .forGetter(CraftingUnitTransformRecipe::getUpgradedBlock), + BuiltInRegistries.ITEM.byNameCodec().fieldOf("upgrade_item") + .forGetter(CraftingUnitTransformRecipe::getUpgradeItem)) + .apply(builder, CraftingUnitTransformRecipe::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec + .composite( + ByteBufCodecs.registry(BuiltInRegistries.BLOCK.key()), + CraftingUnitTransformRecipe::getUpgradedBlock, + ByteBufCodecs.registry(BuiltInRegistries.ITEM.key()), + CraftingUnitTransformRecipe::getUpgradeItem, + CraftingUnitTransformRecipe::new); + + private final Block upgradedBlock; + private final Item upgradeItem; + + public CraftingUnitTransformRecipe(Block upgradedBlock, Item upgradeItem) { + super(CraftingBookCategory.MISC); + this.upgradedBlock = upgradedBlock; + this.upgradeItem = upgradeItem; + } + + public Block getUpgradedBlock() { + return this.upgradedBlock; + } + + public Item getUpgradeItem() { + return upgradeItem; + } + + /** + * Gets the upgrade that would be returned from removing an upgrade from the given crafting block. + * + * @return Empty stack if no upgrade removal is possible. + */ + public static ItemStack getRemovedUpgrade(Level level, Block upgradedBlock) { + var recipeManager = level.getRecipeManager(); + + for (var holder : recipeManager.byType(AERecipeTypes.CRAFTING_UNIT_TRANSFORM)) { + if (holder.value().upgradedBlock == upgradedBlock) { + return holder.value().upgradeItem.getDefaultInstance(); + } + } + + return ItemStack.EMPTY; + } + + /** + * Search for the resulting upgraded block when upgrading a crafting unit with the given upgrade item. + */ + public static Block getUpgradedBlock(Level level, ItemStack upgradeItem) { + for (var holder : level.getRecipeManager().byType(AERecipeTypes.CRAFTING_UNIT_TRANSFORM)) { + if (upgradeItem.is(holder.value().getUpgradeItem())) { + return holder.value().upgradedBlock; + } + } + return null; + } + + @Override + public boolean matches(CraftingInput input, Level level) { + return false; + } + + @Override + public ItemStack assemble(CraftingInput input, HolderLookup.Provider registries) { + return ItemStack.EMPTY; + } + + @Override + public boolean canCraftInDimensions(int width, int height) { + return false; + } + + @Override + public ItemStack getResultItem(HolderLookup.Provider registries) { + return ItemStack.EMPTY; + } + + @Override + public RecipeSerializer getSerializer() { + return CraftingUnitTransformRecipeSerializer.INSTANCE; + } + + @Override + public RecipeType getType() { + return AERecipeTypes.CRAFTING_UNIT_TRANSFORM; + } +} diff --git a/src/main/java/appeng/recipes/game/CraftingUnitTransformRecipeSerializer.java b/src/main/java/appeng/recipes/game/CraftingUnitTransformRecipeSerializer.java new file mode 100644 index 00000000000..0a31b15ef21 --- /dev/null +++ b/src/main/java/appeng/recipes/game/CraftingUnitTransformRecipeSerializer.java @@ -0,0 +1,24 @@ +package appeng.recipes.game; + +import com.mojang.serialization.MapCodec; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.crafting.RecipeSerializer; + +public class CraftingUnitTransformRecipeSerializer implements RecipeSerializer { + public static final CraftingUnitTransformRecipeSerializer INSTANCE = new CraftingUnitTransformRecipeSerializer(); + + private CraftingUnitTransformRecipeSerializer() { + } + + @Override + public MapCodec codec() { + return CraftingUnitTransformRecipe.CODEC; + } + + @Override + public StreamCodec streamCodec() { + return CraftingUnitTransformRecipe.STREAM_CODEC; + } +} diff --git a/src/main/java/appeng/recipes/game/StorageCellDisassemblyRecipe.java b/src/main/java/appeng/recipes/game/StorageCellDisassemblyRecipe.java new file mode 100644 index 00000000000..8d3acc8eac6 --- /dev/null +++ b/src/main/java/appeng/recipes/game/StorageCellDisassemblyRecipe.java @@ -0,0 +1,116 @@ +package appeng.recipes.game; + +import java.util.List; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; + +import appeng.recipes.AERecipeTypes; + +/** + * Used to handle disassembly of the (Portable) Storage Cells. + */ +public class StorageCellDisassemblyRecipe extends CustomRecipe { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec((builder) -> builder + .group( + BuiltInRegistries.ITEM.byNameCodec().fieldOf("cell") + .forGetter(StorageCellDisassemblyRecipe::getStorageCell), + ItemStack.CODEC.listOf().fieldOf("cell_disassembly_items") + .forGetter(StorageCellDisassemblyRecipe::getCellDisassemblyItems)) + .apply(builder, StorageCellDisassemblyRecipe::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec + .composite( + ByteBufCodecs.registry(BuiltInRegistries.ITEM.key()), + StorageCellDisassemblyRecipe::getStorageCell, + ItemStack.STREAM_CODEC.apply(ByteBufCodecs.list()), + StorageCellDisassemblyRecipe::getCellDisassemblyItems, + StorageCellDisassemblyRecipe::new); + + private final List disassemblyItems; + private final Item storageCell; + + public StorageCellDisassemblyRecipe(Item storageCell, List disassemblyItems) { + super(CraftingBookCategory.MISC); + this.storageCell = storageCell; + this.disassemblyItems = disassemblyItems; + } + + public Item getStorageCell() { + return this.storageCell; + } + + public List getCellDisassemblyItems() { + return disassemblyItems.stream().map(ItemStack::copy).toList(); + } + + /** + * @return True when any Disassembly Output is specified. + */ + public boolean canDisassemble() { + return !this.disassemblyItems.isEmpty(); + } + + /** + * Used to get the disassembly result based on recipes for the given cell. + * + * @param cell The cell item being disassembled. + * @return An empty list to indicate the cell cannot be disassembled. Note that stacks in the list must be copied by + * the caller. + */ + public static List getDisassemblyResult(Level level, Item cell) { + var recipeManager = level.getRecipeManager(); + + for (var holder : recipeManager.byType(AERecipeTypes.CELL_DISASSEMBLY)) { + if (holder.value().storageCell == cell) { + return holder.value().getCellDisassemblyItems(); + } + } + + return List.of(); + } + + @Override + public boolean matches(CraftingInput input, Level level) { + return false; + } + + @Override + public ItemStack assemble(CraftingInput input, HolderLookup.Provider registries) { + return ItemStack.EMPTY; + } + + @Override + public boolean canCraftInDimensions(int width, int height) { + return false; + } + + @Override + public ItemStack getResultItem(HolderLookup.Provider registries) { + return ItemStack.EMPTY; + } + + @Override + public RecipeSerializer getSerializer() { + return StorageCellDisassemblyRecipeSerializer.INSTANCE; + } + + @Override + public RecipeType getType() { + return AERecipeTypes.CELL_DISASSEMBLY; + } +} diff --git a/src/main/java/appeng/recipes/game/StorageCellDisassemblyRecipeSerializer.java b/src/main/java/appeng/recipes/game/StorageCellDisassemblyRecipeSerializer.java new file mode 100644 index 00000000000..89f6ca9d145 --- /dev/null +++ b/src/main/java/appeng/recipes/game/StorageCellDisassemblyRecipeSerializer.java @@ -0,0 +1,24 @@ +package appeng.recipes.game; + +import com.mojang.serialization.MapCodec; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.crafting.RecipeSerializer; + +public class StorageCellDisassemblyRecipeSerializer implements RecipeSerializer { + public static final StorageCellDisassemblyRecipeSerializer INSTANCE = new StorageCellDisassemblyRecipeSerializer(); + + private StorageCellDisassemblyRecipeSerializer() { + } + + @Override + public MapCodec codec() { + return StorageCellDisassemblyRecipe.CODEC; + } + + @Override + public StreamCodec streamCodec() { + return StorageCellDisassemblyRecipe.STREAM_CODEC; + } +} diff --git a/src/main/java/appeng/recipes/game/StorageCellUpgradeRecipe.java b/src/main/java/appeng/recipes/game/StorageCellUpgradeRecipe.java index fb73f2e9b1f..fbb6e55bfa7 100644 --- a/src/main/java/appeng/recipes/game/StorageCellUpgradeRecipe.java +++ b/src/main/java/appeng/recipes/game/StorageCellUpgradeRecipe.java @@ -11,7 +11,6 @@ import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; @@ -143,11 +142,12 @@ public ItemStack assemble(CraftingInput container, HolderLookup.Provider registr } } - public NonNullList getRemainingItems(CraftingContainer inv) { - var remainder = NonNullList.withSize(inv.getContainerSize(), ItemStack.EMPTY); + @Override + public NonNullList getRemainingItems(CraftingInput input) { + var remainder = NonNullList.withSize(input.size(), ItemStack.EMPTY); for (int i = 0; i < remainder.size(); ++i) { - var stack = inv.getItem(i); + var stack = input.getItem(i); if (stack.is(inputCell)) { // We replace the cell with the component since it is unstackable and forced to be in match remainder.set(i, new ItemStack(resultComponent));