diff --git a/src/main/java/appeng/block/misc/LightDetectorBlock.java b/src/main/java/appeng/block/misc/LightDetectorBlock.java index b27e59778ab..3ed84835493 100644 --- a/src/main/java/appeng/block/misc/LightDetectorBlock.java +++ b/src/main/java/appeng/block/misc/LightDetectorBlock.java @@ -85,7 +85,7 @@ protected void createBlockStateDefinition(Builder builder) { @Override public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction side) { - if (level instanceof Level && this.getBlockEntity(level, pos).isReady()) { + if (level instanceof Level && this.getBlockEntity(level, pos).isExposedToLight()) { // FIXME: This is ... uhm... fishy return ((Level) level).getMaxLocalRawBrightness(pos) - 6; } diff --git a/src/main/java/appeng/blockentity/misc/LightDetectorBlockEntity.java b/src/main/java/appeng/blockentity/misc/LightDetectorBlockEntity.java index 220f471cf00..911406a3280 100644 --- a/src/main/java/appeng/blockentity/misc/LightDetectorBlockEntity.java +++ b/src/main/java/appeng/blockentity/misc/LightDetectorBlockEntity.java @@ -35,7 +35,7 @@ public LightDetectorBlockEntity(BlockEntityType blockEntityType, BlockPos pos super(blockEntityType, pos, blockState); } - public boolean isReady() { + public boolean isExposedToLight() { return this.lastLight > 0; } diff --git a/src/main/java/appeng/me/service/P2PService.java b/src/main/java/appeng/me/service/P2PService.java index 1a66d13fa3d..dd901f35d64 100644 --- a/src/main/java/appeng/me/service/P2PService.java +++ b/src/main/java/appeng/me/service/P2PService.java @@ -60,8 +60,8 @@ public static P2PService get(IGrid grid) { } private final IGrid myGrid; - private final HashMap inputs = new HashMap<>(); - private final Multimap outputs = LinkedHashMultimap.create(); + private final HashMap> inputs = new HashMap<>(); + private final Multimap> outputs = LinkedHashMultimap.create(); private final Random frequencyGenerator; public P2PService(IGrid g) { diff --git a/src/main/java/appeng/server/testplots/AutoCraftingTestPlots.java b/src/main/java/appeng/server/testplots/AutoCraftingTestPlots.java index afe8ac71e7e..21c69a250f2 100644 --- a/src/main/java/appeng/server/testplots/AutoCraftingTestPlots.java +++ b/src/main/java/appeng/server/testplots/AutoCraftingTestPlots.java @@ -96,7 +96,7 @@ public static void create(PlotBuilder plot) { plot.cable("4 0 [6,9]", AEParts.SMART_DENSE_CABLE); // Add post-processing action once the grid is up and running - plot.afterGridInitAt("4 0 4", (grid, gridNode) -> { + plot.afterGridInitAt(new BlockPos(4, 0, 4), (grid, gridNode) -> { var level = gridNode.getLevel(); var patterns = new ArrayList(); // Crafting pattern table with substitutions enabled and some items that are NOT in storage diff --git a/src/main/java/appeng/server/testplots/P2PPlotHelper.java b/src/main/java/appeng/server/testplots/P2PPlotHelper.java index 6423fbe0a00..1fd3fecba22 100644 --- a/src/main/java/appeng/server/testplots/P2PPlotHelper.java +++ b/src/main/java/appeng/server/testplots/P2PPlotHelper.java @@ -10,10 +10,10 @@ import appeng.api.networking.IGrid; import appeng.api.parts.PartHelper; +import appeng.blockentity.networking.CableBusBlockEntity; import appeng.core.definitions.ItemDefinition; import appeng.items.parts.PartItem; import appeng.me.service.P2PService; -import appeng.parts.AEBasePart; import appeng.parts.p2p.P2PTunnelPart; import appeng.server.testworld.PlotBuilder; import appeng.util.SettingsFrom; @@ -28,9 +28,9 @@ public static > void placeTunnel(PlotBuilder plot, It plot.cable(origin); plot.cable(origin.west()).part(Direction.WEST, tunnel); plot.cable(origin.east()).part(Direction.EAST, tunnel); - plot.afterGridInitAt(origin, (grid, gridNode) -> { - BlockPos absOrigin = ((AEBasePart) gridNode.getOwner()).getBlockEntity().getBlockPos(); - + plot.addPostInitAction((level, player, absOrigin) -> { + var be = (CableBusBlockEntity) level.getBlockEntity(absOrigin); + var grid = be.getCableBus().getPart(null).getGridNode().getGrid(); linkTunnels(grid, tunnel.get().getPartClass(), absOrigin.west(), absOrigin.east()); }); } diff --git a/src/main/java/appeng/server/testplots/SpatialTestPlots.java b/src/main/java/appeng/server/testplots/SpatialTestPlots.java index 9187fd04e35..a53ced16ddf 100644 --- a/src/main/java/appeng/server/testplots/SpatialTestPlots.java +++ b/src/main/java/appeng/server/testplots/SpatialTestPlots.java @@ -7,6 +7,7 @@ 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.ButtonBlock; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; @@ -121,33 +122,36 @@ public static void storeAndRetrieveEntities(PlotBuilder plot) { // Woosh! plot.test(helper -> { + // Remove all entities + // Spawn cow + chicken helper.startSequence() .thenExecute(() -> { - // Remove all entities - // Spawn cow + chicken - helper.killAllEntities(); - helper.spawn(EntityType.CHICKEN, chickenPos.above()); - helper.spawnItem(Items.OBSIDIAN, chickenPos.getX() + .5f, chickenPos.getY() + .5f, - chickenPos.getZ() + .5f); + helper.spawn(EntityType.CHICKEN, Vec3.atBottomCenterOf(chickenPos.above())); + helper.spawnItem(Items.OBSIDIAN, Vec3.atCenterOf(chickenPos)); + }) + .thenWaitUntil(() -> { + helper.assertItemEntityCountIs(Items.OBSIDIAN, chickenPos, 1, 1); + helper.assertEntitiesPresent(EntityType.CHICKEN, chickenPos, 1, 1); }) .thenIdle(5) + // Wait for the grid to become available + .thenWaitUntil(helper::checkAllInitialized) .thenExecute(() -> helper.pressButton(buttonPos)) - .thenIdle(5) - .thenExecute(() -> { + .thenWaitUntil(() -> { // Validate, that the chicken and obsidian are gone helper.assertItemEntityCountIs(Items.OBSIDIAN, chickenPos, 1, 0); helper.assertEntitiesPresent(EntityType.CHICKEN, chickenPos, 0, 1); - + }) + .thenExecute(() -> { // Swap the cell back to the input slot and trigger a transition var cell = getCellFromSpatialIoPortOutput(helper, ioPortPos); insertCell(helper, ioPortPos, cell); }) // Wait for button to reset - .thenIdle(25) + .thenWaitUntil(() -> helper.assertBlockProperty(buttonPos, ButtonBlock.POWERED, false)) // Transition back .thenExecute(() -> helper.pressButton(buttonPos)) - .thenIdle(5) - .thenExecute(() -> { + .thenWaitUntil(() -> { // Validate that the chicken and obsidian are back helper.assertItemEntityCountIs(Items.OBSIDIAN, chickenPos, 1, 1); helper.assertEntitiesPresent(EntityType.CHICKEN, chickenPos, 1, 1); diff --git a/src/main/java/appeng/server/testplots/TestPlots.java b/src/main/java/appeng/server/testplots/TestPlots.java index bff04dd8cf1..9d56d5e98e8 100644 --- a/src/main/java/appeng/server/testplots/TestPlots.java +++ b/src/main/java/appeng/server/testplots/TestPlots.java @@ -235,7 +235,7 @@ public static void allTerminals(PlotBuilder plot) { plot.part("0 [0,8] 0", Direction.WEST, AEParts.CABLE_ANCHOR); plot.block("[-1,0] 5 0", AEBlocks.CONTROLLER); plot.storageDrive(new BlockPos(0, 5, 1)); - plot.afterGridInitAt("0 5 1", (grid, gridNode) -> { + plot.afterGridInitAt(new BlockPos(0, 5, 1), (grid, gridNode) -> { var enchantedPickaxe = createEnchantedPickaxe(gridNode.getLevel()); var storage = grid.getStorageService().getInventory(); var src = new BaseActionSource(); @@ -657,7 +657,7 @@ public static void maxChannelsAdHocTest(PlotBuilder plot) { .part(Direction.EAST, AEParts.PATTERN_PROVIDER) .part(Direction.WEST, AEParts.PATTERN_PROVIDER); - plot.afterGridExistsAt("0 0 0", (grid, node) -> { + plot.afterGridExistsAt(BlockPos.ZERO, (grid, node) -> { // This has so many nodes it needs infinite mode ((PathingService) grid.getPathingService()).setForcedChannelMode(ChannelMode.INFINITE); diff --git a/src/main/java/appeng/server/testworld/GridInitHelper.java b/src/main/java/appeng/server/testworld/GridInitHelper.java index 5135b9ee352..80877bf9e2f 100644 --- a/src/main/java/appeng/server/testworld/GridInitHelper.java +++ b/src/main/java/appeng/server/testworld/GridInitHelper.java @@ -1,9 +1,13 @@ package appeng.server.testworld; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; import java.util.function.BiConsumer; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.BlockEntity; import appeng.api.networking.IGrid; import appeng.api.networking.IGridNode; @@ -13,7 +17,7 @@ final class GridInitHelper { - static void doAfterGridInit(ServerLevel level, BlockPos pos, boolean waitForActive, + static void doAfterGridInit(ServerLevel level, List positions, boolean waitForActive, BiConsumer consumer) { Runnable delayedAction = new Runnable() { private int attempts = 120; @@ -21,33 +25,90 @@ static void doAfterGridInit(ServerLevel level, BlockPos pos, boolean waitForActi @Override public void run() { // Check if there's a grid node there - var be = level.getBlockEntity(pos); - IGridNode gridNode = null; - if (be instanceof IGridConnectedBlockEntity host) { - gridNode = host.getMainNode().getNode(); - } else if (be instanceof CableBusBlockEntity cableBus) { - var centerPart = cableBus.getCableBus().getPart(null); - if (centerPart != null) { - gridNode = centerPart.getGridNode(); + List gridNodes = new ArrayList<>(); + + for (var position : positions) { + var be = level.getBlockEntity(position); + if (be instanceof IGridConnectedBlockEntity host) { + gridNodes.add(host.getMainNode().getNode()); + } else if (be instanceof CableBusBlockEntity cableBus) { + var centerPart = cableBus.getCableBus().getPart(null); + if (centerPart != null) { + gridNodes.add(centerPart.getGridNode()); + } else { + return; // Stop -> not eligible + } } else { return; // Stop -> not eligible } - } else { - return; // Stop -> not eligible } - if (gridNode == null || waitForActive && !gridNode.isActive()) { + if (gridNodes.stream().anyMatch(Objects::isNull) + || waitForActive && !gridNodes.stream().allMatch(IGridNode::isActive)) { if (--attempts > 0) { TickHandler.instance().addCallable(level, this); } else { - throw new IllegalStateException("Couldn't access grid node @ " + pos); + throw new IllegalStateException("Couldn't access grid nodes @ " + positions); } } else { - consumer.accept(gridNode.getGrid(), gridNode); + consumer.accept(gridNodes.getFirst().getGrid(), gridNodes.getFirst()); } } }; TickHandler.instance().addCallable(level, delayedAction); } + static void doAfterGridInit(ServerLevel level, List blockEntities, boolean waitForActive, + Runnable callback) { + Runnable delayedAction = new Runnable() { + private int attempts = 120; + + @Override + public void run() { + var notInitialized = new ArrayList(); + var notActive = new ArrayList(); + + for (var be : blockEntities) { + if (be.isRemoved()) { + return; + } + + if (be instanceof IGridConnectedBlockEntity host) { + var mainNode = host.getMainNode(); + if (mainNode == null) { + notInitialized.add(be); + notActive.add(be); + break; + } else if (!mainNode.isActive()) { + notActive.add(be); + } + } else if (be instanceof CableBusBlockEntity cableBus) { + var centerPart = cableBus.getCableBus().getPart(null); + if (centerPart != null) { + var mainNode = centerPart.getGridNode(); + if (mainNode == null) { + notInitialized.add(be); + notActive.add(be); + break; + } else if (!mainNode.isActive()) { + notActive.add(be); + } + } + } + } + + if (!notInitialized.isEmpty() || waitForActive && !notActive.isEmpty()) { + if (--attempts > 0) { + TickHandler.instance().addCallable(level, this); + } else { + throw new IllegalStateException("Couldn't wait for grid to initialize. Not initialized: " + + notInitialized + ". Not active: " + notActive); + } + } else { + callback.run(); + } + } + }; + TickHandler.instance().addCallable(level, delayedAction); + } } diff --git a/src/main/java/appeng/server/testworld/Plot.java b/src/main/java/appeng/server/testworld/Plot.java index 3bb47fe245f..94f19ab26e3 100644 --- a/src/main/java/appeng/server/testworld/Plot.java +++ b/src/main/java/appeng/server/testworld/Plot.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Pattern; @@ -20,6 +21,7 @@ public class Plot implements PlotBuilder { private final List buildActions = new ArrayList<>(); private final List postBuildActions = new ArrayList<>(); + private final List postInitActions = new ArrayList<>(); private Test test; @@ -52,6 +54,11 @@ public void addPostBuildAction(PostBuildAction action) { postBuildActions.add(action); } + @Override + public void addPostInitAction(PostBuildAction action) { + postInitActions.add(action); + } + @Override public PlotBuilder transform(Function transform) { return new TransformingPlotBuilder(this, transform); @@ -95,6 +102,21 @@ public void build(ServerLevel level, Player player, BlockPos origin, List { + for (var action : postInitActions) { + action.postBuild(level, player, origin); + } + }); + } } public Test getTest() { diff --git a/src/main/java/appeng/server/testworld/PlotBuilder.java b/src/main/java/appeng/server/testworld/PlotBuilder.java index 677649f9073..b700c85cbfa 100644 --- a/src/main/java/appeng/server/testworld/PlotBuilder.java +++ b/src/main/java/appeng/server/testworld/PlotBuilder.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -45,7 +46,7 @@ public interface PlotBuilder { @FunctionalInterface - public interface PostBuildAction { + interface PostBuildAction { void postBuild(ServerLevel level, Player player, BlockPos origin); } @@ -53,6 +54,8 @@ public interface PostBuildAction { void addPostBuildAction(PostBuildAction action); + void addPostInitAction(PostBuildAction action); + BoundingBox bb(String def); static String posToBb(BlockPos pos) { @@ -296,23 +299,23 @@ default PlotBuilder offset(BlockPos pos) { /** * Runs a given callback once the grid has been initialized at all viable nodes in the given bounding box. */ - default void afterGridInitAt(String bb, BiConsumer consumer) { - addBuildAction(new PostGridInitAction(bb(bb), consumer, true)); + default void afterGridInitAt(List positions, BiConsumer consumer) { + addBuildAction(new PostGridInitAction(positions, consumer, true)); } default void afterGridInitAt(BlockPos pos, BiConsumer consumer) { - afterGridInitAt(posToBb(pos), consumer); + afterGridInitAt(List.of(pos), consumer); } /** * Runs a given callback once the grid is available at all viable nodes in the given bounding box. */ - default void afterGridExistsAt(String bb, BiConsumer consumer) { - addBuildAction(new PostGridInitAction(bb(bb), consumer, false)); + default void afterGridExistsAt(List positions, BiConsumer consumer) { + addBuildAction(new PostGridInitAction(positions, consumer, false)); } default void afterGridExistsAt(BlockPos pos, BiConsumer consumer) { - afterGridExistsAt(posToBb(pos), consumer); + afterGridExistsAt(List.of(pos), consumer); } /** diff --git a/src/main/java/appeng/server/testworld/PostGridInitAction.java b/src/main/java/appeng/server/testworld/PostGridInitAction.java index dfa404fe920..4c688e6b218 100644 --- a/src/main/java/appeng/server/testworld/PostGridInitAction.java +++ b/src/main/java/appeng/server/testworld/PostGridInitAction.java @@ -1,5 +1,6 @@ package appeng.server.testworld; +import java.util.List; import java.util.function.BiConsumer; import net.minecraft.core.BlockPos; @@ -10,17 +11,19 @@ import appeng.api.networking.IGrid; import appeng.api.networking.IGridNode; -public record PostGridInitAction(BoundingBox bb, +public record PostGridInitAction(List positions, BiConsumer consumer, - boolean waitForActive) implements BlockPlacingBuildAction { + boolean waitForActive) implements BuildAction { @Override - public void placeBlock(ServerLevel level, Player player, BlockPos pos, BlockPos minPos, BlockPos maxPos) { - GridInitHelper.doAfterGridInit(level, pos, waitForActive, consumer); + public void build(ServerLevel level, Player player, BlockPos origin) { + var absolutePositions = positions.stream().map(p -> p.offset(origin)).toList(); + + GridInitHelper.doAfterGridInit(level, absolutePositions, waitForActive, consumer); } @Override public BoundingBox getBoundingBox() { - return bb; + return new BoundingBox(positions.getFirst()); } } diff --git a/src/main/java/appeng/server/testworld/SpawnExtraGridTestToolsChest.java b/src/main/java/appeng/server/testworld/SpawnExtraGridTestToolsChest.java index 100d9bc8134..9b5874e33ce 100644 --- a/src/main/java/appeng/server/testworld/SpawnExtraGridTestToolsChest.java +++ b/src/main/java/appeng/server/testworld/SpawnExtraGridTestToolsChest.java @@ -1,5 +1,7 @@ package appeng.server.testworld; +import java.util.List; + import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -29,7 +31,7 @@ public void build(ServerLevel level, Player player, BlockPos origin) { var absGridPos = gridPos.offset(origin); level.setBlock(absChestPod, AEBlocks.SMOOTH_SKY_STONE_CHEST.block().defaultBlockState(), Block.UPDATE_ALL); - GridInitHelper.doAfterGridInit(level, absGridPos, false, (grid, gridNode) -> { + GridInitHelper.doAfterGridInit(level, List.of(absGridPos), false, (grid, gridNode) -> { var chest = AEBlockEntities.SKY_CHEST.getBlockEntity(level, absChestPod); if (chest != null) { var inventory = chest.getInternalInventory(); diff --git a/src/main/java/appeng/server/testworld/Test.java b/src/main/java/appeng/server/testworld/Test.java index cc03338a56c..013af4c513c 100644 --- a/src/main/java/appeng/server/testworld/Test.java +++ b/src/main/java/appeng/server/testworld/Test.java @@ -10,7 +10,7 @@ public final class Test { */ public int setupTicks = 21; - public int maxTicks = 100; + public int maxTicks = 150; public boolean skyAccess = false; diff --git a/src/main/java/appeng/server/testworld/TransformingPlotBuilder.java b/src/main/java/appeng/server/testworld/TransformingPlotBuilder.java index 4ae6669f253..07914815df8 100644 --- a/src/main/java/appeng/server/testworld/TransformingPlotBuilder.java +++ b/src/main/java/appeng/server/testworld/TransformingPlotBuilder.java @@ -24,6 +24,11 @@ public void addPostBuildAction(PostBuildAction action) { plot.addPostBuildAction(action); } + @Override + public void addPostInitAction(PostBuildAction action) { + plot.addPostInitAction(action); + } + @Override public BoundingBox bb(String def) { return transform.apply(plot.bb(def));