diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 27a22fa8f..b62b14d67 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -73,7 +73,7 @@ nullAway = "0.9.9"
spotless = "6.23.3"
taskTree = "2.1.1"
teavm = "0.10.0-SQUID.3"
-vanillaExtract = "0.1.1"
+vanillaExtract = "0.1.2"
versionCatalogUpdate = "0.8.1"
[libraries]
diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java
index 2bd6f00f4..a5f6eb34d 100644
--- a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java
+++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlock.java
@@ -23,6 +23,7 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
+import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
@@ -174,6 +175,15 @@ public final void onNeighborChange(BlockState state, LevelReader world, BlockPos
if (be instanceof AbstractComputerBlockEntity computer) computer.neighborChanged(neighbour);
}
+ @Override
+ @Deprecated
+ public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
+ var be = level.getBlockEntity(pos);
+ if (be instanceof AbstractComputerBlockEntity computer) computer.neighbourShapeChanged(direction);
+
+ return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
+ }
+
@Nullable
@Override
@Deprecated
diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java
index 0ad1dc230..462945cbe 100644
--- a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java
+++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/AbstractComputerBlockEntity.java
@@ -298,6 +298,17 @@ public void neighborChanged(BlockPos neighbour) {
invalidSides = DirectionUtil.ALL_SIDES; // Mark all peripherals as dirty.
}
+ /**
+ * Called when a neighbour block's shape changes.
+ *
+ * Unlike {@link #neighborChanged(BlockPos)}, we don't update redstone, only peripherals.
+ *
+ * @param direction The side that changed.
+ */
+ public void neighbourShapeChanged(Direction direction) {
+ invalidSides |= 1 << direction.ordinal();
+ }
+
/**
* Update outputs in a specific direction.
*
diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java
index cb5170444..bb9a728dc 100644
--- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java
+++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlock.java
@@ -196,6 +196,11 @@ public BlockState updateShape(BlockState state, Direction side, BlockState other
if (level.getBlockEntity(pos) instanceof CableBlockEntity cable) cable.scheduleConnectionsChanged();
}
+ var modem = state.getValue(MODEM);
+ if (modem.getFacing() == side && modem.isPeripheralOn() && level.getBlockEntity(pos) instanceof CableBlockEntity cable) {
+ cable.queueRefreshPeripheral();
+ }
+
return level instanceof Level actualLevel
? state.setValue(CONNECTIONS.get(side), doesConnectVisually(state, actualLevel, pos, side))
: state;
diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java
index 9ea7c4668..ea67bbf29 100644
--- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java
+++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java
@@ -112,7 +112,7 @@ void neighborChanged(BlockPos neighbour) {
}
}
- private void queueRefreshPeripheral() {
+ void queueRefreshPeripheral() {
refreshPeripheral = true;
TickScheduler.schedule(tickToken);
}
diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java
index 8707ca5e9..6f9e0b958 100644
--- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java
+++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlock.java
@@ -7,12 +7,14 @@
import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.shared.ModRegistry;
import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
+import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
@@ -49,13 +51,27 @@ public final InteractionResult use(BlockState state, Level world, BlockPos pos,
@Override
@Deprecated
- public final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) {
- if (world.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) modem.neighborChanged(neighbourPos);
+ public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
+ if (state.getValue(PERIPHERAL_ON) && level.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) {
+ modem.queueRefreshPeripheral(direction);
+ }
+
+ return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
+ }
+
+ @Override
+ @Deprecated
+ public final void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) {
+ if (state.getValue(PERIPHERAL_ON) && level.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) {
+ modem.neighborChanged(neighbourPos);
+ }
}
@ForgeOverride
- public final void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbour) {
- if (world.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) modem.neighborChanged(neighbour);
+ public final void onNeighborChange(BlockState state, LevelReader level, BlockPos pos, BlockPos neighbour) {
+ if (state.getValue(PERIPHERAL_ON) && level.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) {
+ modem.neighborChanged(neighbour);
+ }
}
@Override
diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java
index f8c3013ca..288b0e1cd 100644
--- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java
+++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java
@@ -108,14 +108,12 @@ public void clearRemoved() {
}
void neighborChanged(BlockPos neighbour) {
- if (level.isClientSide || !isPeripheralOn()) return;
-
for (var facing : DirectionUtil.FACINGS) {
if (getBlockPos().relative(facing).equals(neighbour)) queueRefreshPeripheral(facing);
}
}
- private void queueRefreshPeripheral(Direction facing) {
+ void queueRefreshPeripheral(Direction facing) {
invalidSides |= 1 << facing.ordinal();
TickScheduler.schedule(tickToken);
}
diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt
index f7800b2b5..517580964 100644
--- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt
+++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt
@@ -11,11 +11,15 @@
import dan200.computercraft.core.computer.ComputerSide
import dan200.computercraft.gametest.api.*
import dan200.computercraft.shared.ModRegistry
+import dan200.computercraft.test.core.assertArrayEquals
import dan200.computercraft.test.core.computer.getApi
import net.minecraft.core.BlockPos
+import net.minecraft.core.Direction
import net.minecraft.gametest.framework.GameTest
import net.minecraft.gametest.framework.GameTestHelper
import net.minecraft.world.InteractionHand
+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.LeverBlock
import net.minecraft.world.level.block.RedstoneLampBlock
@@ -101,6 +105,17 @@ fun Computer_peripheral(context: GameTestHelper) = context.sequence {
}
}
+ /**
+ * Check chest peripherals are reattached with a new size.
+ */
+ @GameTest
+ fun Chest_resizes_on_change(context: GameTestHelper) = context.sequence {
+ thenOnComputer { callPeripheral("right", "size").assertArrayEquals(27) }
+ thenExecute { context.placeItemAt(ItemStack(Items.CHEST), BlockPos(2, 2, 2), Direction.WEST) }
+ thenIdle(1)
+ thenOnComputer { callPeripheral("right", "size").assertArrayEquals(54) }
+ }
+
/**
* Check the client can open the computer UI and interact with it.
*/
diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt
index 85387ee76..01170422f 100644
--- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt
+++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt
@@ -16,8 +16,11 @@
import dan200.computercraft.test.core.computer.LuaTaskContext
import dan200.computercraft.test.core.computer.getApi
import net.minecraft.core.BlockPos
+import net.minecraft.core.Direction
import net.minecraft.gametest.framework.GameTest
import net.minecraft.gametest.framework.GameTestHelper
+import net.minecraft.world.item.ItemStack
+import net.minecraft.world.item.Items
import net.minecraft.world.level.block.Blocks
import org.junit.jupiter.api.Assertions.assertEquals
import kotlin.time.Duration.Companion.milliseconds
@@ -150,6 +153,21 @@ fun Modem_keeps_cable_when_neighbour_removed(helper: GameTestHelper) = helper.se
}
}
}
+
+ /**
+ * Check chest peripherals are reattached with a new size.
+ */
+ @GameTest
+ fun Chest_resizes_on_change(context: GameTestHelper) = context.sequence {
+ thenOnComputer {
+ callRemotePeripheral("minecraft:chest_0", "size").assertArrayEquals(27)
+ }
+ thenExecute { context.placeItemAt(ItemStack(Items.CHEST), BlockPos(2, 2, 2), Direction.WEST) }
+ thenIdle(1)
+ thenOnComputer {
+ callRemotePeripheral("minecraft:chest_0", "size").assertArrayEquals(54)
+ }
+ }
}
private fun LuaTaskContext.findPeripheral(type: String): String? {
@@ -169,7 +187,7 @@ fun Modem_keeps_cable_when_neighbour_removed(helper: GameTestHelper) = helper.se
if (!peripheral.isPresent(side)) continue
peripherals.add(side)
- val hasType = peripheral.hasType(side, "modem")
+ val hasType = peripheral.hasType(side, "peripheral_hub")
if (hasType == null || hasType[0] != true) continue
val names = peripheral.call(context, ObjectArguments(side, "getNamesRemote")).await() ?: continue
@@ -180,3 +198,22 @@ fun Modem_keeps_cable_when_neighbour_removed(helper: GameTestHelper) = helper.se
peripherals.sort()
return peripherals
}
+
+private suspend fun LuaTaskContext.callRemotePeripheral(name: String, method: String, vararg args: Any): Array? {
+ val peripheral = getApi()
+ if (peripheral.isPresent(name)) return peripheral.call(context, ObjectArguments(name, method, *args)).await()
+
+ for (side in ComputerSide.NAMES) {
+ if (!peripheral.isPresent(side)) continue
+
+ val hasType = peripheral.hasType(side, "peripheral_hub")
+ if (hasType == null || hasType[0] != true) continue
+
+ val isPresent = peripheral.call(context, ObjectArguments(side, "isPresentRemote", name)).await() ?: continue
+ if (isPresent[0] as Boolean) {
+ return peripheral.call(context, ObjectArguments(side, "callRemote", name, method, *args)).await()
+ }
+ }
+
+ throw IllegalArgumentException("No such peripheral $name")
+}
diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt
index 2d68bb8aa..fc5977a2d 100644
--- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt
+++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt
@@ -19,15 +19,19 @@
import net.minecraft.gametest.framework.*
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.Container
+import net.minecraft.world.InteractionHand
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityType
import net.minecraft.world.item.ItemStack
+import net.minecraft.world.item.context.UseOnContext
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.entity.BarrelBlockEntity
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.properties.Property
+import net.minecraft.world.phys.BlockHitResult
+import net.minecraft.world.phys.Vec3
import org.hamcrest.Matchers
import org.hamcrest.StringDescription
@@ -304,3 +308,16 @@ private fun getName(type: BlockEntityType<*>): ResourceLocation = RegistryWrappe
container.setItem(slot, item)
container.setChanged()
}
+
+/**
+ * An alternative version ot [GameTestHelper.placeAt], which sets the player's held item first.
+ *
+ * This is required for compatibility with Forge, which uses the in-hand stack, rather than the stack requested.
+ */
+fun GameTestHelper.placeItemAt(stack: ItemStack, pos: BlockPos, direction: Direction) {
+ val player = makeMockPlayer()
+ player.setItemInHand(InteractionHand.MAIN_HAND, stack)
+ val absolutePos = absolutePos(pos.relative(direction))
+ val hit = BlockHitResult(Vec3.atCenterOf(absolutePos), direction, absolutePos, false)
+ stack.useOn(UseOnContext(player, InteractionHand.MAIN_HAND, hit))
+}
diff --git a/projects/common/src/testMod/resources/data/cctest/structures/computer_test.chest_resizes_on_change.snbt b/projects/common/src/testMod/resources/data/cctest/structures/computer_test.chest_resizes_on_change.snbt
new file mode 100644
index 000000000..877e24bdd
--- /dev/null
+++ b/projects/common/src/testMod/resources/data/cctest/structures/computer_test.chest_resizes_on_change.snbt
@@ -0,0 +1,138 @@
+{
+ DataVersion: 3465,
+ size: [5, 5, 5],
+ data: [
+ {pos: [0, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [0, 1, 0], state: "minecraft:air"},
+ {pos: [0, 1, 1], state: "minecraft:air"},
+ {pos: [0, 1, 2], state: "minecraft:air"},
+ {pos: [0, 1, 3], state: "minecraft:air"},
+ {pos: [0, 1, 4], state: "minecraft:air"},
+ {pos: [1, 1, 0], state: "minecraft:air"},
+ {pos: [1, 1, 1], state: "minecraft:air"},
+ {pos: [1, 1, 2], state: "minecraft:air"},
+ {pos: [1, 1, 3], state: "minecraft:air"},
+ {pos: [1, 1, 4], state: "minecraft:air"},
+ {pos: [2, 1, 0], state: "minecraft:air"},
+ {pos: [2, 1, 1], state: "minecraft:air"},
+ {pos: [2, 1, 2], state: "minecraft:chest{facing:north,type:single,waterlogged:false}", nbt: {Items: [], id: "minecraft:chest"}},
+ {pos: [2, 1, 3], state: "minecraft:air"},
+ {pos: [2, 1, 4], state: "minecraft:air"},
+ {pos: [3, 1, 0], state: "minecraft:air"},
+ {pos: [3, 1, 1], state: "minecraft:air"},
+ {pos: [3, 1, 2], state: "computercraft:computer_normal{facing:north,state:on}", nbt: {ComputerId: 1, Label: "computer_test.chest_resizes_on_change", On: 1b, id: "computercraft:computer_normal"}},
+ {pos: [3, 1, 3], state: "minecraft:air"},
+ {pos: [3, 1, 4], state: "minecraft:air"},
+ {pos: [4, 1, 0], state: "minecraft:air"},
+ {pos: [4, 1, 1], state: "minecraft:air"},
+ {pos: [4, 1, 2], state: "minecraft:air"},
+ {pos: [4, 1, 3], state: "minecraft:air"},
+ {pos: [4, 1, 4], state: "minecraft:air"},
+ {pos: [0, 2, 0], state: "minecraft:air"},
+ {pos: [0, 2, 1], state: "minecraft:air"},
+ {pos: [0, 2, 2], state: "minecraft:air"},
+ {pos: [0, 2, 3], state: "minecraft:air"},
+ {pos: [0, 2, 4], state: "minecraft:air"},
+ {pos: [1, 2, 0], state: "minecraft:air"},
+ {pos: [1, 2, 1], state: "minecraft:air"},
+ {pos: [1, 2, 2], state: "minecraft:air"},
+ {pos: [1, 2, 3], state: "minecraft:air"},
+ {pos: [1, 2, 4], state: "minecraft:air"},
+ {pos: [2, 2, 0], state: "minecraft:air"},
+ {pos: [2, 2, 1], state: "minecraft:air"},
+ {pos: [2, 2, 2], state: "minecraft:air"},
+ {pos: [2, 2, 3], state: "minecraft:air"},
+ {pos: [2, 2, 4], state: "minecraft:air"},
+ {pos: [3, 2, 0], state: "minecraft:air"},
+ {pos: [3, 2, 1], state: "minecraft:air"},
+ {pos: [3, 2, 2], state: "minecraft:air"},
+ {pos: [3, 2, 3], state: "minecraft:air"},
+ {pos: [3, 2, 4], state: "minecraft:air"},
+ {pos: [4, 2, 0], state: "minecraft:air"},
+ {pos: [4, 2, 1], state: "minecraft:air"},
+ {pos: [4, 2, 2], state: "minecraft:air"},
+ {pos: [4, 2, 3], state: "minecraft:air"},
+ {pos: [4, 2, 4], state: "minecraft:air"},
+ {pos: [0, 3, 0], state: "minecraft:air"},
+ {pos: [0, 3, 1], state: "minecraft:air"},
+ {pos: [0, 3, 2], state: "minecraft:air"},
+ {pos: [0, 3, 3], state: "minecraft:air"},
+ {pos: [0, 3, 4], state: "minecraft:air"},
+ {pos: [1, 3, 0], state: "minecraft:air"},
+ {pos: [1, 3, 1], state: "minecraft:air"},
+ {pos: [1, 3, 2], state: "minecraft:air"},
+ {pos: [1, 3, 3], state: "minecraft:air"},
+ {pos: [1, 3, 4], state: "minecraft:air"},
+ {pos: [2, 3, 0], state: "minecraft:air"},
+ {pos: [2, 3, 1], state: "minecraft:air"},
+ {pos: [2, 3, 2], state: "minecraft:air"},
+ {pos: [2, 3, 3], state: "minecraft:air"},
+ {pos: [2, 3, 4], state: "minecraft:air"},
+ {pos: [3, 3, 0], state: "minecraft:air"},
+ {pos: [3, 3, 1], state: "minecraft:air"},
+ {pos: [3, 3, 2], state: "minecraft:air"},
+ {pos: [3, 3, 3], state: "minecraft:air"},
+ {pos: [3, 3, 4], state: "minecraft:air"},
+ {pos: [4, 3, 0], state: "minecraft:air"},
+ {pos: [4, 3, 1], state: "minecraft:air"},
+ {pos: [4, 3, 2], state: "minecraft:air"},
+ {pos: [4, 3, 3], state: "minecraft:air"},
+ {pos: [4, 3, 4], state: "minecraft:air"},
+ {pos: [0, 4, 0], state: "minecraft:air"},
+ {pos: [0, 4, 1], state: "minecraft:air"},
+ {pos: [0, 4, 2], state: "minecraft:air"},
+ {pos: [0, 4, 3], state: "minecraft:air"},
+ {pos: [0, 4, 4], state: "minecraft:air"},
+ {pos: [1, 4, 0], state: "minecraft:air"},
+ {pos: [1, 4, 1], state: "minecraft:air"},
+ {pos: [1, 4, 2], state: "minecraft:air"},
+ {pos: [1, 4, 3], state: "minecraft:air"},
+ {pos: [1, 4, 4], state: "minecraft:air"},
+ {pos: [2, 4, 0], state: "minecraft:air"},
+ {pos: [2, 4, 1], state: "minecraft:air"},
+ {pos: [2, 4, 2], state: "minecraft:air"},
+ {pos: [2, 4, 3], state: "minecraft:air"},
+ {pos: [2, 4, 4], state: "minecraft:air"},
+ {pos: [3, 4, 0], state: "minecraft:air"},
+ {pos: [3, 4, 1], state: "minecraft:air"},
+ {pos: [3, 4, 2], state: "minecraft:air"},
+ {pos: [3, 4, 3], state: "minecraft:air"},
+ {pos: [3, 4, 4], state: "minecraft:air"},
+ {pos: [4, 4, 0], state: "minecraft:air"},
+ {pos: [4, 4, 1], state: "minecraft:air"},
+ {pos: [4, 4, 2], state: "minecraft:air"},
+ {pos: [4, 4, 3], state: "minecraft:air"},
+ {pos: [4, 4, 4], state: "minecraft:air"}
+ ],
+ entities: [],
+ palette: [
+ "minecraft:polished_andesite",
+ "minecraft:air",
+ "minecraft:chest{facing:north,type:single,waterlogged:false}",
+ "computercraft:computer_normal{facing:north,state:on}"
+ ]
+}
diff --git a/projects/common/src/testMod/resources/data/cctest/structures/modem_test.chest_resizes_on_change.snbt b/projects/common/src/testMod/resources/data/cctest/structures/modem_test.chest_resizes_on_change.snbt
new file mode 100644
index 000000000..b5fbf4cf8
--- /dev/null
+++ b/projects/common/src/testMod/resources/data/cctest/structures/modem_test.chest_resizes_on_change.snbt
@@ -0,0 +1,139 @@
+{
+ DataVersion: 3465,
+ size: [5, 5, 5],
+ data: [
+ {pos: [0, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [0, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [1, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [2, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [3, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 0], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 1], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 2], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 3], state: "minecraft:polished_andesite"},
+ {pos: [4, 0, 4], state: "minecraft:polished_andesite"},
+ {pos: [0, 1, 0], state: "minecraft:air"},
+ {pos: [0, 1, 1], state: "minecraft:air"},
+ {pos: [0, 1, 2], state: "minecraft:air"},
+ {pos: [0, 1, 3], state: "minecraft:air"},
+ {pos: [0, 1, 4], state: "minecraft:air"},
+ {pos: [1, 1, 0], state: "minecraft:air"},
+ {pos: [1, 1, 1], state: "minecraft:air"},
+ {pos: [1, 1, 2], state: "minecraft:air"},
+ {pos: [1, 1, 3], state: "minecraft:air"},
+ {pos: [1, 1, 4], state: "minecraft:air"},
+ {pos: [2, 1, 0], state: "minecraft:air"},
+ {pos: [2, 1, 1], state: "minecraft:air"},
+ {pos: [2, 1, 2], state: "minecraft:chest{facing:north,type:single,waterlogged:false}", nbt: {Items: [], id: "minecraft:chest"}},
+ {pos: [2, 1, 3], state: "minecraft:air"},
+ {pos: [2, 1, 4], state: "minecraft:air"},
+ {pos: [3, 1, 0], state: "minecraft:air"},
+ {pos: [3, 1, 1], state: "computercraft:computer_normal{facing:north,state:on}", nbt: {ComputerId: 1, Label: "modem_test.chest_resizes_on_change", On: 1b, id: "computercraft:computer_normal"}},
+ {pos: [3, 1, 2], state: "computercraft:wired_modem_full{modem:false,peripheral:true}", nbt: {PeripheralId2: 2, PeripheralId4: 0, PeripheralType2: "computer", PeripheralType4: "minecraft:chest", id: "computercraft:wired_modem_full"}},
+ {pos: [3, 1, 3], state: "minecraft:air"},
+ {pos: [3, 1, 4], state: "minecraft:air"},
+ {pos: [4, 1, 0], state: "minecraft:air"},
+ {pos: [4, 1, 1], state: "minecraft:air"},
+ {pos: [4, 1, 2], state: "minecraft:air"},
+ {pos: [4, 1, 3], state: "minecraft:air"},
+ {pos: [4, 1, 4], state: "minecraft:air"},
+ {pos: [0, 2, 0], state: "minecraft:air"},
+ {pos: [0, 2, 1], state: "minecraft:air"},
+ {pos: [0, 2, 2], state: "minecraft:air"},
+ {pos: [0, 2, 3], state: "minecraft:air"},
+ {pos: [0, 2, 4], state: "minecraft:air"},
+ {pos: [1, 2, 0], state: "minecraft:air"},
+ {pos: [1, 2, 1], state: "minecraft:air"},
+ {pos: [1, 2, 2], state: "minecraft:air"},
+ {pos: [1, 2, 3], state: "minecraft:air"},
+ {pos: [1, 2, 4], state: "minecraft:air"},
+ {pos: [2, 2, 0], state: "minecraft:air"},
+ {pos: [2, 2, 1], state: "minecraft:air"},
+ {pos: [2, 2, 2], state: "minecraft:air"},
+ {pos: [2, 2, 3], state: "minecraft:air"},
+ {pos: [2, 2, 4], state: "minecraft:air"},
+ {pos: [3, 2, 0], state: "minecraft:air"},
+ {pos: [3, 2, 1], state: "minecraft:air"},
+ {pos: [3, 2, 2], state: "minecraft:air"},
+ {pos: [3, 2, 3], state: "minecraft:air"},
+ {pos: [3, 2, 4], state: "minecraft:air"},
+ {pos: [4, 2, 0], state: "minecraft:air"},
+ {pos: [4, 2, 1], state: "minecraft:air"},
+ {pos: [4, 2, 2], state: "minecraft:air"},
+ {pos: [4, 2, 3], state: "minecraft:air"},
+ {pos: [4, 2, 4], state: "minecraft:air"},
+ {pos: [0, 3, 0], state: "minecraft:air"},
+ {pos: [0, 3, 1], state: "minecraft:air"},
+ {pos: [0, 3, 2], state: "minecraft:air"},
+ {pos: [0, 3, 3], state: "minecraft:air"},
+ {pos: [0, 3, 4], state: "minecraft:air"},
+ {pos: [1, 3, 0], state: "minecraft:air"},
+ {pos: [1, 3, 1], state: "minecraft:air"},
+ {pos: [1, 3, 2], state: "minecraft:air"},
+ {pos: [1, 3, 3], state: "minecraft:air"},
+ {pos: [1, 3, 4], state: "minecraft:air"},
+ {pos: [2, 3, 0], state: "minecraft:air"},
+ {pos: [2, 3, 1], state: "minecraft:air"},
+ {pos: [2, 3, 2], state: "minecraft:air"},
+ {pos: [2, 3, 3], state: "minecraft:air"},
+ {pos: [2, 3, 4], state: "minecraft:air"},
+ {pos: [3, 3, 0], state: "minecraft:air"},
+ {pos: [3, 3, 1], state: "minecraft:air"},
+ {pos: [3, 3, 2], state: "minecraft:air"},
+ {pos: [3, 3, 3], state: "minecraft:air"},
+ {pos: [3, 3, 4], state: "minecraft:air"},
+ {pos: [4, 3, 0], state: "minecraft:air"},
+ {pos: [4, 3, 1], state: "minecraft:air"},
+ {pos: [4, 3, 2], state: "minecraft:air"},
+ {pos: [4, 3, 3], state: "minecraft:air"},
+ {pos: [4, 3, 4], state: "minecraft:air"},
+ {pos: [0, 4, 0], state: "minecraft:air"},
+ {pos: [0, 4, 1], state: "minecraft:air"},
+ {pos: [0, 4, 2], state: "minecraft:air"},
+ {pos: [0, 4, 3], state: "minecraft:air"},
+ {pos: [0, 4, 4], state: "minecraft:air"},
+ {pos: [1, 4, 0], state: "minecraft:air"},
+ {pos: [1, 4, 1], state: "minecraft:air"},
+ {pos: [1, 4, 2], state: "minecraft:air"},
+ {pos: [1, 4, 3], state: "minecraft:air"},
+ {pos: [1, 4, 4], state: "minecraft:air"},
+ {pos: [2, 4, 0], state: "minecraft:air"},
+ {pos: [2, 4, 1], state: "minecraft:air"},
+ {pos: [2, 4, 2], state: "minecraft:air"},
+ {pos: [2, 4, 3], state: "minecraft:air"},
+ {pos: [2, 4, 4], state: "minecraft:air"},
+ {pos: [3, 4, 0], state: "minecraft:air"},
+ {pos: [3, 4, 1], state: "minecraft:air"},
+ {pos: [3, 4, 2], state: "minecraft:air"},
+ {pos: [3, 4, 3], state: "minecraft:air"},
+ {pos: [3, 4, 4], state: "minecraft:air"},
+ {pos: [4, 4, 0], state: "minecraft:air"},
+ {pos: [4, 4, 1], state: "minecraft:air"},
+ {pos: [4, 4, 2], state: "minecraft:air"},
+ {pos: [4, 4, 3], state: "minecraft:air"},
+ {pos: [4, 4, 4], state: "minecraft:air"}
+ ],
+ entities: [],
+ palette: [
+ "minecraft:polished_andesite",
+ "minecraft:air",
+ "minecraft:chest{facing:north,type:single,waterlogged:false}",
+ "computercraft:computer_normal{facing:north,state:on}",
+ "computercraft:wired_modem_full{modem:false,peripheral:true}"
+ ]
+}