Merge branch 'mc1.18/dev' into mc1.19/dev

# Conflicts:
#	src/main/java/com/simibubi/create/infrastructure/gametest/tests/TestFluids.java
This commit is contained in:
TropheusJ 2023-06-30 01:25:12 -04:00
commit c77bcbfabf
33 changed files with 486 additions and 50 deletions

View File

@ -4,15 +4,17 @@
name: Crowdin Action
# Controls when the action will run.
on:
on: workflow_dispatch
# Only run when started manually
workflow_dispatch:
inputs:
uploadTranslations:
description: "Set to true to upload (changed) translations to Crowdin"
type: boolean
required: true
default: false
#:
# inputs:
# uploadTranslations:
# description: "Set to true to upload (changed) translations to Crowdin"
# type: boolean
# required: true
# default: false
#schedule:
#- cron: '0 */6 * * *' # Every 6 hours - https://crontab.guru/#0_*/6_*_*_*
@ -30,7 +32,7 @@ jobs:
# Upload sources to Crowdin
upload_sources: true
# Upload translations to Crowdin, only use true at initial run
upload_translations: ${{ github.event.inputs.uploadTranslations }}
upload_translations: false
# Make pull request of Crowdin translations
download_translations: true
# To download translations to the specified version branch

View File

@ -11,6 +11,7 @@
"languages_mapping": {
"locale_with_underscore": {
"cs": "cs_cz",
"cy": "cy_gb",
"da": "da_dk",
"de": "de_de",
"eo": "eo_uy",

View File

@ -353,4 +353,7 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity
angle = forcedAngle;
}
public ControlledContraptionEntity getMovedContraption() {
return movedContraption;
}
}

View File

@ -163,7 +163,7 @@ public class PulleyBlockEntity extends LinearActuatorBlockEntity implements Thre
}
}
}
if (mirrorParent != null)
removeRopes();
@ -284,7 +284,7 @@ public class PulleyBlockEntity extends LinearActuatorBlockEntity implements Thre
if (prevMirrorParent == null || !prevMirrorParent.equals(mirrorParent))
sharedMirrorContraption = null;
}
if (compound.contains("MirrorChildren"))
mirrorChildren = NBTHelper.readCompoundList(compound.getList("MirrorChildren", Tag.TAG_COMPOUND),
NbtUtils::readBlockPos);
@ -379,4 +379,8 @@ public class PulleyBlockEntity extends LinearActuatorBlockEntity implements Thre
return 100;
return 100 * getInterpolatedOffset(.5f) / distance;
}
public BlockPos getMirrorParent() {
return mirrorParent;
}
}

View File

