diff --git a/common/src/dataGen/scala/com/yogpc/qp/data/Recipe.scala b/common/src/dataGen/scala/com/yogpc/qp/data/Recipe.scala index 781c6f4a5..0d62cf6ec 100644 --- a/common/src/dataGen/scala/com/yogpc/qp/data/Recipe.scala +++ b/common/src/dataGen/scala/com/yogpc/qp/data/Recipe.scala @@ -198,6 +198,18 @@ class Recipe(ingredientProvider: IngredientProvider, output: PackOutput, registr .requires(ip.marker) .unlockedBy(ip.markerTag) .save(ip.filterModuleRecipeOutput(recipeOutput)) + + ShapedRecipeBuilder.shaped(RecipeCategory.MISC, PlatformAccess.getAccess.registerObjects().placerBlock().get()) + .define('D', Items.DISPENSER) + .define('R', ip.redStoneDust) + .define('I', ip.ironIngot) + .define('M', Items.MOSSY_COBBLESTONE) + .define('G', ip.goldIngot) + .pattern("GDG") + .pattern("MRM") + .pattern("MIM") + .unlockedBy(Items.DISPENSER) + .save(recipeOutput) } private def quarryItem(name: String): Item = { diff --git a/common/src/gameTest/java/com/yogpc/qp/gametest/GameTestFunctions.java b/common/src/gameTest/java/com/yogpc/qp/gametest/GameTestFunctions.java index 42c13adf1..cc502add1 100644 --- a/common/src/gameTest/java/com/yogpc/qp/gametest/GameTestFunctions.java +++ b/common/src/gameTest/java/com/yogpc/qp/gametest/GameTestFunctions.java @@ -4,6 +4,7 @@ import com.yogpc.qp.machine.DebugStorageTest; import com.yogpc.qp.machine.advquarry.PlaceAdvQuarryTest; import com.yogpc.qp.machine.mover.PlaceMoverTest; +import com.yogpc.qp.machine.placer.PlacerTest; import com.yogpc.qp.machine.quarry.PlaceQuarryTest; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; @@ -51,11 +52,12 @@ public static List createTestFunctionsPlace(String batchName, Stri var fromClass = getTestFunctionStream(batchName, structureName, classes, 100); return Stream.of( CheckBlockDropTest.checkDrops(batchName, structureName), + PlacerTest.tests(batchName, structureName), fromClass ).flatMap(Function.identity()).toList(); } - private static @NotNull Stream getTestFunctionStream(String batchName, String structureName, List> classes, int maxTicks) { + public static @NotNull Stream getTestFunctionStream(String batchName, String structureName, List> classes, int maxTicks) { return classes.stream() .flatMap(c -> Stream.of(c.getDeclaredMethods())) .filter(Predicate.not(Method::isSynthetic)) diff --git a/common/src/gameTest/java/com/yogpc/qp/gametest/LoadRecipeTest.java b/common/src/gameTest/java/com/yogpc/qp/gametest/LoadRecipeTest.java index 1f0b00e93..bd432a486 100644 --- a/common/src/gameTest/java/com/yogpc/qp/gametest/LoadRecipeTest.java +++ b/common/src/gameTest/java/com/yogpc/qp/gametest/LoadRecipeTest.java @@ -8,6 +8,7 @@ import com.yogpc.qp.machine.marker.FlexibleMarkerBlock; import com.yogpc.qp.machine.module.FilterModuleItem; import com.yogpc.qp.machine.module.RepeatTickModuleItem; +import com.yogpc.qp.machine.placer.PlacerBlock; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.resources.ResourceLocation; @@ -451,4 +452,27 @@ public static void createAdvQuarry(GameTestHelper helper) { helper.succeed(); } + + public static void createPlacer(GameTestHelper helper) { + var recipe = findRecipe(helper, PlacerBlock.NAME); + var D = Items.DISPENSER.getDefaultInstance(); + var R = Items.REDSTONE.getDefaultInstance(); + var I = Items.IRON_INGOT.getDefaultInstance(); + var M = Items.MOSSY_COBBLESTONE.getDefaultInstance(); + var G = Items.GOLD_INGOT.getDefaultInstance(); + + var input = CraftingInput.of(3, 3, List.of( + G, D, G, + M, R, M, + M, I, M + )); + assertTrue(recipe.matches(input, helper.getLevel())); + var result = recipe.assemble(input, helper.getLevel().registryAccess()); + assertEquals( + PlatformAccess.getAccess().registerObjects().placerBlock().get().blockItem, + result.getItem() + ); + + helper.succeed(); + } } diff --git a/common/src/gameTest/java/com/yogpc/qp/machine/placer/PlacerTest.java b/common/src/gameTest/java/com/yogpc/qp/machine/placer/PlacerTest.java new file mode 100644 index 000000000..588e837f3 --- /dev/null +++ b/common/src/gameTest/java/com/yogpc/qp/machine/placer/PlacerTest.java @@ -0,0 +1,195 @@ +package com.yogpc.qp.machine.placer; + +import com.google.common.base.CaseFormat; +import com.yogpc.qp.PlatformAccess; +import com.yogpc.qp.gametest.GameTestFunctions; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.TestFunction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.List; +import java.util.Locale; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +public final class PlacerTest { + private static final BlockPos placerPos = new BlockPos(2, 2, 2); + + public static Stream tests(String batchName, String structureName) { + return Stream.of( + PlacerTestDirect.removeBlock(batchName, structureName), + PlacerTestDirect.placeBlock1(batchName, structureName), + GameTestFunctions.getTestFunctionStream(batchName, structureName, List.of( + PlacerTestDirect.class, + PlacerTestRedStone.class, + PlacerTest.class + ), 10) + ).flatMap(Function.identity()); + } + + static void placePlacerBlock(GameTestHelper helper) { + helper.setBlock(placerPos, PlatformAccess.getAccess().registerObjects().placerBlock().get()); + helper.assertBlockPresent(PlatformAccess.getAccess().registerObjects().placerBlock().get(), placerPos); + BlockEntity entity = helper.getBlockEntity(placerPos); + assertInstanceOf(PlacerEntity.class, entity); + helper.succeed(); + } + + static class PlacerTestDirect { + private static Stream removeBlock(String batchName, String structureName) { + return Stream.of(Direction.values()) + .flatMap(direction -> Stream.of(Blocks.STONE, Blocks.ICE, Blocks.ACACIA_LOG, Blocks.BIRCH_LEAVES).map(b -> { + var r = Rotation.NONE; + var blockName = BuiltInRegistries.BLOCK.getKey(b); + var name = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "PlacerTest_removeBlock_%s_%s_%s".formatted( + direction.name().toLowerCase(Locale.ROOT), r.name().toLowerCase(Locale.ROOT), blockName.getPath())); + return new TestFunction(batchName, name, structureName, r, 20, 0, true, g -> removeBlock(g, direction, b)); + })); + } + + private static void removeBlock(GameTestHelper helper, Direction direction, Block block) { + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + var stonePos = placerPos.relative(direction); + helper.startSequence() + .thenExecuteAfter(1, () -> helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, direction))) + .thenExecuteAfter(1, () -> helper.setBlock(stonePos, block)) + .thenExecuteAfter(1, () -> { + BlockEntity entity = helper.getBlockEntity(placerPos); + assertInstanceOf(PlacerEntity.class, entity).breakBlock(); + }) + .thenExecuteAfter(1, () -> helper.assertBlockNotPresent(block, stonePos)) + .thenExecuteAfter(1, () -> { + PlacerEntity placer = helper.getBlockEntity(placerPos); + assertEquals(1, placer.countItem(block.asItem()), "Placer should contain removed item"); + }) + .thenSucceed(); + } + + private static Stream placeBlock1(String batchName, String structureName) { + return Stream.of(Direction.values()) + .flatMap(direction -> Stream.of(Blocks.STONE, Blocks.ICE, Blocks.ACACIA_LOG, Blocks.BIRCH_LEAVES).map(b -> { + var r = Rotation.NONE; + var blockName = BuiltInRegistries.BLOCK.getKey(b); + var name = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "PlacerTest_placeBlock1_%s_%s_%s".formatted( + direction.name().toLowerCase(Locale.ROOT), r.name().toLowerCase(Locale.ROOT), blockName.getPath())); + return new TestFunction(batchName, name, structureName, r, 20, 0, true, g -> placeBlock1(g, direction, b)); + })); + } + + private static void placeBlock1(GameTestHelper helper, Direction direction, Block block) { + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + var stonePos = placerPos.relative(direction); + helper.startSequence() + .thenExecuteAfter(1, () -> helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, direction))) + .thenExecuteAfter(1, () -> { + PlacerEntity placer = helper.getBlockEntity(placerPos); + placer.setItem(0, new ItemStack(block)); + }) + .thenExecuteAfter(1, () -> { + PlacerEntity placer = helper.getBlockEntity(placerPos); + placer.placeBlock(); + }) + .thenExecuteAfter(1, () -> helper.assertBlockPresent(block, stonePos)) + .thenExecuteAfter(1, () -> { + PlacerEntity placer = helper.getBlockEntity(placerPos); + assertEquals(0, placer.countItem(block.asItem()), "Placer must not contain placed item"); + }) + .thenSucceed(); + } + + static void notPlaceMode(GameTestHelper helper) { + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, Direction.NORTH)); + PlacerEntity tile = helper.getBlockEntity(placerPos); + tile.redstoneMode = AbstractPlacerTile.RedStoneMode.PULSE_BREAK_ONLY; + helper.startSequence() + .thenExecuteAfter(1, () -> tile.setItem(0, new ItemStack(Blocks.STONE))) + .thenExecuteAfter(1, tile::placeBlock) + .thenExecuteAfter(1, () -> helper.assertBlockNotPresent(Blocks.STONE, placerPos.relative(Direction.NORTH))) + .thenSucceed(); + } + + static void notBreakMode(GameTestHelper helper) { + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, Direction.NORTH)); + helper.setBlock(placerPos.relative(Direction.NORTH), Blocks.STONE); + PlacerEntity tile = helper.getBlockEntity(placerPos); + tile.redstoneMode = AbstractPlacerTile.RedStoneMode.PULSE_PLACE_ONLY; + helper.startSequence() + .thenExecuteAfter(1, tile::breakBlock) + .thenExecuteAfter(1, () -> helper.assertBlockPresent(Blocks.STONE, placerPos.relative(Direction.NORTH))) + .thenSucceed(); + } + + static void placeInWater(GameTestHelper helper) { + var waterPos = placerPos.above(); + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP)); + helper.setBlock(waterPos, Blocks.WATER); + PlacerEntity tile = helper.getBlockEntity(placerPos); + + helper.startSequence() + .thenExecuteAfter(1, () -> tile.setItem(0, new ItemStack(Blocks.STONE))) + .thenExecuteAfter(1, tile::placeBlock) + .thenExecuteAfter(1, () -> helper.assertBlockPresent(Blocks.STONE, placerPos.relative(Direction.UP))) + .thenExecute(() -> assertTrue(tile.getItem(0).isEmpty())) + .thenSucceed(); + } + + static void cantPlaceInSolidBlock(GameTestHelper helper) { + var blockPos = placerPos.above(); + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP)); + helper.setBlock(blockPos, Blocks.DIAMOND_BLOCK); + PlacerEntity tile = helper.getBlockEntity(placerPos); + + helper.startSequence() + .thenExecuteAfter(1, () -> tile.setItem(0, new ItemStack(Blocks.STONE))) + .thenExecuteAfter(1, tile::placeBlock) + .thenExecuteAfter(1, () -> helper.assertBlockPresent(Blocks.DIAMOND_BLOCK, placerPos.relative(Direction.UP))) + .thenExecute(() -> assertEquals(Blocks.STONE.asItem(), tile.getItem(0).getItem())) + .thenSucceed(); + } + } + + static class PlacerTestRedStone { + static void sendRedStoneSignalPlace(GameTestHelper helper) { + var stonePos = placerPos.relative(Direction.NORTH); + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, Direction.NORTH)); + PlacerEntity tile = helper.getBlockEntity(placerPos); + + helper.startSequence() + .thenExecuteAfter(1, () -> tile.setItem(0, new ItemStack(Blocks.STONE))) + .thenExecuteAfter(1, () -> helper.setBlock(placerPos.relative(Direction.EAST), Blocks.REDSTONE_BLOCK)) + .thenExecuteAfter(1, () -> helper.assertBlockPresent(Blocks.STONE, stonePos)) + .thenSucceed(); + } + + static void sendRedStoneSignalBreak(GameTestHelper helper) { + var stonePos = placerPos.relative(Direction.NORTH); + var placerBlock = PlatformAccess.getAccess().registerObjects().placerBlock().get(); + helper.setBlock(placerPos, placerBlock.defaultBlockState().setValue(BlockStateProperties.FACING, Direction.NORTH)); + helper.setBlock(stonePos, Blocks.STONE); + PlacerEntity tile = helper.getBlockEntity(placerPos); + + helper.startSequence() + .thenExecuteAfter(1, () -> helper.setBlock(placerPos.relative(Direction.EAST), Blocks.REDSTONE_BLOCK)) + .thenExecuteAfter(1, () -> helper.setBlock(placerPos.relative(Direction.EAST), Blocks.AIR)) + .thenExecuteAfter(1, () -> helper.assertBlockNotPresent(Blocks.STONE, stonePos)) + .thenExecuteAfter(1, () -> assertEquals(1, tile.countItem(Items.STONE))) + .thenSucceed(); + } + } +} diff --git a/common/src/generated/resources/assets/quarryplus/blockstates/placer_plus.json b/common/src/generated/resources/assets/quarryplus/blockstates/placer_plus.json new file mode 100644 index 000000000..5201e7410 --- /dev/null +++ b/common/src/generated/resources/assets/quarryplus/blockstates/placer_plus.json @@ -0,0 +1,27 @@ +{ + "variants": { + "facing=down": { + "model": "quarryplus:block/placer_plus", + "x": 90 + }, + "facing=east": { + "model": "quarryplus:block/placer_plus", + "y": 90 + }, + "facing=north": { + "model": "quarryplus:block/placer_plus" + }, + "facing=south": { + "model": "quarryplus:block/placer_plus", + "y": 180 + }, + "facing=up": { + "model": "quarryplus:block/placer_plus", + "x": 270 + }, + "facing=west": { + "model": "quarryplus:block/placer_plus", + "y": 270 + } + } +} \ No newline at end of file diff --git a/common/src/generated/resources/assets/quarryplus/models/block/placer_plus.json b/common/src/generated/resources/assets/quarryplus/models/block/placer_plus.json new file mode 100644 index 000000000..8129120f4 --- /dev/null +++ b/common/src/generated/resources/assets/quarryplus/models/block/placer_plus.json @@ -0,0 +1,9 @@ +{ + "parent": "minecraft:block/orientable_with_bottom", + "textures": { + "bottom": "quarryplus:block/plus_stone_top", + "front": "quarryplus:block/placer_front_horizontal", + "side": "quarryplus:block/plus_stone_side", + "top": "quarryplus:block/placer_front_vertical" + } +} \ No newline at end of file diff --git a/common/src/generated/resources/assets/quarryplus/models/item/placer_plus.json b/common/src/generated/resources/assets/quarryplus/models/item/placer_plus.json new file mode 100644 index 000000000..61f2e24bd --- /dev/null +++ b/common/src/generated/resources/assets/quarryplus/models/item/placer_plus.json @@ -0,0 +1,3 @@ +{ + "parent": "quarryplus:block/placer_plus" +} \ No newline at end of file diff --git a/common/src/generated/resources/data/quarryplus/loot_table/blocks/placer_plus.json b/common/src/generated/resources/data/quarryplus/loot_table/blocks/placer_plus.json new file mode 100644 index 000000000..281c949ce --- /dev/null +++ b/common/src/generated/resources/data/quarryplus/loot_table/blocks/placer_plus.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "quarryplus:placer_plus" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "quarryplus:blocks/placer_plus" +} \ No newline at end of file diff --git a/common/src/main/java/com/yogpc/qp/PlatformAccess.java b/common/src/main/java/com/yogpc/qp/PlatformAccess.java index a2411cdb4..766af6ec4 100644 --- a/common/src/main/java/com/yogpc/qp/PlatformAccess.java +++ b/common/src/main/java/com/yogpc/qp/PlatformAccess.java @@ -18,6 +18,8 @@ import com.yogpc.qp.machine.module.ModuleContainer; import com.yogpc.qp.machine.mover.MoverBlock; import com.yogpc.qp.machine.mover.MoverContainer; +import com.yogpc.qp.machine.placer.PlacerBlock; +import com.yogpc.qp.machine.placer.PlacerContainer; import com.yogpc.qp.machine.quarry.QuarryBlock; import com.yogpc.qp.machine.storage.DebugStorageBlock; import com.yogpc.qp.machine.storage.DebugStorageContainer; @@ -82,6 +84,8 @@ interface RegisterObjects { Supplier softBlock(); + Supplier placerBlock(); + Optional> getBlockEntityType(QpBlock block); default Collection> getBlockEntityTypes() { @@ -113,6 +117,10 @@ default Collection> getBlockEntityTypes() { Supplier> filterModuleContainer(); + Supplier> placerContainer(); + + Supplier> remotePlacerContainer(); + Supplier> machineLootFunction(); } diff --git a/common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerBlock.java b/common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerBlock.java new file mode 100644 index 000000000..210ed27ba --- /dev/null +++ b/common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerBlock.java @@ -0,0 +1,125 @@ +package com.yogpc.qp.machine.placer; + +import com.yogpc.qp.PlatformAccess; +import com.yogpc.qp.machine.GeneralScreenHandler; +import com.yogpc.qp.machine.QpEntityBlock; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.RandomSource; +import net.minecraft.world.Containers; +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.*; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.phys.BlockHitResult; + +import java.util.List; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.TRIGGERED; + +public abstract class AbstractPlacerBlock extends QpEntityBlock { + public AbstractPlacerBlock(String name) { + super( + Properties.of() + .mapColor(MapColor.METAL) + .pushReaction(PushReaction.BLOCK).strength(1.2f), + name, + b -> new BlockItem(b, new Item.Properties()) + ); + } + + @Override + protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) { + if (!player.isCrouching() && stack.is(Items.REDSTONE_TORCH)) { + if (!level.isClientSide && level.getBlockEntity(pos) instanceof AbstractPlacerTile placer) { + if (placer.enabled) { + placer.cycleRedStoneMode(); + player.displayClientMessage(Component.translatable("quarryplus.chat.placer_rs", placer.redstoneMode.toString()), false); + } else { + player.displayClientMessage(Component.translatable("quarryplus.chat.disable_message", getName()), true); + } + } + return ItemInteractionResult.SUCCESS; + } + return super.useItemOn(stack, state, level, pos, player, hand, hitResult); + } + + @Override + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + if (level.getBlockEntity(pos) instanceof AbstractPlacerTile placer) { + if (!level.isClientSide()) { + if (placer.enabled) { + PlatformAccess.getAccess().openGui((ServerPlayer) player, createScreenHandler(placer)); + } else { + player.displayClientMessage(Component.translatable("quarryplus.chat.disable_message", getName()), true); + } + } + return InteractionResult.sidedSuccess(level.isClientSide()); + } + return super.useWithoutItem(state, level, pos, player, hitResult); + } + + protected abstract GeneralScreenHandler createScreenHandler(AbstractPlacerTile placer); + + @Override + protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + super.tick(state, level, pos, random); + if (level.getBlockEntity(pos) instanceof AbstractPlacerTile placer) { + boolean isPowered = state.getValue(TRIGGERED); + if (isPowered) { + placer.placeBlock(); + } else { + placer.breakBlock(); + } + } + } + + @Override + protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos, boolean movedByPiston) { + super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston); + if (!level.isClientSide() && level.getBlockEntity(pos) instanceof AbstractPlacerTile placer) { + boolean poweredNow = placer.isPowered(); + boolean poweredOld = state.getValue(TRIGGERED); + if (poweredNow != poweredOld) { + level.scheduleTick(pos, this, 1); + level.setBlock(pos, state.setValue(TRIGGERED, poweredNow), Block.UPDATE_INVISIBLE); + } + } + } + + @Override + protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { + Containers.dropContentsOnDestroy(state, newState, level, pos); + super.onRemove(state, level, pos, newState, movedByPiston); + } + + @Override + public void appendHoverText(ItemStack stack, Item.TooltipContext context, List tooltipComponents, TooltipFlag tooltipFlag) { + super.appendHoverText(stack, context, tooltipComponents, tooltipFlag); + if (Screen.hasShiftDown()) { + tooltipComponents.add(Component.translatable("quarryplus.tooltip.placer_plus")); + } + } + + @Override + protected BlockState rotate(BlockState state, Rotation rotation) { + return state.setValue(FACING, rotation.rotate(state.getValue(FACING))); + } + + @Override + protected BlockState mirror(BlockState state, Mirror mirror) { + return state.rotate(mirror.getRotation(state.getValue(FACING))); + } +} diff --git a/common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerTile.java b/common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerTile.java new file mode 100644 index 000000000..e0e0e44e2 --- /dev/null +++ b/common/src/main/java/com/yogpc/qp/machine/placer/AbstractPlacerTile.java @@ -0,0 +1,285 @@ +package com.yogpc.qp.machine.placer; + +import com.yogpc.qp.PlatformAccess; +import com.yogpc.qp.machine.QpEntity; +import com.yogpc.qp.packet.ClientSync; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; + +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; + +public abstract class AbstractPlacerTile extends QpEntity + implements ClientSync, Container { + + public static final Map DIRECTION_VEC3D_MAP; + + static { + EnumMap map = new EnumMap<>(Direction.class); + map.put(Direction.DOWN, new Vec3(0.5, 0, 0.5)); + map.put(Direction.UP, new Vec3(0.5, 1, 0.5)); + map.put(Direction.NORTH, new Vec3(0.5, 0.5, 0)); + map.put(Direction.SOUTH, new Vec3(0.5, 0.5, 1)); + map.put(Direction.EAST, new Vec3(1, 0.5, 0.5)); + map.put(Direction.WEST, new Vec3(0, 0.5, 0.5)); + DIRECTION_VEC3D_MAP = Collections.unmodifiableMap(map); + } + + private final SimpleContainer container = new PlacerContainer(this, getContainerSize()); + private int lastPlacedIndex = 0; + public RedStoneMode redstoneMode = RedStoneMode.PULSE; + + protected AbstractPlacerTile(BlockPos pos, BlockState blockState) { + super(pos, blockState); + } + + @Override + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.saveAdditional(tag, registries); + toClientTag(tag, registries); + tag.put("container", container.createTag(registries)); + } + + @Override + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + fromClientTag(tag, registries); + container.fromTag(tag.getList("container", Tag.TAG_COMPOUND), registries); + } + + @Override + public void fromClientTag(CompoundTag tag, HolderLookup.Provider registries) { + lastPlacedIndex = tag.getInt("lastPlacedIndex"); + redstoneMode = RedStoneMode.valueOf(tag.getString("mode")); + } + + @Override + public CompoundTag toClientTag(CompoundTag tag, HolderLookup.Provider registries) { + tag.putInt("lastPlacedIndex", lastPlacedIndex); + tag.putString("mode", redstoneMode.name()); + return tag; + } + + protected abstract BlockPos getTargetPos(); + + protected abstract Direction getMachineFacing(); + + protected boolean isPowered() { + assert level != null; + return Arrays.stream(Direction.values()).filter(Predicate.isEqual(getMachineFacing()).negate()) + .anyMatch(f -> level.hasSignal(getBlockPos().relative(f), f)) || level.hasNeighborSignal(getBlockPos().above()); + } + + void breakBlock() { + if (level == null || !redstoneMode.canBreak()) return; + BlockPos pos = getTargetPos(); + BlockState state = level.getBlockState(pos); + if (state.getDestroySpeed(level, pos) < 0) return; // Unbreakable. + Player fake = PlatformAccess.getAccess().mining().getQuarryFakePlayer(this, (ServerLevel) level, pos); + var pickaxe = getSilkPickaxe(); + fake.setItemInHand(InteractionHand.MAIN_HAND, pickaxe); + List drops = Block.getDrops(state, (ServerLevel) level, pos, level.getBlockEntity(pos), fake, pickaxe); + level.removeBlock(pos, false); + drops.stream().map(container::addItem) // Return not-inserted items. + .filter(Predicate.not(ItemStack::isEmpty)).forEach(s -> Block.popResource(level, getBlockPos(), s)); + } + + /** + * @return Whether the placement succeeded. + */ + boolean placeBlock() { + if (isEmpty() || !redstoneMode.canPlace()) return false; + Direction facing = getMachineFacing(); + BlockPos pos = getTargetPos(); + Vec3 hitPos = DIRECTION_VEC3D_MAP.get(facing.getOpposite()).add(pos.getX(), pos.getY(), pos.getZ()); + BlockHitResult rayTrace = new BlockHitResult(hitPos, facing.getOpposite(), pos, false); + Player fake = PlatformAccess.getAccess().mining().getQuarryFakePlayer(this, (ServerLevel) level, pos); + + AtomicBoolean result = new AtomicBoolean(false); + findEntry(container.getItems(), + i -> tryPlaceItem(i, fake, rayTrace), + lastPlacedIndex).ifPresent(i -> { + if (!getItem(i).isEmpty()) { + this.lastPlacedIndex = i; + } else { + this.lastPlacedIndex = findEntry(container.getItems(), s -> !s.isEmpty() && s.getItem() instanceof BlockItem, i).orElse(0); + } + setChanged(); + syncToClient(); + result.set(true); + }); + fake.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); + return result.get(); + } + + // -------------------- Utility -------------------- + + public static OptionalInt findEntry(List check, Predicate filter, int startIndex) { + int listSize = check.size(); + if (startIndex >= listSize) + return OptionalInt.empty(); + return findEntryInternal(check, filter, startIndex, startIndex, listSize); + } + + private static OptionalInt findEntryInternal(List check, Predicate filter, int startIndex, int index, int listSize) { + T value = check.get(index); + if (filter.test(value)) + return OptionalInt.of(index); + if (index == startIndex - 1 || (startIndex == 0 && index == listSize - 1)) { + // last search + return OptionalInt.empty(); + } else { + int next = index + 1 == listSize ? 0 : index + 1; + return findEntryInternal(check, filter, startIndex, next, listSize); + } + } + + static boolean tryPlaceItem(ItemStack stack, Player fake, BlockHitResult rayTrace) { + if (stack.isEmpty()) return false; + Item item = stack.getItem(); + if (item instanceof BlockItem blockItem) { + fake.setItemInHand(InteractionHand.MAIN_HAND, stack); + BlockPlaceContext context = new BlockPlaceContext(new UseOnContext(fake, InteractionHand.MAIN_HAND, rayTrace)); + return blockItem.place(context).consumesAction(); + } else { + return false; + } + } + + public int getLastPlacedIndex() { + return lastPlacedIndex; + } + + protected ItemStack getSilkPickaxe() { + assert level != null; + ItemStack stack = new ItemStack(Items.DIAMOND_PICKAXE); + stack.enchant(level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(Enchantments.SILK_TOUCH), 1); + return stack; + } + + // Container + + @Override + public int getContainerSize() { + return 9; + } + + @Override + public boolean isEmpty() { + return container.isEmpty(); + } + + @Override + public ItemStack getItem(int slot) { + return container.getItem(slot); + } + + @Override + public ItemStack removeItem(int slot, int amount) { + return container.removeItem(slot, amount); + } + + @Override + public ItemStack removeItemNoUpdate(int slot) { + return container.removeItemNoUpdate(slot); + } + + @Override + public void setItem(int slot, ItemStack stack) { + container.setItem(slot, stack); + } + + @Override + public boolean stillValid(Player player) { + return getBlockPos().closerToCenterThan(player.position(), 8); + } + + @Override + public void clearContent() { + container.clearContent(); + } + + public void cycleRedStoneMode() { + this.redstoneMode = RedStoneMode.cycle(redstoneMode); + if (level != null && !level.isClientSide) { + syncToClient(); + } + } + + private static final class PlacerContainer extends SimpleContainer { + private final QpEntity parent; + + public PlacerContainer(QpEntity parent, int size) { + super(size); + this.parent = parent; + } + + @Override + public void setChanged() { + super.setChanged(); + parent.setChanged(); + } + } + + public enum RedStoneMode { + PULSE(true, true), + PULSE_PLACE_ONLY(true, false), + PULSE_BREAK_ONLY(false, true), + ; + private final boolean placeEnabled; + private final boolean breakEnabled; + + RedStoneMode(boolean placeEnabled, boolean breakEnabled) { + this.placeEnabled = placeEnabled; + this.breakEnabled = breakEnabled; + } + + @Override + public String toString() { + return name().replace('_', ' '); + } + + public boolean canPlace() { + return placeEnabled; + } + + public boolean canBreak() { + return breakEnabled; + } + + public static RedStoneMode cycle(RedStoneMode now) { + RedStoneMode[] modes = values(); + for (int i = 0; i < modes.length; i++) { + RedStoneMode mode = modes[i]; + if (mode == now) { + if (i + 1 == modes.length) + return modes[0]; + else + return modes[i + 1]; + } + } + return modes[0]; + } + } +} diff --git a/common/src/main/java/com/yogpc/qp/machine/placer/PlacerBlock.java b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerBlock.java new file mode 100644 index 000000000..f92a42c46 --- /dev/null +++ b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerBlock.java @@ -0,0 +1,42 @@ +package com.yogpc.qp.machine.placer; + +import com.yogpc.qp.machine.GeneralScreenHandler; +import com.yogpc.qp.machine.QpBlock; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.TRIGGERED; + +public final class PlacerBlock extends AbstractPlacerBlock { + public static final String NAME = "placer_plus"; + + public PlacerBlock() { + super(NAME); + registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.NORTH).setValue(TRIGGERED, Boolean.FALSE)); + } + + @Override + protected QpBlock createBlock(Properties properties) { + return new PlacerBlock(); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + super.createBlockStateDefinition(builder); + builder.add(FACING, TRIGGERED); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { + return this.defaultBlockState().setValue(FACING, ctx.getNearestLookingDirection().getOpposite()); + } + + @Override + protected GeneralScreenHandler createScreenHandler(AbstractPlacerTile placer) { + return new GeneralScreenHandler<>(placer, PlacerContainer::createPlacerContainer); + } +} diff --git a/common/src/main/java/com/yogpc/qp/machine/placer/PlacerContainer.java b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerContainer.java new file mode 100644 index 000000000..947d2f7f0 --- /dev/null +++ b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerContainer.java @@ -0,0 +1,100 @@ +package com.yogpc.qp.machine.placer; + +import com.yogpc.qp.PlatformAccess; +import com.yogpc.qp.QuarryPlus; +import com.yogpc.qp.machine.misc.SlotContainer; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public final class PlacerContainer extends AbstractContainerMenu { + public static final String PLACER_GUI_NAME = "gui_" + PlacerBlock.NAME; + public static final String REMOTE_PLACER_GUI_NAME = "gui_" + RemotePlacerBlock.NAME; + public static final String PLACER_GUI_ID = QuarryPlus.modID + ":" + PLACER_GUI_NAME; + public static final String REMOTE_PLACER_GUI_ID = QuarryPlus.modID + ":" + REMOTE_PLACER_GUI_NAME; + private static final int PLACER_START_X = 62; + private static final int REMOTE_PLACER_START_X = 26; + @NotNull + final AbstractPlacerTile tile; + final int startX; + + private PlacerContainer(@Nullable MenuType menuType, int containerId, Player player, BlockPos pos, int startX) { + super(menuType, containerId); + this.startX = startX; + tile = (AbstractPlacerTile) Objects.requireNonNull(player.level().getBlockEntity(pos)); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + this.addSlot(new SlotContainer(this.tile, j + i * 3, startX + j * 18, 17 + i * 18)); + } + } + + for (int k = 0; k < 3; ++k) { + for (int i1 = 0; i1 < 9; ++i1) { + this.addSlot(new Slot(player.getInventory(), i1 + k * 9 + 9, 8 + i1 * 18, 84 + k * 18)); + } + } + + for (int l = 0; l < 9; ++l) { + this.addSlot(new Slot(player.getInventory(), l, 8 + l * 18, 142)); + } + + if (!player.level().isClientSide) { + tile.syncToClient(); + } + } + + public static PlacerContainer createPlacerContainer(int containerId, Inventory inventory, BlockPos pos) { + return new PlacerContainer(PlatformAccess.getAccess().registerObjects().placerContainer().get(), containerId, inventory.player, pos, PLACER_START_X); + } + + public static PlacerContainer createRemotePlacerContainer(int containerId, Inventory inventory, BlockPos pos) { + return new PlacerContainer(PlatformAccess.getAccess().registerObjects().remotePlacerContainer().get(), containerId, inventory.player, pos, REMOTE_PLACER_START_X); + } + + @Override + public ItemStack quickMoveStack(Player player, int index) { + var allSlots = tile.getContainerSize(); + Slot slot = this.getSlot(index); + if (slot.hasItem()) { + ItemStack remain = slot.getItem(); + ItemStack slotContent = remain.copy(); + if (index < allSlots) { + if (!this.moveItemStackTo(remain, allSlots, 36 + allSlots, true)) { + return ItemStack.EMPTY; + } + } else if (!this.moveItemStackTo(remain, 0, allSlots, false)) { + return ItemStack.EMPTY; + } + + if (remain.isEmpty()) { + slot.set(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + + if (remain.getCount() == slotContent.getCount()) { + // Nothing moved + return ItemStack.EMPTY; + } + + slot.onTake(player, remain); + return slotContent; + } else { + return ItemStack.EMPTY; + } + } + + @Override + public boolean stillValid(Player player) { + return this.tile.stillValid(player); + } +} diff --git a/common/src/main/java/com/yogpc/qp/machine/placer/PlacerEntity.java b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerEntity.java new file mode 100644 index 000000000..45aca1107 --- /dev/null +++ b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerEntity.java @@ -0,0 +1,22 @@ +package com.yogpc.qp.machine.placer; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public final class PlacerEntity extends AbstractPlacerTile { + public PlacerEntity(BlockPos pos, BlockState blockState) { + super(pos, blockState); + } + + @Override + protected BlockPos getTargetPos() { + return getBlockPos().relative(getMachineFacing()); + } + + @Override + protected Direction getMachineFacing() { + return getBlockState().getValue(BlockStateProperties.FACING); + } +} diff --git a/common/src/main/java/com/yogpc/qp/machine/placer/PlacerScreen.java b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerScreen.java new file mode 100644 index 000000000..65a4b0158 --- /dev/null +++ b/common/src/main/java/com/yogpc/qp/machine/placer/PlacerScreen.java @@ -0,0 +1,58 @@ +package com.yogpc.qp.machine.placer; + +import com.yogpc.qp.QuarryPlus; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; + +public final class PlacerScreen extends AbstractContainerScreen { + private static final ResourceLocation LOCATION = ResourceLocation.fromNamespaceAndPath(QuarryPlus.modID, "textures/gui/replacer.png"); + + public PlacerScreen(PlacerContainer c, Inventory inventory, Component component) { + super(c, inventory, component); + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + this.renderBackground(graphics, mouseX, mouseY, delta); + super.render(graphics, mouseX, mouseY, delta); + this.renderTooltip(graphics, mouseX, mouseY); + } + + @Override + protected void renderBg(GuiGraphics graphics, float delta, int mouseX, int mouseY) { + graphics.blit(LOCATION, leftPos, topPos, 0, 0, imageWidth, imageHeight); + { + // red = 176, 0; start = 61, 16; + int oneBox = 18; + int x = getMenu().startX - 1 + (getMenu().tile.getLastPlacedIndex() % 3) * oneBox; + int y = 16 + (getMenu().tile.getLastPlacedIndex() / 3) * oneBox; + int pX = leftPos + x; + int pY = topPos + y; + graphics.blit(LOCATION, pX, pY, 176, 0, oneBox, oneBox); + } + } + + @Override + protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) { + super.renderLabels(graphics, mouseX, mouseY); + renderModeLabel(graphics); + } + + void renderModeLabel(GuiGraphics graphics) { + // Mode + AbstractPlacerTile.RedStoneMode mode = this.getMenu().tile.redstoneMode; + String pA = "Pulse"; + int x = 116; + graphics.drawString(font, pA, x, 6, 0x404040, false); + String rs = ""; + graphics.drawString(font, rs, x, 18, 0x404040, false); + String only; + if (mode.canBreak() && !mode.canPlace()) only = "Break Only"; + else if (mode.canPlace() && !mode.canBreak()) only = "Place Only"; + else only = ""; + graphics.drawString(font, only, x, 30, 0x404040, false); + } +} diff --git a/common/src/main/java/com/yogpc/qp/machine/placer/RemotePlacerBlock.java b/common/src/main/java/com/yogpc/qp/machine/placer/RemotePlacerBlock.java new file mode 100644 index 000000000..d615899c4 --- /dev/null +++ b/common/src/main/java/com/yogpc/qp/machine/placer/RemotePlacerBlock.java @@ -0,0 +1,5 @@ +package com.yogpc.qp.machine.placer; + +public final class RemotePlacerBlock { + public static final String NAME = "remote_placer"; +} diff --git a/common/src/test/java/com/yogpc/qp/machine/placer/AbstractPlacerTileTest.java b/common/src/test/java/com/yogpc/qp/machine/placer/AbstractPlacerTileTest.java new file mode 100644 index 000000000..f3c10ada5 --- /dev/null +++ b/common/src/test/java/com/yogpc/qp/machine/placer/AbstractPlacerTileTest.java @@ -0,0 +1,53 @@ +package com.yogpc.qp.machine.placer; + +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.OptionalInt; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static com.yogpc.qp.machine.placer.AbstractPlacerTile.findEntry; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AbstractPlacerTileTest { + @Test + void empty() { + List strings = Collections.emptyList(); + assertEquals(OptionalInt.empty(), findEntry(strings, always_true(), 0)); + } + + @Test + void singleton() { + List one = Collections.singletonList("one"); + assertEquals(OptionalInt.of(0), findEntry(one, always_true(), 0)); + assertEquals(OptionalInt.empty(), findEntry(one, Predicate.not(always_true()), 0)); + assertEquals(OptionalInt.empty(), findEntry(one, always_true(), 1)); + } + + @Test + void ten() { + List ten = IntStream.range(0, 10).boxed().collect(Collectors.toList()); + assertEquals(OptionalInt.of(0), findEntry(ten, i -> i % 2 == 0, 0)); + assertEquals(OptionalInt.of(2), findEntry(ten, i -> i % 2 == 0, 1)); + assertEquals(OptionalInt.of(2), findEntry(ten, i -> i % 2 == 0, 2)); + assertEquals(OptionalInt.of(4), findEntry(ten, i -> i % 2 == 0, 3)); + assertEquals(OptionalInt.of(4), findEntry(ten, i -> i % 2 == 0, 4)); + assertEquals(OptionalInt.of(5), findEntry(ten, i -> i % 5 == 0, 1)); + } + + @Test + void loop() { + List ten = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList()); + assertEquals(OptionalInt.empty(), findEntry(ten, Predicate.isEqual(0), 0)); + assertEquals(OptionalInt.of(0), findEntry(ten, Predicate.isEqual(1), 0)); + assertEquals(OptionalInt.of(0), findEntry(ten, Predicate.isEqual(1), 2)); + assertEquals(OptionalInt.of(0), findEntry(ten, Predicate.isEqual(1), 9)); + } + + private static Predicate always_true() { + return t -> true; + } +} diff --git a/fabric/game-test/server.properties b/fabric/game-test/server.properties index b93fdb121..e25af72fb 100644 --- a/fabric/game-test/server.properties +++ b/fabric/game-test/server.properties @@ -1,5 +1,5 @@ #Minecraft server properties -#Thu Oct 17 07:20:56 JST 2024 +#Tue Nov 05 00:59:39 JST 2024 accepts-transfers=false allow-flight=true allow-nether=true diff --git a/fabric/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json b/fabric/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json new file mode 100644 index 000000000..4a194868c --- /dev/null +++ b/fabric/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_dispenser": { + "conditions": { + "items": [ + { + "items": "minecraft:dispenser" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "quarryplus:placer_plus" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_dispenser" + ] + ], + "rewards": { + "recipes": [ + "quarryplus:placer_plus" + ] + } +} \ No newline at end of file diff --git a/fabric/src/generated/resources/data/quarryplus/recipe/placer_plus.json b/fabric/src/generated/resources/data/quarryplus/recipe/placer_plus.json new file mode 100644 index 000000000..77da19edd --- /dev/null +++ b/fabric/src/generated/resources/data/quarryplus/recipe/placer_plus.json @@ -0,0 +1,30 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "D": { + "item": "minecraft:dispenser" + }, + "G": { + "tag": "c:ingots/gold" + }, + "I": { + "tag": "c:ingots/iron" + }, + "M": { + "item": "minecraft:mossy_cobblestone" + }, + "R": { + "tag": "c:dusts/redstone" + } + }, + "pattern": [ + "GDG", + "MRM", + "MIM" + ], + "result": { + "count": 1, + "id": "quarryplus:placer_plus" + } +} \ No newline at end of file diff --git a/fabric/src/main/java/com/yogpc/qp/fabric/PlatformAccessFabric.java b/fabric/src/main/java/com/yogpc/qp/fabric/PlatformAccessFabric.java index 6a414b1a5..95485f867 100644 --- a/fabric/src/main/java/com/yogpc/qp/fabric/PlatformAccessFabric.java +++ b/fabric/src/main/java/com/yogpc/qp/fabric/PlatformAccessFabric.java @@ -26,6 +26,9 @@ import com.yogpc.qp.machine.mover.MoverBlock; import com.yogpc.qp.machine.mover.MoverContainer; import com.yogpc.qp.machine.mover.MoverEntity; +import com.yogpc.qp.machine.placer.PlacerBlock; +import com.yogpc.qp.machine.placer.PlacerContainer; +import com.yogpc.qp.machine.placer.PlacerEntity; import com.yogpc.qp.machine.quarry.QuarryBlock; import com.yogpc.qp.machine.storage.DebugStorageBlock; import com.yogpc.qp.machine.storage.DebugStorageContainer; @@ -107,6 +110,10 @@ public static final class RegisterObjectsFabric implements RegisterObjects { public static final MenuType DEBUG_STORAGE_MENU = new ExtendedScreenHandlerType<>(DebugStorageContainer::new, BlockPos.STREAM_CODEC); public static final FilterModuleItem FILTER_MODULE_ITEM = new FilterModuleItem(); public static final MenuType FILTER_MODULE_MENU = new ExtendedScreenHandlerType<>((i, inventory, pos) -> new FilterModuleContainer(i, inventory, inventory.getSelected()), BlockPos.STREAM_CODEC); + public static final PlacerBlock PLACER_BLOCK = new PlacerBlock(); + public static final BlockEntityType PLACER_ENTITY_TYPE = BlockEntityType.Builder.of(PlacerEntity::new, PLACER_BLOCK).build(DSL.emptyPartType()); + public static final MenuType PLACER_MENU_TYPE = new ExtendedScreenHandlerType<>(PlacerContainer::createPlacerContainer, BlockPos.STREAM_CODEC); + public static final MenuType REMOTE_PLACER_MENU_TYPE = new ExtendedScreenHandlerType<>(PlacerContainer::createRemotePlacerContainer, BlockPos.STREAM_CODEC); public static final LootItemFunctionType MACHINE_LOOT_FUNCTION = new LootItemFunctionType<>(MachineLootFunction.SERIALIZER); @@ -125,6 +132,7 @@ static void registerAll() { registerEntityBlock(ADV_QUARRY_BLOCK, ADV_QUARRY_ENTITY_TYPE, EnableMap.EnableOrNot.CONFIG_ON); registerEntityBlock(GENERATOR_BLOCK, GENERATOR_ENTITY_TYPE, EnableMap.EnableOrNot.ALWAYS_ON); registerEntityBlock(MOVER_BLOCK, MOVER_ENTITY_TYPE, EnableMap.EnableOrNot.CONFIG_ON); + registerEntityBlock(PLACER_BLOCK, PLACER_ENTITY_TYPE, EnableMap.EnableOrNot.CONFIG_ON); // Marker registerEntityBlock(MARKER_BLOCK, MARKER_ENTITY_TYPE, EnableMap.EnableOrNot.ALWAYS_ON); registerEntityBlock(FLEXIBLE_MARKER_BLOCK, FLEXIBLE_MARKER_ENTITY_TYPE, EnableMap.EnableOrNot.CONFIG_ON); @@ -150,6 +158,8 @@ static void registerAll() { Registry.register(BuiltInRegistries.MENU, ResourceLocation.fromNamespaceAndPath(QuarryPlus.modID, DebugStorageContainer.NAME), DEBUG_STORAGE_MENU); Registry.register(BuiltInRegistries.MENU, AdvQuarryContainer.GUI_ID, ADV_QUARRY_MENU); Registry.register(BuiltInRegistries.MENU, FilterModuleContainer.GUI_ID, FILTER_MODULE_MENU); + Registry.register(BuiltInRegistries.MENU, PlacerContainer.PLACER_GUI_ID, PLACER_MENU_TYPE); + Registry.register(BuiltInRegistries.MENU, PlacerContainer.REMOTE_PLACER_GUI_ID, REMOTE_PLACER_MENU_TYPE); Registry.register(BuiltInRegistries.LOOT_FUNCTION_TYPE, ResourceLocation.fromNamespaceAndPath(QuarryPlus.modID, MachineLootFunction.NAME), MACHINE_LOOT_FUNCTION); Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, ResourceLocation.fromNamespaceAndPath(QuarryPlus.modID, QuarryPlus.modID), TAB); for (Map.Entry> entry : QuarryDataComponents.ALL.entrySet()) { @@ -240,6 +250,11 @@ public Supplier softBlock() { return Lazy.value(SOFT_BLOCK); } + @Override + public Supplier placerBlock() { + return Lazy.value(PLACER_BLOCK); + } + @Override public Optional> getBlockEntityType(QpBlock block) { var t = BLOCK_ENTITY_TYPES.get(block.getClass()); @@ -305,6 +320,16 @@ public Supplier> filterModuleContainer return Lazy.value(FILTER_MODULE_MENU); } + @Override + public Supplier> placerContainer() { + return Lazy.value(PLACER_MENU_TYPE); + } + + @Override + public Supplier> remotePlacerContainer() { + return Lazy.value(REMOTE_PLACER_MENU_TYPE); + } + @Override public Supplier> machineLootFunction() { return Lazy.value(MACHINE_LOOT_FUNCTION); diff --git a/fabric/src/main/java/com/yogpc/qp/fabric/QuarryPlusFabricClient.java b/fabric/src/main/java/com/yogpc/qp/fabric/QuarryPlusFabricClient.java index 6f2d59eb1..7c148145b 100644 --- a/fabric/src/main/java/com/yogpc/qp/fabric/QuarryPlusFabricClient.java +++ b/fabric/src/main/java/com/yogpc/qp/fabric/QuarryPlusFabricClient.java @@ -10,6 +10,7 @@ import com.yogpc.qp.machine.module.FilterModuleScreen; import com.yogpc.qp.machine.module.ModuleScreen; import com.yogpc.qp.machine.mover.MoverScreen; +import com.yogpc.qp.machine.placer.PlacerScreen; import com.yogpc.qp.machine.storage.DebugStorageScreen; import com.yogpc.qp.render.*; import net.fabricmc.api.ClientModInitializer; @@ -39,6 +40,7 @@ public void onInitializeClient() { MenuScreens.register(PlatformAccessFabric.RegisterObjectsFabric.DEBUG_STORAGE_MENU, DebugStorageScreen::new); MenuScreens.register(PlatformAccessFabric.RegisterObjectsFabric.ADV_QUARRY_MENU, AdvQuarryScreen::new); MenuScreens.register(PlatformAccessFabric.RegisterObjectsFabric.FILTER_MODULE_MENU, FilterModuleScreen::new); + MenuScreens.register(PlatformAccessFabric.RegisterObjectsFabric.PLACER_MENU_TYPE, PlacerScreen::new); QuarryPlus.LOGGER.info("Initialize Client finished"); } } diff --git a/forge/game-test/server.properties b/forge/game-test/server.properties index ba051731b..92f77e2d1 100644 --- a/forge/game-test/server.properties +++ b/forge/game-test/server.properties @@ -1,5 +1,5 @@ #Minecraft server properties -#Thu Oct 17 07:20:57 JST 2024 +#Tue Nov 05 00:59:43 JST 2024 accepts-transfers=false allow-flight=true allow-nether=true diff --git a/forge/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json b/forge/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json new file mode 100644 index 000000000..4a194868c --- /dev/null +++ b/forge/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_dispenser": { + "conditions": { + "items": [ + { + "items": "minecraft:dispenser" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "quarryplus:placer_plus" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_dispenser" + ] + ], + "rewards": { + "recipes": [ + "quarryplus:placer_plus" + ] + } +} \ No newline at end of file diff --git a/forge/src/generated/resources/data/quarryplus/recipe/placer_plus.json b/forge/src/generated/resources/data/quarryplus/recipe/placer_plus.json new file mode 100644 index 000000000..77da19edd --- /dev/null +++ b/forge/src/generated/resources/data/quarryplus/recipe/placer_plus.json @@ -0,0 +1,30 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "D": { + "item": "minecraft:dispenser" + }, + "G": { + "tag": "c:ingots/gold" + }, + "I": { + "tag": "c:ingots/iron" + }, + "M": { + "item": "minecraft:mossy_cobblestone" + }, + "R": { + "tag": "c:dusts/redstone" + } + }, + "pattern": [ + "GDG", + "MRM", + "MIM" + ], + "result": { + "count": 1, + "id": "quarryplus:placer_plus" + } +} \ No newline at end of file diff --git a/forge/src/main/java/com/yogpc/qp/forge/PlatformAccessForge.java b/forge/src/main/java/com/yogpc/qp/forge/PlatformAccessForge.java index 672144c83..fe3a128db 100644 --- a/forge/src/main/java/com/yogpc/qp/forge/PlatformAccessForge.java +++ b/forge/src/main/java/com/yogpc/qp/forge/PlatformAccessForge.java @@ -30,6 +30,9 @@ import com.yogpc.qp.machine.mover.MoverBlock; import com.yogpc.qp.machine.mover.MoverContainer; import com.yogpc.qp.machine.mover.MoverEntity; +import com.yogpc.qp.machine.placer.PlacerBlock; +import com.yogpc.qp.machine.placer.PlacerContainer; +import com.yogpc.qp.machine.placer.PlacerEntity; import com.yogpc.qp.machine.quarry.QuarryBlock; import com.yogpc.qp.machine.storage.DebugStorageBlock; import com.yogpc.qp.machine.storage.DebugStorageContainer; @@ -97,6 +100,7 @@ public static class RegisterObjectsForge implements PlatformAccess.RegisterObjec public static final RegistryObject BLOCK_ADV_QUARRY = registerBlock(AdvQuarryBlock.NAME, AdvQuarryBlock::new); public static final RegistryObject BLOCK_GENERATOR = registerBlock(GeneratorBlock.NAME, GeneratorBlock::new); public static final RegistryObject BLOCK_MOVER = registerBlock(MoverBlock.NAME, MoverBlock::new); + public static final RegistryObject BLOCK_PLACER = registerBlock(PlacerBlock.NAME, PlacerBlock::new); // Marker public static final RegistryObject BLOCK_MARKER = registerBlock(NormalMarkerBlock.NAME, NormalMarkerBlock::new); public static final RegistryObject BLOCK_FLEXIBLE_MARKER = registerBlock(FlexibleMarkerBlock.NAME, FlexibleMarkerBlock::new); @@ -123,6 +127,7 @@ public static class RegisterObjectsForge implements PlatformAccess.RegisterObjec public static final RegistryObject> CHUNK_MARKER_ENTITY_TYPE = registerBlockEntity(ChunkMarkerBlock.NAME, BLOCK_CHUNK_MARKER, ChunkMarkerEntityForge::new, EnableMap.EnableOrNot.CONFIG_ON); public static final RegistryObject> DEBUG_STORAGE_TYPE = registerBlockEntity(DebugStorageBlock.NAME, BLOCK_DEBUG_STORAGE, DebugStorageEntity::new, EnableMap.EnableOrNot.ALWAYS_ON); public static final RegistryObject> ADV_QUARRY_ENTITY_TYPE = registerBlockEntity(AdvQuarryBlock.NAME, BLOCK_ADV_QUARRY, AdvQuarryEntityForge::new, EnableMap.EnableOrNot.CONFIG_ON); + public static final RegistryObject> PLACER_ENTITY_TYPE = registerBlockEntity(PlacerBlock.NAME, BLOCK_PLACER, PlacerEntity::new, EnableMap.EnableOrNot.CONFIG_ON); public static final RegistryObject> Y_SET_MENU_TYPE = registerMenu("gui_y_setter", YSetterContainer::new); public static final RegistryObject> MOVER_MENU_TYPE = registerMenu("gui_mover", MoverContainer::new); @@ -133,6 +138,8 @@ public static class RegisterObjectsForge implements PlatformAccess.RegisterObjec public static final RegistryObject> ADV_QUARRY_MENU_TYPE = registerMenu(AdvQuarryContainer.NAME, AdvQuarryContainer::new); public static final RegistryObject> FILTER_MODULE_MENU_TYPE = MENU_TYPE_REGISTER.register(FilterModuleContainer.NAME, () -> IForgeMenuType.create((windowId, inv, data) -> new FilterModuleContainer(windowId, inv, inv.getSelected()))); + public static final RegistryObject> PLACER_MENU_TYPE = registerMenu(PlacerContainer.PLACER_GUI_NAME, PlacerContainer::createPlacerContainer); + public static final RegistryObject> REMOTE_PLACER_MENU_TYPE = registerMenu(PlacerContainer.REMOTE_PLACER_GUI_NAME, PlacerContainer::createRemotePlacerContainer); public static final RegistryObject> MACHINE_LOOT_FUNCTION = LOOT_TYPE_REGISTER.register(MachineLootFunction.NAME, () -> new LootItemFunctionType<>(MachineLootFunction.SERIALIZER)); @@ -228,6 +235,11 @@ public Supplier softBlock() { return BLOCK_SOFT; } + @Override + public Supplier placerBlock() { + return BLOCK_PLACER; + } + @Override public Optional> getBlockEntityType(QpBlock block) { var t = BLOCK_ENTITY_TYPES.get(block.getClass()); @@ -293,6 +305,16 @@ public Supplier> filterModuleContainer return FILTER_MODULE_MENU_TYPE; } + @Override + public Supplier> placerContainer() { + return PLACER_MENU_TYPE; + } + + @Override + public Supplier> remotePlacerContainer() { + return REMOTE_PLACER_MENU_TYPE; + } + @Override public Supplier> machineLootFunction() { return MACHINE_LOOT_FUNCTION; diff --git a/forge/src/main/java/com/yogpc/qp/forge/QuarryPlusClientForge.java b/forge/src/main/java/com/yogpc/qp/forge/QuarryPlusClientForge.java index 2cc52da26..dd7633d06 100644 --- a/forge/src/main/java/com/yogpc/qp/forge/QuarryPlusClientForge.java +++ b/forge/src/main/java/com/yogpc/qp/forge/QuarryPlusClientForge.java @@ -8,6 +8,7 @@ import com.yogpc.qp.machine.module.FilterModuleScreen; import com.yogpc.qp.machine.module.ModuleScreen; import com.yogpc.qp.machine.mover.MoverScreen; +import com.yogpc.qp.machine.placer.PlacerScreen; import com.yogpc.qp.machine.storage.DebugStorageScreen; import com.yogpc.qp.render.*; import net.minecraft.client.gui.screens.MenuScreens; @@ -37,6 +38,7 @@ public static void clientInit(FMLClientSetupEvent event) { MenuScreens.register(PlatformAccessForge.RegisterObjectsForge.DEBUG_STORAGE_MENU_TYPE.get(), DebugStorageScreen::new); MenuScreens.register(PlatformAccessForge.RegisterObjectsForge.ADV_QUARRY_MENU_TYPE.get(), AdvQuarryScreen::new); MenuScreens.register(PlatformAccessForge.RegisterObjectsForge.FILTER_MODULE_MENU_TYPE.get(), FilterModuleScreen::new); + MenuScreens.register(PlatformAccessForge.RegisterObjectsForge.PLACER_MENU_TYPE.get(), PlacerScreen::new); QuarryPlus.LOGGER.info("Initialize Client finished"); } } diff --git a/neoforge/game-test/server.properties b/neoforge/game-test/server.properties index 53384dd03..ae13850ff 100644 --- a/neoforge/game-test/server.properties +++ b/neoforge/game-test/server.properties @@ -1,5 +1,5 @@ #Minecraft server properties -#Thu Oct 17 07:20:56 JST 2024 +#Tue Nov 05 00:59:44 JST 2024 accepts-transfers=false allow-flight=true allow-nether=true diff --git a/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/BlockDropProvider.scala b/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/BlockDropProvider.scala index e7d153f17..cb161cc2d 100644 --- a/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/BlockDropProvider.scala +++ b/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/BlockDropProvider.scala @@ -22,6 +22,7 @@ class BlockDropProvider(registries: HolderLookup.Provider) extends BlockLootSubP holder.flexibleMarkerBlock().get(), holder.chunkMarkerBlock().get(), holder.generatorBlock().get(), + holder.placerBlock().get(), ).foreach(this.dropSelf) Seq( diff --git a/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/StateAndModelProvider.java b/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/StateAndModelProvider.java index 5f4d9b9f8..bc5929300 100644 --- a/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/StateAndModelProvider.java +++ b/neoforge/src/commonDataGen/scala/com/yogpc/qp/common/data/StateAndModelProvider.java @@ -203,7 +203,7 @@ void simpleItem(QpItem item, ResourceLocation texture) { } void placer() { - /*QpBlock block = Holder.BLOCK_PLACER; + QpBlock block = PlatformAccessNeoForge.RegisterObjectsNeoForge.BLOCK_PLACER.get(); var basePath = block.name.getPath(); var model = models().orientableWithBottom("block/" + basePath, blockTexture("plus_stone_side"), @@ -218,7 +218,7 @@ void placer() { .rotationY(direction.getAxis() == Direction.Axis.Y ? 0 : Math.floorMod(((int) direction.toYRot()) + 180, 360)) .build(); }, BlockStateProperties.TRIGGERED); - simpleBlockItem(block, model);*/ + simpleBlockItem(block, model); } void mining_well() { diff --git a/neoforge/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json b/neoforge/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json new file mode 100644 index 000000000..4a194868c --- /dev/null +++ b/neoforge/src/generated/resources/data/quarryplus/advancement/recipes/misc/placer_plus.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_dispenser": { + "conditions": { + "items": [ + { + "items": "minecraft:dispenser" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "quarryplus:placer_plus" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_dispenser" + ] + ], + "rewards": { + "recipes": [ + "quarryplus:placer_plus" + ] + } +} \ No newline at end of file diff --git a/neoforge/src/generated/resources/data/quarryplus/recipe/placer_plus.json b/neoforge/src/generated/resources/data/quarryplus/recipe/placer_plus.json new file mode 100644 index 000000000..77da19edd --- /dev/null +++ b/neoforge/src/generated/resources/data/quarryplus/recipe/placer_plus.json @@ -0,0 +1,30 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "D": { + "item": "minecraft:dispenser" + }, + "G": { + "tag": "c:ingots/gold" + }, + "I": { + "tag": "c:ingots/iron" + }, + "M": { + "item": "minecraft:mossy_cobblestone" + }, + "R": { + "tag": "c:dusts/redstone" + } + }, + "pattern": [ + "GDG", + "MRM", + "MIM" + ], + "result": { + "count": 1, + "id": "quarryplus:placer_plus" + } +} \ No newline at end of file diff --git a/neoforge/src/main/java/com/yogpc/qp/neoforge/PlatformAccessNeoForge.java b/neoforge/src/main/java/com/yogpc/qp/neoforge/PlatformAccessNeoForge.java index 6c96901c5..3b83cce83 100644 --- a/neoforge/src/main/java/com/yogpc/qp/neoforge/PlatformAccessNeoForge.java +++ b/neoforge/src/main/java/com/yogpc/qp/neoforge/PlatformAccessNeoForge.java @@ -18,6 +18,9 @@ import com.yogpc.qp.machine.mover.MoverBlock; import com.yogpc.qp.machine.mover.MoverContainer; import com.yogpc.qp.machine.mover.MoverEntity; +import com.yogpc.qp.machine.placer.PlacerBlock; +import com.yogpc.qp.machine.placer.PlacerContainer; +import com.yogpc.qp.machine.placer.PlacerEntity; import com.yogpc.qp.machine.quarry.QuarryBlock; import com.yogpc.qp.machine.storage.DebugStorageBlock; import com.yogpc.qp.machine.storage.DebugStorageContainer; @@ -89,6 +92,7 @@ public static class RegisterObjectsNeoForge implements PlatformAccess.RegisterOb public static final DeferredBlock BLOCK_ADV_QUARRY = registerBlock(AdvQuarryBlock.NAME, AdvQuarryBlock::new); public static final DeferredBlock BLOCK_GENERATOR = registerBlock(GeneratorBlock.NAME, GeneratorBlock::new); public static final DeferredBlock BLOCK_MOVER = registerBlock(MoverBlock.NAME, MoverBlock::new); + public static final DeferredBlock BLOCK_PLACER = registerBlock(PlacerBlock.NAME, PlacerBlock::new); // Marker public static final DeferredBlock BLOCK_MARKER = registerBlock(NormalMarkerBlock.NAME, NormalMarkerBlock::new); public static final DeferredBlock BLOCK_FLEXIBLE_MARKER = registerBlock(FlexibleMarkerBlock.NAME, FlexibleMarkerBlock::new); @@ -115,6 +119,7 @@ public static class RegisterObjectsNeoForge implements PlatformAccess.RegisterOb public static final DeferredHolder, BlockEntityType> CHUNK_MARKER_ENTITY_TYPE = registerBlockEntity(ChunkMarkerBlock.NAME, BLOCK_CHUNK_MARKER, ChunkMarkerEntity::new, EnableMap.EnableOrNot.CONFIG_ON); public static final DeferredHolder, BlockEntityType> DEBUG_STORAGE_TYPE = registerBlockEntity(DebugStorageBlock.NAME, BLOCK_DEBUG_STORAGE, DebugStorageEntity::new, EnableMap.EnableOrNot.ALWAYS_ON); public static final DeferredHolder, BlockEntityType> ADV_QUARRY_ENTITY_TYPE = registerBlockEntity(AdvQuarryBlock.NAME, BLOCK_ADV_QUARRY, AdvQuarryEntityNeoForge::new, EnableMap.EnableOrNot.CONFIG_ON); + public static final DeferredHolder, BlockEntityType> PLACER_ENTITY_TYPE = registerBlockEntity(PlacerBlock.NAME, BLOCK_PLACER, PlacerEntity::new, EnableMap.EnableOrNot.CONFIG_ON); public static final DeferredHolder CREATIVE_MODE_TAB = CREATIVE_TAB_REGISTER.register(QuarryPlus.modID, () -> QuarryPlus.buildCreativeModeTab(CreativeModeTab.builder()).build()); public static final DeferredHolder, MenuType> Y_SET_MENU_TYPE = registerMenu("gui_y_setter", YSetterContainer::new); @@ -126,6 +131,8 @@ public static class RegisterObjectsNeoForge implements PlatformAccess.RegisterOb public static final DeferredHolder, MenuType> ADV_QUARRY_MENU_TYPE = registerMenu(AdvQuarryContainer.NAME, AdvQuarryContainer::new); public static final DeferredHolder, MenuType> FILTER_MODULE_MENU_TYPE = MENU_TYPE_REGISTER.register(FilterModuleContainer.NAME, () -> IMenuTypeExtension.create((windowId, inv, data) -> new FilterModuleContainer(windowId, inv, inv.getSelected()))); + public static final DeferredHolder, MenuType> PLACER_MENU_TYPE = registerMenu(PlacerContainer.PLACER_GUI_NAME, PlacerContainer::createPlacerContainer); + public static final DeferredHolder, MenuType> REMOTE_PLACER_MENU_TYPE = registerMenu(PlacerContainer.REMOTE_PLACER_GUI_NAME, PlacerContainer::createRemotePlacerContainer); public static final DeferredHolder, LootItemFunctionType> MACHINE_LOOT_FUNCTION = LOOT_TYPE_REGISTER.register(MachineLootFunction.NAME, () -> new LootItemFunctionType<>(MachineLootFunction.SERIALIZER)); public static final DeferredHolder, RecipeSerializer> INSTALL_BEDROCK_MODULE_RECIPE = RECIPE_REGISTER.register(InstallBedrockModuleRecipe.NAME, () -> InstallBedrockModuleRecipe.SERIALIZER); @@ -219,6 +226,11 @@ public Supplier softBlock() { return BLOCK_SOFT; } + @Override + public Supplier placerBlock() { + return BLOCK_PLACER; + } + @Override public Optional> getBlockEntityType(QpBlock block) { var t = BLOCK_ENTITY_TYPES.get(block.getClass()); @@ -284,6 +296,16 @@ public Supplier> filterModuleContainer return FILTER_MODULE_MENU_TYPE; } + @Override + public Supplier> placerContainer() { + return PLACER_MENU_TYPE; + } + + @Override + public Supplier> remotePlacerContainer() { + return REMOTE_PLACER_MENU_TYPE; + } + @Override public Supplier> machineLootFunction() { return MACHINE_LOOT_FUNCTION; diff --git a/neoforge/src/main/java/com/yogpc/qp/neoforge/QuarryPlusClientNeoForge.java b/neoforge/src/main/java/com/yogpc/qp/neoforge/QuarryPlusClientNeoForge.java index d4a72a803..1a697f5e1 100644 --- a/neoforge/src/main/java/com/yogpc/qp/neoforge/QuarryPlusClientNeoForge.java +++ b/neoforge/src/main/java/com/yogpc/qp/neoforge/QuarryPlusClientNeoForge.java @@ -8,6 +8,7 @@ import com.yogpc.qp.machine.module.FilterModuleScreen; import com.yogpc.qp.machine.module.ModuleScreen; import com.yogpc.qp.machine.mover.MoverScreen; +import com.yogpc.qp.machine.placer.PlacerScreen; import com.yogpc.qp.machine.storage.DebugStorageScreen; import com.yogpc.qp.neoforge.render.RenderChunkMarkerNeoForge; import com.yogpc.qp.neoforge.render.RenderFlexibleMarkerNeoForge; @@ -41,5 +42,6 @@ public static void registerMenu(RegisterMenuScreensEvent event) { event.register(PlatformAccessNeoForge.RegisterObjectsNeoForge.DEBUG_STORAGE_MENU_TYPE.get(), DebugStorageScreen::new); event.register(PlatformAccessNeoForge.RegisterObjectsNeoForge.ADV_QUARRY_MENU_TYPE.get(), AdvQuarryScreen::new); event.register(PlatformAccessNeoForge.RegisterObjectsNeoForge.FILTER_MODULE_MENU_TYPE.get(), FilterModuleScreen::new); + event.register(PlatformAccessNeoForge.RegisterObjectsNeoForge.PLACER_MENU_TYPE.get(), PlacerScreen::new); } }