Skip to content

Commit

Permalink
Merge pull request #669 from Kotori316/1.21-placer
Browse files Browse the repository at this point in the history
[1.21.1] Placer Plus
  • Loading branch information
Kotori316 authored Nov 7, 2024
2 parents 8653af1 + 5648fdb commit 0a6a4fa
Show file tree
Hide file tree
Showing 34 changed files with 1,259 additions and 6 deletions.
12 changes: 12 additions & 0 deletions common/src/dataGen/scala/com/yogpc/qp/data/Recipe.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -51,11 +52,12 @@ public static List<TestFunction> 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<TestFunction> getTestFunctionStream(String batchName, String structureName, List<Class<?>> classes, int maxTicks) {
public static @NotNull Stream<TestFunction> getTestFunctionStream(String batchName, String structureName, List<Class<?>> classes, int maxTicks) {
return classes.stream()
.flatMap(c -> Stream.of(c.getDeclaredMethods()))
.filter(Predicate.not(Method::isSynthetic))
Expand Down
24 changes: 24 additions & 0 deletions common/src/gameTest/java/com/yogpc/qp/gametest/LoadRecipeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}
195 changes: 195 additions & 0 deletions common/src/gameTest/java/com/yogpc/qp/machine/placer/PlacerTest.java
Original file line number Diff line number Diff line change
@@ -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<TestFunction> 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<TestFunction> 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<TestFunction> 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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"parent": "quarryplus:block/placer_plus"
}
Original file line number Diff line number Diff line change
@@ -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"
}
8 changes: 8 additions & 0 deletions common/src/main/java/com/yogpc/qp/PlatformAccess.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -82,6 +84,8 @@ interface RegisterObjects {

Supplier<? extends SoftBlock> softBlock();

Supplier<? extends PlacerBlock> placerBlock();

Optional<BlockEntityType<?>> getBlockEntityType(QpBlock block);

default Collection<? extends BlockEntityType<?>> getBlockEntityTypes() {
Expand Down Expand Up @@ -113,6 +117,10 @@ default Collection<? extends BlockEntityType<?>> getBlockEntityTypes() {

Supplier<MenuType<? extends FilterModuleContainer>> filterModuleContainer();

Supplier<MenuType<? extends PlacerContainer>> placerContainer();

Supplier<MenuType<? extends PlacerContainer>> remotePlacerContainer();

Supplier<LootItemFunctionType<? extends MachineLootFunction>> machineLootFunction();
}

Expand Down
Loading

0 comments on commit 0a6a4fa

Please sign in to comment.