Roll a placement back to what was there rather than to air

This commit is contained in:
ABKQPO committed 2026-09-11 10:13:09 +08:00
1 parent 6209d67ba7
commit 6bc8cea2bf
3 files changed
+36 -8

No files matched your search

@@ -2,6 +2,8 @@ package com.gtnewhorizon.structurelib;
import static com.gtnewhorizon.structurelib.StructureLib.proxy;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
@@ -328,6 +330,26 @@ public class StructureLibAPI {
return block.isAir(w, x, y, z) || block.isReplaceable(w, x, y, z);
}
/**
* Put back the block that was at a position, which is what a placement that could not be paid for should roll back
* to.
* <p>
* Restoring the previous state instead of clearing the position matters whenever the position held something
* autoplace is allowed to replace, e.g. a fluid that is not a source block: the player would otherwise be left with
* a hole where their fluid used to be.
*
* @param world world to write to
* @param x x coord
* @param y y coord
* @param z z coord
* @param block the block that was there, or null for air
* @param meta the meta that was there
*/
public static void restoreBlock(World world, int x, int y, int z, @Nullable Block block, int meta) {
if (block == null || block.isAir(world, x, y, z)) world.setBlockToAir(x, y, z);
else world.setBlock(x, y, z, block, meta, 3);
}
/**
* Send chat to player, but throttled.
*
@@ -319,8 +319,7 @@ public class FluidAutoplace {
}
private static void restore(World world, int x, int y, int z, Block block, int meta) {
if (block == null || block.isAir(world, x, y, z)) world.setBlockToAir(x, y, z);
else world.setBlock(x, y, z, block, meta, 3);
StructureLibAPI.restoreBlock(world, x, y, z, block, meta);
}
private static void reportMissingFluid(AutoPlaceEnvironment env, FluidBlockRequirement requirement, int missing) {
@@ -194,7 +194,7 @@ public class StructureUtility {
@Override
public boolean placeBlock(Object o, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, Blocks.air, 0, 2);
world.setBlock(x, y, z, Blocks.air, 0, 3);
return false;
}
@@ -204,7 +204,8 @@ public class StructureUtility {
AutoPlaceEnvironment env) {
if (check(o, world, x, y, z)) return PlaceResult.SKIP;
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, env.getActor())) return PlaceResult.REJECT;
world.setBlock(x, y, z, Blocks.air, 0, 2);
// Notify the neighbours, so that e.g. a fluid next to a position that had to be emptied flows back into it.
world.setBlock(x, y, z, Blocks.air, 0, 3);
return PlaceResult.ACCEPT;
}
};
@@ -494,6 +495,8 @@ public class StructureUtility {
new ChatComponentTranslation("structurelib.autoplace.missing_block", getStackChatName(stack)));
return PlaceResult.REJECT;
}
Block previousBlock = world.getBlock(x, y, z);
int previousMeta = world.getBlockMetadata(x, y, z);
if (block instanceof ICustomBlockSetting blockCustom) {
blockCustom.setBlock(world, x, y, z, meta);
} else if (!stack.copy()
@@ -501,8 +504,9 @@ public class StructureUtility {
return PlaceResult.REJECT;
}
if (!s.takeOne(stack, false)) {
// rollback
world.setBlockToAir(x, y, z);
// Roll back to what was there before, which is often a fluid that this block was placed over, so that a
// position is never left empty by a placement that was not paid for.
StructureLibAPI.restoreBlock(world, x, y, z, previousBlock, previousMeta);
}
return PlaceResult.ACCEPT;
}
@@ -600,11 +604,14 @@ public class StructureUtility {
new ChatComponentTranslation("structurelib.autoplace.missing_block", getStackChatName(stack)));
return PlaceResult.REJECT;
}
Block previousBlock = world.getBlock(x, y, z);
int previousMeta = world.getBlockMetadata(x, y, z);
if (!stack.copy().tryPlaceItemIntoWorld(actor, world, x, y, z, ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f))
return PlaceResult.REJECT;
if (!s.takeOne(stack, false))
// this is bad! probably an exploit somehow. Let's nullify the block we just placed instead
world.setBlockToAir(x, y, z);
// this is bad! probably an exploit somehow. Put back what was there instead of clearing the position, as
// that would destroy the fluid this block was placed over.
StructureLibAPI.restoreBlock(world, x, y, z, previousBlock, previousMeta);
return PlaceResult.ACCEPT;
}