@ -3,7 +3,19 @@ package com.simibubi.create.infrastructure.gametest;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovingInteraction;
import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.kinetics.gauge.SpeedGaugeBlockEntity;
import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.lang3.tuple.MutablePair;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@ -27,6 +39,7 @@ import net.minecraft.core.Registry;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.gametest.framework.GameTestInfo;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity;
@ -40,6 +53,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
@ -80,7 +94,7 @@ public class CreateGameTestHelper extends GameTestHelper {
public void flipBlock(BlockPos pos) {
BlockState original = getBlockState(pos);
if (!original.hasProperty(BlockStateProperties.FACING))
fail("FACING property not in block: " + Registry.BLOCK.getId(original.getBlock()));
fail("FACING property not in block: " + ForgeRegistries.BLOCKS.getKey(original.getBlock()));
Direction facing = original.getValue(BlockStateProperties.FACING);
BlockState reversed = original.setValue(BlockStateProperties.FACING, facing.getOpposite());
setBlock(pos, reversed);
@ -123,6 +137,34 @@ public class CreateGameTestHelper extends GameTestHelper {
behavior.setValue(mode.ordinal());
}
public void assertSpeedometerSpeed(BlockPos speedometer, float value) {
SpeedGaugeBlockEntity be = getBlockEntity(AllBlockEntityTypes.SPEEDOMETER.get(), speedometer);
assertInRange(be.getSpeed(), value - 0.01, value + 0.01);
}
public void assertStressometerCapacity(BlockPos stressometer, float value) {
StressGaugeBlockEntity be = getBlockEntity(AllBlockEntityTypes.STRESSOMETER.get(), stressometer);
assertInRange(be.getNetworkCapacity(), value - 0.01, value + 0.01);
}
public void toggleActorsOfType(Contraption contraption, ItemLike item) {
AtomicBoolean toggled = new AtomicBoolean(false);
contraption.getInteractors().forEach((localPos, behavior) -> {
if (toggled.get() || !(behavior instanceof ContraptionControlsMovingInteraction controls))
return;
MutablePair<StructureBlockInfo, MovementContext> actor = contraption.getActorAt(localPos);
if (actor == null)
return;
ItemStack filter = ContraptionControlsMovement.getFilter(actor.right);
if (filter != null && filter.is(item.asItem())) {
controls.handlePlayerInteraction(
makeMockPlayer(), InteractionHand.MAIN_HAND, localPos, contraption.entity
);
toggled.set(true);
}
});
}
// block entities
/**

View File

@ -1,11 +1,20 @@
package com.simibubi.create.infrastructure.gametest.tests;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllEntityTypes;
import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlockEntity;
import com.simibubi.create.content.contraptions.elevator.ElevatorPulleyBlockEntity;
import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlock;
import com.simibubi.create.infrastructure.gametest.CreateGameTestHelper;
import com.simibubi.create.infrastructure.gametest.GameTestGroup;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import net.minecraft.core.BlockPos;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.world.entity.EntityType;
@ -13,6 +22,9 @@ import net.minecraft.world.entity.projectile.Arrow;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.LeverBlock;
import net.minecraft.world.level.block.RedstoneLampBlock;
import net.minecraftforge.fluids.FluidStack;
@GameTestGroup(path = "contraptions")
@ -89,6 +101,128 @@ public class TestContraptions {
helper.succeedWhen(() -> helper.assertBlockPresent(Blocks.DIAMOND_BLOCK, end));
}
@GameTest(template = "controls", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void controls(CreateGameTestHelper helper) {
BlockPos button = new BlockPos(5, 5, 4);
BlockPos gearshift = new BlockPos(4, 5, 4);
BlockPos bearingPos = new BlockPos(4, 4, 4);
AtomicInteger step = new AtomicInteger(1);
List<BlockPos> dirt = List.of(new BlockPos(4, 2, 6), new BlockPos(2, 2, 4), new BlockPos(4, 2, 2));
List<BlockPos> wheat = List.of(new BlockPos(4, 3, 7), new BlockPos(1, 3, 4), new BlockPos(4, 3, 1));
helper.pressButton(button);
helper.succeedWhen(() -> {
// wait for gearshift to reset
helper.assertBlockProperty(gearshift, SequencedGearshiftBlock.STATE, 0);
if (step.get() == 4)
return; // step 4: all done!
MechanicalBearingBlockEntity bearing = helper.getBlockEntity(AllBlockEntityTypes.MECHANICAL_BEARING.get(), bearingPos);
if (bearing.getMovedContraption() == null)
helper.fail("Contraption not assembled");
Contraption contraption = bearing.getMovedContraption().getContraption();
switch (step.get()) {
case 1 -> { // step 1: both should be active
helper.assertBlockPresent(Blocks.FARMLAND, dirt.get(0));
helper.assertBlockProperty(wheat.get(0), CropBlock.AGE, 0);
// now disable harvester
helper.toggleActorsOfType(contraption, AllBlocks.MECHANICAL_HARVESTER.get());
helper.pressButton(button);
step.incrementAndGet();
helper.fail("Entering step 2");
}
case 2 -> { // step 2: harvester disabled
helper.assertBlockPresent(Blocks.FARMLAND, dirt.get(1));
helper.assertBlockProperty(wheat.get(1), CropBlock.AGE, 7);
// now disable plough
helper.toggleActorsOfType(contraption, AllBlocks.MECHANICAL_PLOUGH.get());
helper.pressButton(button);
step.incrementAndGet();
helper.fail("Entering step 3");
}
case 3 -> { // step 3: both disabled
helper.assertBlockPresent(Blocks.DIRT, dirt.get(2));
helper.assertBlockProperty(wheat.get(2), CropBlock.AGE, 7);
// successful!
helper.pressButton(button);
step.incrementAndGet();
helper.fail("Entering step 4");
}
}
});
}
@GameTest(template = "elevator")
public static void elevator(CreateGameTestHelper helper) {
BlockPos pulley = new BlockPos(5, 12, 3);
BlockPos secondaryPulley = new BlockPos(5, 12, 1);
BlockPos bottomLamp = new BlockPos(2, 3, 2);
BlockPos topLamp = new BlockPos(2, 12, 2);
BlockPos lever = new BlockPos(1, 11, 2);
BlockPos elevatorStart = new BlockPos(4, 2, 2);
BlockPos cowSpawn = new BlockPos(4, 4, 2);
BlockPos cowEnd = new BlockPos(4, 13, 2);
helper.runAtTickTime(1, () -> helper.spawn(EntityType.COW, cowSpawn));
helper.runAtTickTime(
15, () -> helper.getBlockEntity(AllBlockEntityTypes.ELEVATOR_PULLEY.get(), pulley).clicked()
);
helper.succeedWhen(() -> {
helper.assertSecondsPassed(1);
if (!helper.getBlockState(lever).getValue(LeverBlock.POWERED)) { // step 1: check entity, lamps, and secondary, then move up
helper.getFirstEntity(AllEntityTypes.CONTROLLED_CONTRAPTION.get(), elevatorStart); // make sure entity exists
helper.assertBlockProperty(topLamp, RedstoneLampBlock.LIT, false);
helper.assertBlockProperty(bottomLamp, RedstoneLampBlock.LIT, true);
ElevatorPulleyBlockEntity secondary = helper.getBlockEntity(AllBlockEntityTypes.ELEVATOR_PULLEY.get(), secondaryPulley);
if (secondary.getMirrorParent() == null)
helper.fail("Secondary pulley has no parent");
helper.pullLever(lever);
helper.fail("Entering step 2");
} else { // step 2: wait for top lamp and cow passenger
helper.assertBlockProperty(topLamp, RedstoneLampBlock.LIT, true);
helper.assertBlockProperty(bottomLamp, RedstoneLampBlock.LIT, false);
helper.assertEntityPresent(EntityType.COW, cowEnd);
// all done, disassemble
helper.getBlockEntity(AllBlockEntityTypes.ELEVATOR_PULLEY.get(), pulley).clicked();
}
});
}
@GameTest(template = "roller_filling")
public static void rollerFilling(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(7, 6, 1);
BlockPos barrelEnd = new BlockPos(2, 5, 2);
List<BlockPos> existing = BlockPos.betweenClosedStream(new BlockPos(1, 3, 2), new BlockPos(4, 2, 2)).toList();
List<BlockPos> filled = BlockPos.betweenClosedStream(new BlockPos(1, 2, 1), new BlockPos(4, 3, 3))
.filter(pos -> !existing.contains(pos)).toList();
List<BlockPos> tracks = BlockPos.betweenClosedStream(new BlockPos(1, 4, 2), new BlockPos(4, 4, 2)).toList();
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertSecondsPassed(4);
existing.forEach(pos -> helper.assertBlockPresent(AllBlocks.RAILWAY_CASING.get(), pos));
filled.forEach(pos -> helper.assertBlockPresent(AllBlocks.ANDESITE_CASING.get(), pos));
tracks.forEach(pos -> helper.assertBlockPresent(AllBlocks.TRACK.get(), pos));
helper.assertContainerEmpty(barrelEnd);
});
}
@GameTest(template = "roller_paving_and_clearing", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void rollerPavingAndClearing(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(8, 5, 1);
List<BlockPos> paved = BlockPos.betweenClosedStream(new BlockPos(1, 2, 1), new BlockPos(4, 2, 1)).toList();
// block above will be cleared too, but will later be replaced by the contraption's barrel
BlockPos cleared = new BlockPos(2, 3, 1);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertSecondsPassed(9);
paved.forEach(pos -> helper.assertBlockPresent(AllBlocks.ANDESITE_CASING.get(), pos));
helper.assertBlockPresent(Blocks.AIR, cleared);
});
}
// FIXME: trains do not enjoy being loaded in structures
// https://gist.github.com/TropheusJ/f2d0a7df48360d2e078d0987c115c6ef
// @GameTest(template = "train_observer")

View File

@ -1,55 +1,62 @@
package com.simibubi.create.infrastructure.gametest.tests;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.content.fluids.hosePulley.HosePulleyFluidHandler;
import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlock;
import com.simibubi.create.content.kinetics.gauge.SpeedGaugeBlockEntity;
import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity;
import com.simibubi.create.content.kinetics.waterwheel.WaterWheelBlockEntity;
import com.simibubi.create.infrastructure.gametest.CreateGameTestHelper;
import com.simibubi.create.infrastructure.gametest.GameTestGroup;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestAssertException;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Mth;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
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.RedStoneWireBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.RedstoneSide;
import net.minecraft.world.level.block.LeverBlock;
import net.minecraft.world.level.block.RedstoneLampBlock;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidType;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.registries.ForgeRegistries;
@GameTestGroup(path = "fluids")
public class TestFluids {
@GameTest(template = "hose_pulley_transfer", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS)
public static void hosePulleyTransfer(CreateGameTestHelper helper) {
// there was supposed to be redstone here built in, but it kept popping off, so put it there manually
BlockPos brokenRedstone = new BlockPos(4, 8, 3);
BlockState redstone = Blocks.REDSTONE_WIRE.defaultBlockState()
.setValue(RedStoneWireBlock.NORTH, RedstoneSide.NONE)
.setValue(RedStoneWireBlock.SOUTH, RedstoneSide.NONE)
.setValue(RedStoneWireBlock.EAST, RedstoneSide.UP)
.setValue(RedStoneWireBlock.WEST, RedstoneSide.SIDE)
.setValue(RedStoneWireBlock.POWER, 14);
helper.setBlock(brokenRedstone, redstone);
// pump
BlockPos lever = new BlockPos(6, 9, 3);
BlockPos lever = new BlockPos(7, 7, 5);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertSecondsPassed(15);
// check filled
BlockPos filledLowerCorner = new BlockPos(8, 3, 2);
BlockPos filledUpperCorner = new BlockPos(10, 5, 4);
BlockPos filledLowerCorner = new BlockPos(2, 3, 2);
BlockPos filledUpperCorner = new BlockPos(4, 5, 4);
BlockPos.betweenClosed(filledLowerCorner, filledUpperCorner)
.forEach(pos -> helper.assertBlockPresent(Blocks.WATER, pos));
// check emptied
BlockPos emptiedLowerCorner = new BlockPos(2, 3, 2);
BlockPos emptiedUpperCorner = new BlockPos(4, 5, 4);
BlockPos emptiedLowerCorner = new BlockPos(8, 3, 2);
BlockPos emptiedUpperCorner = new BlockPos(10, 5, 4);
BlockPos.betweenClosed(emptiedLowerCorner, emptiedUpperCorner)
.forEach(pos -> helper.assertBlockPresent(Blocks.AIR, pos));
// check nothing left in pulley
BlockPos pulleyPos = new BlockPos(8, 7, 4);
BlockPos pulleyPos = new BlockPos(4, 7, 3);
IFluidHandler storage = helper.fluidStorageAt(pulleyPos);
if (storage instanceof HosePulleyFluidHandler hose) {
IFluidHandler internalTank = hose.getInternalTank();
@ -62,27 +69,27 @@ public class TestFluids {
}
@GameTest(template = "in_world_pumping_out")
public static void inWorldPumpingOutput(CreateGameTestHelper helper) {
BlockPos pumpPos = new BlockPos(3, 2, 2);
BlockPos waterPos = pumpPos.west();
BlockPos basinPos = pumpPos.east();
helper.flipBlock(pumpPos);
public static void inWorldPumpingOut(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(4, 3, 3);
BlockPos basin = new BlockPos(5, 2, 2);
BlockPos output = new BlockPos(2, 2, 2);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertBlockPresent(Blocks.WATER, waterPos);
helper.assertTankEmpty(basinPos);
helper.assertBlockPresent(Blocks.WATER, output);
helper.assertTankEmpty(basin);
});
}
@GameTest(template = "in_world_pumping_in")
public static void inWorldPumpingPickup(CreateGameTestHelper helper) {
BlockPos pumpPos = new BlockPos(3, 2, 2);
BlockPos basinPos = pumpPos.east();
BlockPos waterPos = pumpPos.west();
public static void inWorldPumpingIn(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(4, 3, 3);
BlockPos basin = new BlockPos(5, 2, 2);
BlockPos water = new BlockPos(2, 2, 2);
FluidStack expectedResult = new FluidStack(Fluids.WATER, FluidType.BUCKET_VOLUME);
helper.flipBlock(pumpPos);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertBlockPresent(Blocks.AIR, waterPos);
helper.assertFluidPresent(expectedResult, basinPos);
helper.assertBlockPresent(Blocks.AIR, water);
helper.assertFluidPresent(expectedResult, basin);
});
}
@ -147,4 +154,151 @@ public class TestFluids {
}
});
}
@GameTest(template = "large_waterwheel", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void largeWaterwheel(CreateGameTestHelper helper) {
BlockPos wheel = new BlockPos(4, 3, 2);
BlockPos leftEnd = new BlockPos(6, 2, 2);
BlockPos rightEnd = new BlockPos(2, 2, 2);
List<BlockPos> edges = List.of(new BlockPos(4, 5, 1), new BlockPos(4, 5, 3));
BlockPos openLever = new BlockPos(3, 8, 1);
BlockPos leftLever = new BlockPos(5, 7, 1);
waterwheel(helper, wheel, 4, 512, leftEnd, rightEnd, edges, openLever, leftLever);
}
@GameTest(template = "small_waterwheel", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void smallWaterwheel(CreateGameTestHelper helper) {
BlockPos wheel = new BlockPos(3, 2, 2);
BlockPos leftEnd = new BlockPos(4, 2, 2);
BlockPos rightEnd = new BlockPos(2, 2, 2);
List<BlockPos> edges = List.of(new BlockPos(3, 3, 1), new BlockPos(3, 3, 3));
BlockPos openLever = new BlockPos(2, 6, 1);
BlockPos leftLever = new BlockPos(4, 5, 1);
waterwheel(helper, wheel, 8, 128, leftEnd, rightEnd, edges, openLever, leftLever);
}
private static void waterwheel(CreateGameTestHelper helper,
BlockPos wheel, float expectedRpm, float expectedSU,
BlockPos leftEnd, BlockPos rightEnd, List<BlockPos> edges,
BlockPos openLever, BlockPos leftLever) {
BlockPos speedometer = wheel.north();
BlockPos stressometer = wheel.south();
helper.pullLever(openLever);
helper.succeedWhen(() -> {
// must always be true
edges.forEach(pos -> helper.assertBlockNotPresent(Blocks.WATER, pos));
helper.assertBlockPresent(Blocks.WATER, rightEnd);
// first step: expect water on left end while flow is allowed
if (!helper.getBlockState(leftLever).getValue(LeverBlock.POWERED)) {
helper.assertBlockPresent(Blocks.WATER, leftEnd);
// water is present. both sides should cancel.
helper.assertSpeedometerSpeed(speedometer, 0);
helper.assertStressometerCapacity(stressometer, 0);
// success, pull the lever, enter step 2
helper.powerLever(leftLever);
helper.fail("Entering step 2");
} else {
// lever is pulled, flow should stop
helper.assertBlockNotPresent(Blocks.WATER, leftEnd);
// 1-sided flow, should be spinning
helper.assertSpeedometerSpeed(speedometer, expectedRpm);
helper.assertStressometerCapacity(stressometer, expectedSU);
}
});
}
@GameTest(template = "waterwheel_materials", timeoutTicks = CreateGameTestHelper.FIFTEEN_SECONDS)
public static void waterwheelMaterials(CreateGameTestHelper helper) {
List<Item> planks = ForgeRegistries.BLOCKS.tags().getTag(BlockTags.PLANKS).stream()
.map(ItemLike::asItem).collect(Collectors.toCollection(ArrayList::new));
List<BlockPos> chests = List.of(new BlockPos(6, 4, 2), new BlockPos(6, 4, 3));
List<BlockPos> deployers = chests.stream().map(pos -> pos.below(2)).toList();
helper.runAfterDelay(3, () -> chests.forEach(chest ->
planks.forEach(plank -> ItemHandlerHelper.insertItem(helper.itemStorageAt(chest), new ItemStack(plank), false))
));
BlockPos smallWheel = new BlockPos(4, 2, 2);
BlockPos largeWheel = new BlockPos(3, 3, 3);
BlockPos lever = new BlockPos(5, 3, 1);
helper.pullLever(lever);
helper.succeedWhen(() -> {
Item plank = planks.get(0);
if (!(plank instanceof BlockItem blockItem))
throw new GameTestAssertException(ForgeRegistries.ITEMS.getKey(plank) + " is not a BlockItem");
Block block = blockItem.getBlock();
WaterWheelBlockEntity smallWheelBe = helper.getBlockEntity(AllBlockEntityTypes.WATER_WHEEL.get(), smallWheel);
if (!smallWheelBe.material.is(block))
helper.fail("Small waterwheel has not consumed " + ForgeRegistries.ITEMS.getKey(plank));
WaterWheelBlockEntity largeWheelBe = helper.getBlockEntity(AllBlockEntityTypes.LARGE_WATER_WHEEL.get(), largeWheel);
if (!largeWheelBe.material.is(block))
helper.fail("Large waterwheel has not consumed " + ForgeRegistries.ITEMS.getKey(plank));
// next item
planks.remove(0);
deployers.forEach(pos -> {
IItemHandler handler = helper.itemStorageAt(pos);
for (int i = 0; i < handler.getSlots(); i++) {
handler.extractItem(i, Integer.MAX_VALUE, false);
}
});
if (!planks.isEmpty())
helper.fail("Not all planks have been consumed");
});
}
@GameTest(template = "smart_observer_pipes")
public static void smartObserverPipes(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(3, 3, 1);
BlockPos output = new BlockPos(3, 4, 4);
BlockPos tankOutput = new BlockPos(1, 2, 4);
FluidStack expected = new FluidStack(Fluids.WATER, 2 * FluidAttributes.BUCKET_VOLUME);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertFluidPresent(expected, tankOutput);
helper.assertBlockPresent(Blocks.DIAMOND_BLOCK, output);
});
}
@GameTest(template = "threshold_switch", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS)
public static void thresholdSwitch(CreateGameTestHelper helper) {
BlockPos leftHandle = new BlockPos(4, 2, 4);
BlockPos leftValve = new BlockPos(4, 2, 3);
BlockPos leftTank = new BlockPos(5, 2, 3);
BlockPos rightHandle = new BlockPos(2, 2, 4);
BlockPos rightValve = new BlockPos(2, 2, 3);
BlockPos rightTank = new BlockPos(1, 2, 3);
BlockPos drainHandle = new BlockPos(3, 3, 2);
BlockPos drainValve = new BlockPos(3, 3, 1);
BlockPos lamp = new BlockPos(1, 3, 1);
BlockPos tank = new BlockPos(2, 2, 1);
helper.succeedWhen(() -> {
if (!helper.getBlockState(leftValve).getValue(FluidValveBlock.ENABLED)) { // step 1
helper.getBlockEntity(AllBlockEntityTypes.VALVE_HANDLE.get(), leftHandle)
.activate(false); // open the valve, fill 4 buckets
helper.fail("Entering step 2");
} else if (!helper.getBlockState(rightValve).getValue(FluidValveBlock.ENABLED)) { // step 2
helper.assertFluidPresent(FluidStack.EMPTY, leftTank); // wait for left tank to drain
helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, false); // should not be on yet
helper.getBlockEntity(AllBlockEntityTypes.VALVE_HANDLE.get(), rightHandle)
.activate(false); // fill another 4 buckets
helper.fail("Entering step 3");
} else if (!helper.getBlockState(drainValve).getValue(FluidValveBlock.ENABLED)) { // step 3
helper.assertFluidPresent(FluidStack.EMPTY, rightTank); // wait for right tank to drain
// 16 buckets inserted. tank full, lamp on.
helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, true);
// drain what's filled so far
helper.getBlockEntity(AllBlockEntityTypes.VALVE_HANDLE.get(), drainHandle)
.activate(false); // drain all 8 buckets
helper.fail("Entering step 4");
} else {
helper.assertTankEmpty(tank); // wait for it to empty
helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, false); // should be off now
}
});
}
}

View File

@ -34,6 +34,7 @@ import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RedstoneLampBlock;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.registries.ForgeRegistries;
@GameTestGroup(path = "items")
public class TestItems {
@ -229,8 +230,35 @@ public class TestItems {
});
}
@GameTest(template = "content_observer_counting")
public static void contentObserverCounting(CreateGameTestHelper helper) {
@GameTest(template = "smart_observer_belt_and_funnel", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void smartObserverBeltAndFunnel(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(6, 3, 2);
List<BlockPos> targets = List.of(
new BlockPos(5, 2, 1), // belt
new BlockPos(2, 4, 6) // funnel
);
List<BlockPos> overflows = List.of(
new BlockPos(6, 2, 1), // belt
new BlockPos(1, 3, 6) // funnel
);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertSecondsPassed(9);
targets.forEach(pos -> helper.assertBlockPresent(Blocks.DIAMOND_BLOCK, pos));
overflows.forEach(pos -> helper.assertBlockPresent(Blocks.AIR, pos));
});
}
@GameTest(template = "smart_observer_chutes")
public static void smartObserverChutes(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(1, 5, 2);
BlockPos output = new BlockPos(1, 5, 3);
helper.pullLever(lever);
helper.succeedWhen(() -> helper.assertBlockPresent(Blocks.DIAMOND_BLOCK, output));
}
@GameTest(template = "smart_observer_counting")
public static void smartObserverCounting(CreateGameTestHelper helper) {
BlockPos chest = new BlockPos(3, 2, 1);
long totalChestItems = helper.getTotalItems(chest);
BlockPos chestNixiePos = new BlockPos(2, 3, 1);
@ -253,6 +281,26 @@ public class TestItems {
});
}
@GameTest(template = "smart_observer_filtered_storage")
public static void smartObserverFilteredStorage(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(2, 3, 1);
BlockPos leftLamp = new BlockPos(3, 2, 3);
BlockPos rightLamp = new BlockPos(1, 2, 3);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertBlockProperty(leftLamp, RedstoneLampBlock.LIT, true);
helper.assertBlockProperty(rightLamp, RedstoneLampBlock.LIT, false);
});
}
@GameTest(template = "smart_observer_storage")
public static void smartObserverStorage(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(1, 3, 2);
BlockPos lamp = new BlockPos(1, 2, 3);
helper.pullLever(lever);
helper.succeedWhen(() -> helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, true));
}
@GameTest(template = "depot_display", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void depotDisplay(CreateGameTestHelper helper) {
BlockPos displayPos = new BlockPos(5, 3, 1);
@ -275,7 +323,7 @@ public class TestItems {
DepotBlockEntity depot = depots.get(i);
ItemStack item = depot.getHeldItem();
String name = Registry.ITEM.getKey(item.getItem()).getPath();
String name = ForgeRegistries.ITEMS.getKey(item.getItem()).getPath();
if (!name.equals(text))
helper.fail("Text mismatch: wanted [" + name + "], got: " + text);
@ -283,8 +331,8 @@ public class TestItems {
});
}
@GameTest(template = "stockpile_switch")
public static void stockpileSwitch(CreateGameTestHelper helper) {
@GameTest(template = "threshold_switch")
public static void thresholdSwitch(CreateGameTestHelper helper) {
BlockPos chest = new BlockPos(1, 2, 1);
BlockPos lamp = new BlockPos(2, 3, 1);
helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, false);

View File

@ -3,6 +3,7 @@ package com.simibubi.create.infrastructure.gametest.tests;
import static com.simibubi.create.infrastructure.gametest.CreateGameTestHelper.FIFTEEN_SECONDS;
import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchBlockEntity;
import com.simibubi.create.content.schematics.SchematicExport;
import com.simibubi.create.content.schematics.SchematicItem;
import com.simibubi.create.content.schematics.cannon.SchematicannonBlockEntity;
@ -16,10 +17,14 @@ import net.minecraft.nbt.NbtUtils;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.animal.Sheep;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RedstoneLampBlock;
@GameTestGroup(path = "misc")
public class TestMisc {
@ -63,4 +68,47 @@ public class TestMisc {
helper.assertItemEntityPresent(Items.WHITE_WOOL, sheepPos, 2);
});
}
@GameTest(template = "smart_observer_blocks")
public static void smartObserverBlocks(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(2, 2, 1);
BlockPos leftLamp = new BlockPos(3, 4, 3);
BlockPos rightLamp = new BlockPos(1, 4, 3);
helper.pullLever(lever);
helper.succeedWhen(() -> {
helper.assertBlockProperty(leftLamp, RedstoneLampBlock.LIT, true);
helper.assertBlockProperty(rightLamp, RedstoneLampBlock.LIT, false);
});
}
@GameTest(template = "threshold_switch_pulley")
public static void thresholdSwitchPulley(CreateGameTestHelper helper) {
BlockPos lever = new BlockPos(3, 7, 1);
BlockPos switchPos = new BlockPos(1, 6, 1);
helper.pullLever(lever);
helper.succeedWhen(() -> {
ThresholdSwitchBlockEntity switchBe = helper.getBlockEntity(AllBlockEntityTypes.THRESHOLD_SWITCH.get(), switchPos);
float level = switchBe.getStockLevel();
if (level < 0 || level > 1)
helper.fail("Invalid level: " + level);
});
}
@GameTest(template = "netherite_backtank", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void netheriteBacktank(CreateGameTestHelper helper) {
BlockPos lava = new BlockPos(2, 2, 3);
BlockPos zombieSpawn = lava.above(2);
BlockPos armorStandPos = new BlockPos(2, 2, 1);
helper.runAtTickTime(5, () -> {
Zombie zombie = helper.spawn(EntityType.ZOMBIE, zombieSpawn);
ArmorStand armorStand = helper.getFirstEntity(EntityType.ARMOR_STAND, armorStandPos);
for (EquipmentSlot slot : EquipmentSlot.values()) {
zombie.setItemSlot(slot, armorStand.getItemBySlot(slot).copy());
}
});
helper.succeedWhen(() -> {
helper.assertSecondsPassed(9);
helper.assertEntityPresent(EntityType.ZOMBIE, lava);
});
}
}