Skip to content

Commit 9b8160d

Browse files
committed
Fix item loss when replacing walls in Fabric
Closes #191
1 parent 9eea08b commit 9b8160d

8 files changed

Lines changed: 122 additions & 14 deletions

File tree

loader-common/src/main/java/org/cyclops/colossalchests/block/ChestWall.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,24 +73,28 @@ public boolean propagatesSkylightDown(BlockState blockState, BlockGetter blockRe
7373
@Override
7474
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
7575
super.setPlacedBy(world, pos, state, placer, stack);
76-
ColossalChest.triggerDetector(this.material, world, pos, true, placer instanceof Player ? (Player) placer : null);
76+
ColossalChest.triggerDetector(this.material, world, pos, true, placer instanceof Player ? (Player) placer : null, canBlockSnapshotsBeCaptured());
7777
}
7878

7979
@Override
8080
public void onPlace(BlockState blockStateNew, Level world, BlockPos blockPos, BlockState blockStateOld, boolean isMoving) {
8181
super.onPlace(blockStateNew, world, blockPos, blockStateOld, isMoving);
8282
if(!isCaptureBlockSnapshots(world) && blockStateNew.getBlock() != blockStateOld.getBlock() && !blockStateNew.getValue(ENABLED)) {
83-
ColossalChest.triggerDetector(this.material, world, blockPos, true, null);
83+
ColossalChest.triggerDetector(this.material, world, blockPos, true, null, true);
8484
}
8585
}
8686

87+
protected boolean canBlockSnapshotsBeCaptured() {
88+
return false;
89+
}
90+
8791
protected boolean isCaptureBlockSnapshots(Level level) {
8892
return false;
8993
}
9094

9195
@Override
9296
public void destroy(LevelAccessor world, BlockPos blockPos, BlockState blockState) {
93-
if(blockState.getValue(ENABLED)) ColossalChest.triggerDetector(material, world, blockPos, false, null);
97+
if(blockState.getValue(ENABLED)) ColossalChest.triggerDetector(material, world, blockPos, false, null, true);
9498
super.destroy(world, blockPos, blockState);
9599
}
96100

@@ -126,7 +130,7 @@ public boolean canSurvive(BlockState blockState, LevelReader world, BlockPos blo
126130
}
127131

