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

This commit is contained in:
TropheusJ 2023-06-30 02:14:10 -04:00
commit c3ab704a17
33 changed files with 481 additions and 48 deletions

View File

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

View File

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

View File

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

View File

@ -163,7 +163,7 @@ public class PulleyBlockEntity extends LinearActuatorBlockEntity implements Thre
} }
} }
} }
if (mirrorParent != null) if (mirrorParent != null)
removeRopes(); removeRopes();
@ -284,7 +284,7 @@ public class PulleyBlockEntity extends LinearActuatorBlockEntity implements Thre
if (prevMirrorParent == null || !prevMirrorParent.equals(mirrorParent)) if (prevMirrorParent == null || !prevMirrorParent.equals(mirrorParent))
sharedMirrorContraption = null; sharedMirrorContraption = null;
} }
if (compound.contains("MirrorChildren")) if (compound.contains("MirrorChildren"))
mirrorChildren = NBTHelper.readCompoundList(compound.getList("MirrorChildren", Tag.TAG_COMPOUND), mirrorChildren = NBTHelper.readCompoundList(compound.getList("MirrorChildren", Tag.TAG_COMPOUND),
NbtUtils::readBlockPos); NbtUtils::readBlockPos);
@ -379,4 +379,8 @@ public class PulleyBlockEntity extends LinearActuatorBlockEntity implements Thre
return 100; return 100;
return 100 * getInterpolatedOffset(.5f) / distance; 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.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; 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.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -26,6 +38,7 @@ import net.minecraft.core.Direction;
import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.gametest.framework.GameTestInfo; import net.minecraft.gametest.framework.GameTestInfo;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.item.ItemEntity;
@ -39,6 +52,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.levelgen.structure.BoundingBox; 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.minecraft.world.phys.Vec3;
import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
@ -122,6 +136,34 @@ public class CreateGameTestHelper extends GameTestHelper {
behavior.setValue(mode.ordinal()); 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 // block entities
/** /**

View File

@ -1,11 +1,20 @@
package com.simibubi.create.infrastructure.gametest.tests; package com.simibubi.create.infrastructure.gametest.tests;
import java.util.List; 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.CreateGameTestHelper;
import com.simibubi.create.infrastructure.gametest.GameTestGroup; import com.simibubi.create.infrastructure.gametest.GameTestGroup;
import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.gametest.framework.GameTest; import net.minecraft.gametest.framework.GameTest;
import net.minecraft.world.entity.EntityType; 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.Item;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks; 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; import net.minecraftforge.fluids.FluidStack;
@GameTestGroup(path = "contraptions") @GameTestGroup(path = "contraptions")
@ -89,6 +101,128 @@ public class TestContraptions {
helper.succeedWhen(() -> helper.assertBlockPresent(Blocks.DIAMOND_BLOCK, end)); 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 // FIXME: trains do not enjoy being loaded in structures
// https://gist.github.com/TropheusJ/f2d0a7df48360d2e078d0987c115c6ef // https://gist.github.com/TropheusJ/f2d0a7df48360d2e078d0987c115c6ef
// @GameTest(template = "train_observer") // @GameTest(template = "train_observer")

View File

@ -1,55 +1,60 @@
package com.simibubi.create.infrastructure.gametest.tests; 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.AllBlockEntityTypes;
import com.simibubi.create.content.fluids.hosePulley.HosePulleyFluidHandler; 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.SpeedGaugeBlockEntity;
import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity; 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.CreateGameTestHelper;
import com.simibubi.create.infrastructure.gametest.GameTestGroup; import com.simibubi.create.infrastructure.gametest.GameTestGroup;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.gametest.framework.GameTest; 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.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.Blocks;
import net.minecraft.world.level.block.RedStoneWireBlock; import net.minecraft.world.level.block.LeverBlock;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.RedstoneLampBlock;
import net.minecraft.world.level.block.state.properties.RedstoneSide;
import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidType; import net.minecraftforge.fluids.FluidType;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; 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") @GameTestGroup(path = "fluids")
public class TestFluids { public class TestFluids {
@GameTest(template = "hose_pulley_transfer", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS) @GameTest(template = "hose_pulley_transfer", timeoutTicks = CreateGameTestHelper.TWENTY_SECONDS)
public static void hosePulleyTransfer(CreateGameTestHelper helper) { 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 lever = new BlockPos(7, 7, 5);
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);
helper.pullLever(lever); helper.pullLever(lever);
helper.succeedWhen(() -> { helper.succeedWhen(() -> {
helper.assertSecondsPassed(15); helper.assertSecondsPassed(15);
// check filled // check filled
BlockPos filledLowerCorner = new BlockPos(8, 3, 2); BlockPos filledLowerCorner = new BlockPos(2, 3, 2);
BlockPos filledUpperCorner = new BlockPos(10, 5, 4); BlockPos filledUpperCorner = new BlockPos(4, 5, 4);
BlockPos.betweenClosed(filledLowerCorner, filledUpperCorner) BlockPos.betweenClosed(filledLowerCorner, filledUpperCorner)
.forEach(pos -> helper.assertBlockPresent(Blocks.WATER, pos)); .forEach(pos -> helper.assertBlockPresent(Blocks.WATER, pos));
// check emptied // check emptied
BlockPos emptiedLowerCorner = new BlockPos(2, 3, 2); BlockPos emptiedLowerCorner = new BlockPos(8, 3, 2);
BlockPos emptiedUpperCorner = new BlockPos(4, 5, 4); BlockPos emptiedUpperCorner = new BlockPos(10, 5, 4);
BlockPos.betweenClosed(emptiedLowerCorner, emptiedUpperCorner) BlockPos.betweenClosed(emptiedLowerCorner, emptiedUpperCorner)
.forEach(pos -> helper.assertBlockPresent(Blocks.AIR, pos)); .forEach(pos -> helper.assertBlockPresent(Blocks.AIR, pos));
// check nothing left in pulley // check nothing left in pulley
BlockPos pulleyPos = new BlockPos(8, 7, 4); BlockPos pulleyPos = new BlockPos(4, 7, 3);
IFluidHandler storage = helper.fluidStorageAt(pulleyPos); IFluidHandler storage = helper.fluidStorageAt(pulleyPos);
if (storage instanceof HosePulleyFluidHandler hose) { if (storage instanceof HosePulleyFluidHandler hose) {
IFluidHandler internalTank = hose.getInternalTank(); IFluidHandler internalTank = hose.getInternalTank();
@ -62,27 +67,27 @@ public class TestFluids {
} }
@GameTest(template = "in_world_pumping_out") @GameTest(template = "in_world_pumping_out")
public static void inWorldPumpingOutput(CreateGameTestHelper helper) { public static void inWorldPumpingOut(CreateGameTestHelper helper) {
BlockPos pumpPos = new BlockPos(3, 2, 2); BlockPos lever = new BlockPos(4, 3, 3);
BlockPos waterPos = pumpPos.west(); BlockPos basin = new BlockPos(5, 2, 2);
BlockPos basinPos = pumpPos.east(); BlockPos output = new BlockPos(2, 2, 2);
helper.flipBlock(pumpPos); helper.pullLever(lever);
helper.succeedWhen(() -> { helper.succeedWhen(() -> {
helper.assertBlockPresent(Blocks.WATER, waterPos); helper.assertBlockPresent(Blocks.WATER, output);
helper.assertTankEmpty(basinPos); helper.assertTankEmpty(basin);
}); });
} }
@GameTest(template = "in_world_pumping_in") @GameTest(template = "in_world_pumping_in")
public static void inWorldPumpingPickup(CreateGameTestHelper helper) { public static void inWorldPumpingIn(CreateGameTestHelper helper) {
BlockPos pumpPos = new BlockPos(3, 2, 2); BlockPos lever = new BlockPos(4, 3, 3);
BlockPos basinPos = pumpPos.east(); BlockPos basin = new BlockPos(5, 2, 2);
BlockPos waterPos = pumpPos.west(); BlockPos water = new BlockPos(2, 2, 2);
FluidStack expectedResult = new FluidStack(Fluids.WATER, FluidType.BUCKET_VOLUME); FluidStack expectedResult = new FluidStack(Fluids.WATER, FluidType.BUCKET_VOLUME);
helper.flipBlock(pumpPos); helper.pullLever(lever);
helper.succeedWhen(() -> { helper.succeedWhen(() -> {
helper.assertBlockPresent(Blocks.AIR, waterPos); helper.assertBlockPresent(Blocks.AIR, water);
helper.assertFluidPresent(expectedResult, basinPos); helper.assertFluidPresent(expectedResult, basin);
}); });
} }
@ -147,4 +152,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, 256, 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 * FluidType.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

@ -230,8 +230,35 @@ public class TestItems {
}); });
} }
@GameTest(template = "content_observer_counting") @GameTest(template = "smart_observer_belt_and_funnel", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void contentObserverCounting(CreateGameTestHelper helper) { 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); BlockPos chest = new BlockPos(3, 2, 1);
long totalChestItems = helper.getTotalItems(chest); long totalChestItems = helper.getTotalItems(chest);
BlockPos chestNixiePos = new BlockPos(2, 3, 1); BlockPos chestNixiePos = new BlockPos(2, 3, 1);
@ -254,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) @GameTest(template = "depot_display", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
public static void depotDisplay(CreateGameTestHelper helper) { public static void depotDisplay(CreateGameTestHelper helper) {
BlockPos displayPos = new BlockPos(5, 3, 1); BlockPos displayPos = new BlockPos(5, 3, 1);
@ -284,8 +331,8 @@ public class TestItems {
}); });
} }
@GameTest(template = "stockpile_switch") @GameTest(template = "threshold_switch")
public static void stockpileSwitch(CreateGameTestHelper helper) { public static void thresholdSwitch(CreateGameTestHelper helper) {
BlockPos chest = new BlockPos(1, 2, 1); BlockPos chest = new BlockPos(1, 2, 1);
BlockPos lamp = new BlockPos(2, 3, 1); BlockPos lamp = new BlockPos(2, 3, 1);
helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, false); 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 static com.simibubi.create.infrastructure.gametest.CreateGameTestHelper.FIFTEEN_SECONDS;
import com.simibubi.create.AllBlockEntityTypes; 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.SchematicExport;
import com.simibubi.create.content.schematics.SchematicItem; import com.simibubi.create.content.schematics.SchematicItem;
import com.simibubi.create.content.schematics.cannon.SchematicannonBlockEntity; import com.simibubi.create.content.schematics.cannon.SchematicannonBlockEntity;
@ -17,10 +18,14 @@ import net.minecraft.nbt.NbtUtils;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.animal.Sheep; 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.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RedstoneLampBlock;
@GameTestGroup(path = "misc") @GameTestGroup(path = "misc")
public class TestMisc { public class TestMisc {
@ -65,4 +70,47 @@ public class TestMisc {
helper.assertItemEntityPresent(Items.WHITE_WOOL, sheepPos, 2); 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);
});
}
} }