Skip to content

Commit

Permalink
Fix //snow (#3019)
Browse files Browse the repository at this point in the history
* chore: update isFullCube to actually check for shape not occlusion

* chore/fix: fix and update snow simulator

* chore: consistent property field naming
  • Loading branch information
PierreSchwang authored Dec 11, 2024
1 parent 6d44537 commit b548219
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public boolean isAir() {

@Override
public boolean isFullCube() {
return craftMaterial.isOccluding();
return Block.isShapeFullBlock(blockState.getShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public boolean isAir() {

@Override
public boolean isFullCube() {
return craftMaterial.isOccluding();
return Block.isShapeFullBlock(blockState.getShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public boolean isAir() {

@Override
public boolean isFullCube() {
return craftMaterial.isOccluding();
return Block.isShapeFullBlock(blockState.getShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public boolean isAir() {

@Override
public boolean isFullCube() {
return craftMaterial.isOccluding();
return Block.isShapeFullBlock(blockState.getShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public boolean isAir() {

@Override
public boolean isFullCube() {
return craftMaterial.isOccluding();
return Block.isShapeFullBlock(blockState.getShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.function.block.SnowSimulator.snowy;
import static com.sk89q.worldedit.function.block.SnowSimulator.SNOWY;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
Expand Down Expand Up @@ -2788,8 +2788,8 @@ public int thaw(BlockVector3 position, double radius, int height)
if (setBlock(mutable, air)) {
if (y > getMinY()) {
BlockState block = getBlock(mutable2);
if (block.getBlockType().hasProperty(snowy)) {
if (setBlock(mutable2, block.with(snowy, false))) {
if (block.getBlockType().hasProperty(SNOWY)) {
if (setBlock(mutable2, block.with(SNOWY, false))) {
affected++;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,35 @@
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;

import java.util.Locale;
import java.util.Comparator;

//FAWE start - rewrite simulator
public class SnowSimulator implements LayerFunction {

//FAWE start
public static final BooleanProperty snowy = (BooleanProperty) (Property<?>) BlockTypes.GRASS_BLOCK.getProperty("snowy");
private static final EnumProperty slab = (EnumProperty) (Property<?>) BlockTypes.SANDSTONE_SLAB.getProperty("type");
private static final EnumProperty stair = (EnumProperty) (Property<?>) BlockTypes.SANDSTONE_STAIRS.getProperty("half");
private static final EnumProperty trapdoor = (EnumProperty) (Property<?>) BlockTypes.ACACIA_TRAPDOOR.getProperty("half");
private static final BooleanProperty trapdoorOpen = (BooleanProperty) (Property<?>) BlockTypes.ACACIA_TRAPDOOR.getProperty(
"open");
//FAWE end
public static final BooleanProperty SNOWY = (BooleanProperty) (Property<?>) BlockTypes.GRASS_BLOCK.getProperty("snowy");
private static final EnumProperty PROPERTY_SLAB = (EnumProperty) (Property<?>) BlockTypes.OAK_SLAB.getProperty("type");
private static final EnumProperty PROPERTY_STAIR = (EnumProperty) (Property<?>) BlockTypes.OAK_STAIRS.getProperty("half");
private static final EnumProperty PROPERTY_TRAPDOOR = (EnumProperty) (Property<?>) BlockTypes.OAK_TRAPDOOR.getProperty("half");
private static final BooleanProperty PROPERTY_TRAPDOOR_OPEN = (BooleanProperty) (Property<?>) BlockTypes.OAK_TRAPDOOR.getProperty("open");

private final BlockState ice = BlockTypes.ICE.getDefaultState();
private final BlockState snow = BlockTypes.SNOW.getDefaultState();
private final BlockState snowBlock = BlockTypes.SNOW_BLOCK.getDefaultState();
private static final BlockState ICE = BlockTypes.ICE.getDefaultState();
private static final BlockState SNOW = BlockTypes.SNOW.getDefaultState();
private static final BlockState SNOW_BLOCK = BlockTypes.SNOW_BLOCK.getDefaultState();

private final Property<Integer> snowLayersProperty = BlockTypes.SNOW.getProperty("layers");
private final Property<Integer> waterLevelProperty = BlockTypes.WATER.getProperty("level");
private static final Property<Integer> PROPERTY_SNOW_LAYERS = BlockTypes.SNOW.getProperty("layers");
private static final Property<Integer> PROPERTY_WATER_LEVEL = BlockTypes.WATER.getProperty("level");

private static final String PROPERTY_VALUE_TOP = "top";
private static final String PROPERTY_VALUE_BOTTOM = "bottom";
private static final int MAX_SNOW_LAYER = PROPERTY_SNOW_LAYERS.getValues().stream().max(Comparator.naturalOrder()).orElse(8);

private final Extent extent;
private final boolean stack;

private int affected;

public SnowSimulator(Extent extent, boolean stack) {

this.extent = extent;
this.stack = stack;

this.affected = 0;
}

Expand All @@ -70,20 +69,21 @@ public int getAffected() {

@Override
public boolean isGround(BlockVector3 position) {
BlockState block = this.extent.getBlock(position);
final BlockState block = this.extent.getBlock(position);
final BlockType blockType = block.getBlockType();

// We're returning the first block we can place *on top of*
if (block.getBlockType().getMaterial().isAir() || (stack && block.getBlockType() == BlockTypes.SNOW)) {
// We're returning the first block we can (potentially) place *on top of*
if (blockType.getMaterial().isAir() || (stack && blockType == BlockTypes.SNOW)) {
return false;
}

// Unless it's water
if (block.getBlockType() == BlockTypes.WATER) {
if (blockType == BlockTypes.WATER) {
return true;
}

// Stop searching when we hit a movement blocker
return block.getBlockType().getMaterial().isMovementBlocker();
return blockType.getMaterial().isMovementBlocker();
}

@Override
Expand All @@ -93,18 +93,17 @@ public boolean apply(BlockVector3 position, int depth) throws WorldEditException
return false;
}

BlockState block = this.extent.getBlock(position);
final BlockState block = this.extent.getBlock(position);
final BlockType blockType = block.getBlockType();

if (block.getBlockType() == BlockTypes.WATER) {
if (block.getState(waterLevelProperty) == 0) {
if (this.extent.setBlock(position, ice)) {
affected++;
}
// If affected block is water, replace with ice
if (blockType == BlockTypes.WATER) {
if (shouldFreeze(position, block) && this.extent.setBlock(position.x(), position.y(), position.z(), ICE)) {
affected++;
}
return false;
}


// Can't put snow this far up
if (position.y() == this.extent.getMaximumPoint().y()) {
return false;
Expand All @@ -113,57 +112,91 @@ public boolean apply(BlockVector3 position, int depth) throws WorldEditException
BlockVector3 abovePosition = position.add(0, 1, 0);
BlockState above = this.extent.getBlock(abovePosition);

// Can only replace air (or snow in stack mode)
if (!above.getBlockType().getMaterial().isAir() && (!stack || above.getBlockType() != BlockTypes.SNOW)) {
return false;
//FAWE start
} else if (!block.getBlockType().id().toLowerCase(Locale.ROOT).contains("ice") && this.extent.getEmittedLight(
abovePosition) > 10) {
if (!shouldSnow(block, above)) {
return false;
} else if (!block.getBlockType().getMaterial().isFullCube()) {
BlockType type = block.getBlockType();
if (type.hasProperty(slab) && block.getState(slab).equalsIgnoreCase("bottom")) {
return false;
} else if ((type.hasProperty(trapdoorOpen) && block.getState(trapdoorOpen)) ||
(type.hasProperty(trapdoor) && block.getState(trapdoor).equalsIgnoreCase("bottom"))) {
}

// in stack mode, we want to increase existing snow layers
if (stack && above.getBlockType() == BlockTypes.SNOW) {
int layers = above.getState(PROPERTY_SNOW_LAYERS);
// if we would place the last possible layer (in current versions layer 8) we just replace with a snow block and
// set the block beneath snowy (if property is applicable, example would be grass with snow texture on top)
if (layers == MAX_SNOW_LAYER - 1 && !this.extent.setBlock(abovePosition, SNOW_BLOCK)) {
return false;
} else if (type.hasProperty(stair) && block.getState(stair).equalsIgnoreCase("bottom")) {
}
// we've not reached the top snow layer yet, so just add another layer
if (!this.extent.setBlock(abovePosition, above.with(PROPERTY_SNOW_LAYERS, layers + 1))) {
return false;
} else {
}
} else {
if (!this.extent.setBlock(abovePosition, SNOW)) {
return false;
}
//FAWE end
} else if (!BlockCategories.SNOW_LAYER_CAN_SURVIVE_ON.contains(block.getBlockType())) {
}
// set block beneath snow (layers) snowy, if applicable
if (block.getBlockType().hasProperty(SNOWY)) {
this.extent.setBlock(position, block.with(SNOWY, true));
}
this.affected++;
return false;
}

/**
* Check if snow should be placed at {@code above}
*
* @param blockState The block under the snow layer
* @param above The block which will hold the snow layer
* @return if snow should be placed
*/
private boolean shouldSnow(BlockState blockState, BlockState above) {
// simplified net.minecraft.world.level.biome.Biome#shouldSnow
// if the block, where the snow should be actually placed at, is not air or snow (if in stack mode), we can't place
// anything
if (!(above.isAir() || (above.getBlockType() == BlockTypes.SNOW && stack))) {
return false;
}
// net.minecraft.world.level.block.SnowLayerBlock#canSurvive
if (BlockCategories.SNOW_LAYER_CANNOT_SURVIVE_ON.contains(blockState)) {
return false;
}
if (BlockCategories.SNOW_LAYER_CAN_SURVIVE_ON.contains(blockState)) {
return true;
}
BlockType type = blockState.getBlockType();

if (stack && above.getBlockType() == BlockTypes.SNOW) {
int currentHeight = above.getState(snowLayersProperty);
// We've hit the highest layer (If it doesn't contain current + 2 it means it's 1 away from full)
if (!snowLayersProperty.getValues().contains(currentHeight + 2)) {
if (this.extent.setBlock(abovePosition, snowBlock)) {
if (block.getBlockType().hasProperty(snowy)) {
this.extent.setBlock(position, block.with(snowy, true));
}
this.affected++;
}
} else {
if (this.extent.setBlock(abovePosition, above.with(snowLayersProperty, currentHeight + 1))) {
if (block.getBlockType().hasProperty(snowy)) {
this.extent.setBlock(position, block.with(snowy, true));
}
this.affected++;
}
}
// net.minecraft.world.level.block.Block.isFaceFull (block has 1x1x1 bounding box)
if (type.getMaterial().isFullCube()) {
return true;
}
// if block beneath potential snow layer has snow layers, we can place snow if all possible layers are present.
if (type == BlockTypes.SNOW && blockState.getState(PROPERTY_SNOW_LAYERS) == MAX_SNOW_LAYER) {
return true;
}
// return potential non-full blocks, which could hold snow layers due to block states
// if block is a slab, needs to be on the upper part of the block
if (type.hasProperty(PROPERTY_SLAB)) {
return PROPERTY_VALUE_TOP.equals(blockState.getState(PROPERTY_SLAB));
}
// if block is a trapdoor, the trapdoor must NOT be open
if (type.hasProperty(PROPERTY_TRAPDOOR_OPEN) && blockState.getState(PROPERTY_TRAPDOOR_OPEN)) {
return false;
}
if (this.extent.setBlock(abovePosition, snow)) {
if (block.getBlockType().hasProperty(snowy)) {
this.extent.setBlock(position, block.with(snowy, true));
}
this.affected++;
// if block is a closed trapdoor, the trapdoor must be aligned at the top part of the block
if (type.hasProperty(PROPERTY_TRAPDOOR)) {
return PROPERTY_VALUE_TOP.equals(blockState.getState(PROPERTY_TRAPDOOR));
}
// if block is a stair, it must be "bottom" (upside-down)
if (type.hasProperty(PROPERTY_STAIR)) {
return PROPERTY_VALUE_BOTTOM.equals(blockState.getState(PROPERTY_STAIR));
}
return false;
}

// net.minecraft.world.level.biome.Biome#shouldFreeze
private boolean shouldFreeze(BlockVector3 position, BlockState blockState) {
return blockState.getBlockType() == BlockTypes.WATER &&
blockState.getState(PROPERTY_WATER_LEVEL) == 0 &&
this.extent.getEmittedLight(position) < 10;
}

}

0 comments on commit b548219

Please sign in to comment.