128132
public void onBlockExplodedCommon(BlockState state, Level world, BlockPos pos, Explosion explosion) {
129-
if(world.getBlockState(pos).getValue(ENABLED)) ColossalChest.triggerDetector(material, world, pos, false, null);
133+
if(world.getBlockState(pos).getValue(ENABLED)) ColossalChest.triggerDetector(material, world, pos, false, null, true);
130134
// IForgeBlock.super.onBlockExploded(state, world, pos, explosion);
131135
world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
132136
wasExploded(world, pos, explosion);

loader-common/src/main/java/org/cyclops/colossalchests/block/ColossalChest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ public boolean propagatesSkylightDown(BlockState blockState, BlockGetter blockRe
140140
return blockState.getValue(ENABLED);
141141
}
142142

143-
public static DetectionResult triggerDetector(ChestMaterial material, LevelAccessor world, BlockPos blockPos, boolean valid, @Nullable Player player) {
144-
DetectionResult detectionResult = material.getChestDetector().detect(world, blockPos, valid ? null : blockPos, new MaterialValidationAction(), true);
143+
public static DetectionResult triggerDetector(ChestMaterial material, LevelAccessor world, BlockPos blockPos, boolean valid, @Nullable Player player, boolean changeState) {
144+
DetectionResult detectionResult = material.getChestDetector().detect(world, blockPos, valid ? null : blockPos, new MaterialValidationAction(), changeState);
145145
if (player instanceof ServerPlayer && detectionResult.getError() == null) {
146146
BlockState blockState = world.getBlockState(blockPos);
147147
if (blockState.getValue(ENABLED)) {
@@ -167,14 +167,14 @@ public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntit
167167
tile.setSize(Vec3i.ZERO);
168168
}
169169
}
170-
triggerDetector(this.material, world, pos, true, placer instanceof Player ? (Player) placer : null);
170+
triggerDetector(this.material, world, pos, true, placer instanceof Player ? (Player) placer : null, true);
171171
}
172172

173173
@Override
174174
public void onPlace(BlockState blockStateNew, Level world, BlockPos blockPos, BlockState blockStateOld, boolean isMoving) {
175175
super.onPlace(blockStateNew, world, blockPos, blockStateOld, isMoving);
176176
if(!isCaptureBlockSnapshots(world) && blockStateNew.getBlock() != blockStateOld.getBlock() && !blockStateNew.getValue(ENABLED)) {
177-
triggerDetector(this.material, world, blockPos, true, null);
177+
triggerDetector(this.material, world, blockPos, true, null, true);
178178
}
179179
}
180180

@@ -273,7 +273,7 @@ public InteractionResult useWithoutItem(BlockState blockState, Level world, Bloc
273273

274274
@Override
275275
public void destroy(LevelAccessor world, BlockPos blockPos, BlockState blockState) {
276-
if(blockState.getValue(ENABLED)) ColossalChest.triggerDetector(material, world, blockPos, false, null);
276+
if(blockState.getValue(ENABLED)) ColossalChest.triggerDetector(material, world, blockPos, false, null, true);
277277
super.destroy(world, blockPos, blockState);
278278
}
279279

@@ -296,7 +296,7 @@ public void onRemove(BlockState oldState, Level world, BlockPos blockPos, BlockS
296296
}
297297

298298
public void onBlockExplodedCommon(BlockState state, Level world, BlockPos pos, Explosion explosion) {
299-
if(world.getBlockState(pos).getValue(ENABLED)) ColossalChest.triggerDetector(material, world, pos, false, null);
299+
if(world.getBlockState(pos).getValue(ENABLED)) ColossalChest.triggerDetector(material, world, pos, false, null, true);
300300
// IForgeBlock.super.onBlockExploded(state, world, pos, explosion);
301301
world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
302302
wasExploded(world, pos, explosion);

loader-common/src/main/java/org/cyclops/colossalchests/block/Interface.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,28 @@ public boolean propagatesSkylightDown(BlockState blockState, BlockGetter blockRe
8888
@Override
8989
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
9090
super.setPlacedBy(world, pos, state, placer, stack);
91-
ColossalChest.triggerDetector(this.material, world, pos, true, placer instanceof Player ? (Player) placer : null);
91+
ColossalChest.triggerDetector(this.material, world, pos, true, placer instanceof Player ? (Player) placer : null, canBlockSnapshotsBeCaptured());
9292
}
9393

9494
@Override
9595
public void onPlace(BlockState blockStateNew, Level world, BlockPos blockPos, BlockState blockStateOld, boolean isMoving) {
9696
super.onPlace(blockStateNew, world, blockPos, blockStateOld, isMoving);
9797
if(!isCaptureBlockSnapshots(world) && blockStateNew.getBlock() != blockStateOld.getBlock() && !blockStateNew.getValue(ENABLED)) {
98-
ColossalChest.triggerDetector(this.material, world, blockPos, true, null);
98+
ColossalChest.triggerDetector(this.material, world, blockPos, true, null, true);
9999
}
100100
}
101101

102+
protected boolean canBlockSnapshotsBeCaptured() {
103+
return false;
104+
}
105+
102106
protected boolean isCaptureBlockSnapshots(Level level) {
103107
return false;
104108
}
105109

106110
@Override
107111
public void destroy(LevelAccessor world, BlockPos blockPos, BlockState blockState) {
108-
if(blockState.getValue(ENABLED)) ColossalChest.triggerDetector(material, world, blockPos, false, null);
112+
if(blockState.getValue(ENABLED)) ColossalChest.triggerDetector(material, world, blockPos, false, null, true);
109113
super.destroy(world, blockPos, blockState);
110114
}
111115

@@ -130,7 +134,7 @@ public void onDetect(LevelReader world, BlockPos location, Vec3i size, boolean v
130134
}
131135

132136
public void onBlockExplodedCommon(BlockState state, Level world, BlockPos pos, Explosion explosion) {
133-
if(world.getBlockState(pos).getValue(ENABLED)) ColossalChest.triggerDetector(material, world, pos, false, null);
137+
if(world.getBlockState(pos).getValue(ENABLED)) ColossalChest.triggerDetector(material, world, pos, false, null, true);
134138
// IForgeBlock.super.onBlockExploded(state, world, pos, explosion);
135139
world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
136140
wasExploded(world, pos, explosion);

loader-common/src/main/java/org/cyclops/colossalchests/gametest/GameTestsCommon.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import net.minecraft.world.item.Items;
1414
import net.minecraft.world.item.context.UseOnContext;
1515
import net.minecraft.world.level.GameType;
16+
import net.minecraft.world.level.block.Block;
1617
import net.minecraft.world.level.block.Blocks;
1718
import net.minecraft.world.level.block.HopperBlock;
1819
import net.minecraft.world.level.block.entity.HopperBlockEntity;
@@ -836,6 +837,29 @@ public void testColossalWood3x3BreakPlaceWall(GameTestHelper helper) {
836837
});
837838
}
838839

840+
@GameTest(template = TEMPLATE_EMPTY)
841+
public void testColossalWood3x3BreakPlaceWallAsPlayer(GameTestHelper helper) {
842+
HashSet<BlockPos> interfaces = Sets.newHashSet(POS.east().above(), POS.south().above());
843+
BlockEntityColossalChest core = createChest(helper, POS, ChestMaterial.WOOD, 3, Sets.newHashSet(), interfaces);
844+
845+
// Insert item
846+
core.getInventory().setItem(0, new ItemStack(Items.APPLE));
847+
848+
// Break wall
849+
destroyBlock(helper, POS.east());
850+
851+
// Replace wall
852+
setBlockAsPlayer(helper, POS.east(), ChestMaterial.WOOD.getBlockWall());
853+
854+
helper.succeedWhen(() -> {
855+
assertChestValid(helper, POS, ChestMaterial.WOOD, 3, interfaces, false);
856+
857+
// Chest must still contain item, and there must be no dropped items on the ground
858+
assertCoreContains(helper, POS, new ItemStack(Items.APPLE));
859+
helper.assertEntityNotPresent(EntityType.ITEM);
860+
});
861+
}
862+
839863
@GameTest(template = TEMPLATE_EMPTY)
840864
public void testColossalWood3x3BreakPlaceInterface(GameTestHelper helper) {
841865
HashSet<BlockPos> interfaces = Sets.newHashSet(POS.east().above(), POS.south().above());
@@ -859,6 +883,29 @@ public void testColossalWood3x3BreakPlaceInterface(GameTestHelper helper) {
859883
});
860884
}
861885

886+
@GameTest(template = TEMPLATE_EMPTY)
887+
public void testColossalWood3x3BreakPlaceInterfaceAsPlayer(GameTestHelper helper) {
888+
HashSet<BlockPos> interfaces = Sets.newHashSet(POS.east().above(), POS.south().above());
889+
BlockEntityColossalChest core = createChest(helper, POS, ChestMaterial.WOOD, 3, Sets.newHashSet(), interfaces);
890+
891+
// Insert item
892+
core.getInventory().setItem(0, new ItemStack(Items.APPLE));
893+
894+
// Break interface
895+
destroyBlock(helper, POS.east().above());
896+
897+
// Replace interface
898+
setBlockAsPlayer(helper, POS.east().above(), ChestMaterial.WOOD.getBlockInterface());
899+
900+
helper.succeedWhen(() -> {
901+
assertChestValid(helper, POS, ChestMaterial.WOOD, 3, interfaces, false);
902+
903+
// Chest must still contain item, and there must be no dropped items on the ground
904+
assertCoreContains(helper, POS, new ItemStack(Items.APPLE));
905+
helper.assertEntityNotPresent(EntityType.ITEM);
906+
});
907+
}
908+
862909
@GameTest(template = TEMPLATE_EMPTY)
863910
public void testColossalWood3x3BreakPlaceCore(GameTestHelper helper) {
864911
HashSet<BlockPos> interfaces = Sets.newHashSet(POS.offset(4, 1, 4).east().above(), POS.offset(4, 1, 4).south().above());
@@ -884,6 +931,31 @@ public void testColossalWood3x3BreakPlaceCore(GameTestHelper helper) {
884931
});
885932
}
886933

934+
@GameTest(template = TEMPLATE_EMPTY)
935+
public void testColossalWood3x3BreakPlaceCoreAsPlayer(GameTestHelper helper) {
936+
HashSet<BlockPos> interfaces = Sets.newHashSet(POS.offset(4, 1, 4).east().above(), POS.offset(4, 1, 4).south().above());
937+
BlockEntityColossalChest core = createChest(helper, POS.offset(4, 1, 4), ChestMaterial.WOOD, 3, Sets.newHashSet(), interfaces);
938+
939+
// Insert item
940+
core.getInventory().setItem(0, new ItemStack(Items.APPLE));
941+
core.getInventory().setItem(1, new ItemStack(Items.ACACIA_LEAVES));
942+
core.getInventory().setItem(2, new ItemStack(Items.WHITE_WOOL));
943+
944+
// Break core
945+
destroyBlock(helper, POS.offset(4, 1, 4));
946+
947+
// Replace core
948+
setBlockAsPlayer(helper, POS.offset(4, 1, 4), ChestMaterial.WOOD.getBlockCore());
949+
950+
helper.succeedWhen(() -> {
951+
// Chest must not contain item, and all items must be dropped on the ground
952+
assertChestValid(helper, POS.offset(4, 1, 4), ChestMaterial.WOOD, 3, interfaces, true);
953+
helper.assertItemEntityPresent(Items.APPLE);
954+
helper.assertItemEntityPresent(Items.ACACIA_LEAVES);
955+
helper.assertItemEntityPresent(Items.WHITE_WOOL);
956+
});
957+
}
958+
887959
@GameTest(template = TEMPLATE_EMPTY)
888960
public void testColossalWood3x3DestroyTnt(GameTestHelper helper) {
889961
HashSet<BlockPos> interfaces = Sets.newHashSet(POS.east().above(), POS.south().above());
@@ -1052,6 +1124,14 @@ protected void destroyBlock(GameTestHelper helper, BlockPos pos) {
10521124
}
10531125
}
10541126

1127+
private void setBlockAsPlayer(GameTestHelper helper, BlockPos pos, Block block) {
1128+
Player player = helper.makeMockPlayer(GameType.SURVIVAL);
1129+
ItemStack itemStack = new ItemStack(block);
1130+
player.setItemInHand(InteractionHand.MAIN_HAND, itemStack);
1131+
InteractionResult interactionResult = itemStack.useOn(new UseOnContext(player, InteractionHand.MAIN_HAND, new BlockHitResult(pos.getCenter(), Direction.DOWN, helper.absolutePos(pos), false)));
1132+
helper.assertTrue(interactionResult.consumesAction(), "Block placement as player failed");
1133+
}
1134+
10551135
protected boolean isFabric() {
10561136
try {
10571137
Class.forName("net.fabricmc.fabric.api.transfer.v1.item.ItemStorage");

loader-forge/src/main/java/org/cyclops/colossalchests/block/ChestWallForge.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public boolean shouldDisplayFluidOverlay(BlockState blockState, BlockAndTintGett
2121
return true;
2222
}
2323

24+
@Override
25+
protected boolean canBlockSnapshotsBeCaptured() {
26+
return true;
27+
}
28+
2429
@Override
2530
protected boolean isCaptureBlockSnapshots(Level level) {
2631
return level.captureBlockSnapshots;

loader-forge/src/main/java/org/cyclops/colossalchests/block/InterfaceForge.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public boolean shouldDisplayFluidOverlay(BlockState blockState, BlockAndTintGett
2222
return true;
2323
}
2424

25+
@Override
26+
protected boolean canBlockSnapshotsBeCaptured() {
27+
return true;
28+
}
29+
2530
@Override
2631
protected boolean isCaptureBlockSnapshots(Level level) {
2732
return level.captureBlockSnapshots;

loader-neoforge/src/main/java/org/cyclops/colossalchests/block/ChestWallNeoForge.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public boolean shouldDisplayFluidOverlay(BlockState blockState, BlockAndTintGett
2121
return true;
2222
}
2323

24+
@Override
25+
protected boolean canBlockSnapshotsBeCaptured() {
26+
return true;
27+
}
28+
2429
@Override
2530
protected boolean isCaptureBlockSnapshots(Level level) {
2631
return level.captureBlockSnapshots;

loader-neoforge/src/main/java/org/cyclops/colossalchests/block/InterfaceNeoForge.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public boolean shouldDisplayFluidOverlay(BlockState blockState, BlockAndTintGett
2222
return true;
2323
}
2424

25+
@Override
26+
protected boolean canBlockSnapshotsBeCaptured() {
27+
return true;
28+
}
29+
2530
@Override
2631
protected boolean isCaptureBlockSnapshots(Level level) {
2732
return level.captureBlockSnapshots;

0 commit comments

Comments
 (0)