3131import com .sk89q .worldedit .world .block .BlockType ;
3232import com .sk89q .worldedit .world .block .BlockTypes ;
3333
34- import java .util .Locale ;
34+ import java .util .Comparator ;
3535
36+ //FAWE start - rewrite simulator
3637public class SnowSimulator implements LayerFunction {
3738
38- //FAWE start
39- public static final BooleanProperty snowy = (BooleanProperty ) (Property <?>) BlockTypes .GRASS_BLOCK .getProperty ("snowy" );
40- private static final EnumProperty slab = (EnumProperty ) (Property <?>) BlockTypes .SANDSTONE_SLAB .getProperty ("type" );
41- private static final EnumProperty stair = (EnumProperty ) (Property <?>) BlockTypes .SANDSTONE_STAIRS .getProperty ("half" );
42- private static final EnumProperty trapdoor = (EnumProperty ) (Property <?>) BlockTypes .ACACIA_TRAPDOOR .getProperty ("half" );
43- private static final BooleanProperty trapdoorOpen = (BooleanProperty ) (Property <?>) BlockTypes .ACACIA_TRAPDOOR .getProperty (
39+ public static final BooleanProperty SNOWY = (BooleanProperty ) (Property <?>) BlockTypes .GRASS_BLOCK .getProperty ("snowy" );
40+ private static final EnumProperty PROPERTY_SLAB = (EnumProperty ) (Property <?>) BlockTypes .OAK_SLAB .getProperty ("type" );
41+ private static final EnumProperty PROPERTY_STAIR = (EnumProperty ) (Property <?>) BlockTypes .OAK_STAIRS .getProperty ("half" );
42+ private static final EnumProperty TRAPDOOR = (EnumProperty ) (Property <?>) BlockTypes .OAK_TRAPDOOR .getProperty ("half" );
43+ private static final BooleanProperty TRAPDOOR_OPEN = (BooleanProperty ) (Property <?>) BlockTypes .OAK_TRAPDOOR .getProperty (
4444 "open" );
45- //FAWE end
4645
47- private final BlockState ice = BlockTypes .ICE .getDefaultState ();
48- private final BlockState snow = BlockTypes .SNOW .getDefaultState ();
49- private final BlockState snowBlock = BlockTypes .SNOW_BLOCK .getDefaultState ();
46+ private static final BlockState ICE = BlockTypes .ICE .getDefaultState ();
47+ private static final BlockState SNOW = BlockTypes .SNOW .getDefaultState ();
48+ private static final BlockState SNOW_BLOCK = BlockTypes .SNOW_BLOCK .getDefaultState ();
5049
51- private final Property <Integer > snowLayersProperty = BlockTypes .SNOW .getProperty ("layers" );
52- private final Property <Integer > waterLevelProperty = BlockTypes .WATER .getProperty ("level" );
50+ private static final Property <Integer > PROPERTY_SNOW_LAYERS = BlockTypes .SNOW .getProperty ("layers" );
51+ private static final Property <Integer > PROPERTY_WATER_LEVEL = BlockTypes .WATER .getProperty ("level" );
52+
53+ private static final String PROPERTY_VALUE_TOP = "top" ;
54+ private static final String PROPERTY_VALUE_BOTTOM = "bottom" ;
55+ private static final int MAX_SNOW_LAYER = PROPERTY_SNOW_LAYERS .getValues ().stream ().max (Comparator .naturalOrder ()).orElse (8 );
5356
5457 private final Extent extent ;
5558 private final boolean stack ;
56-
5759 private int affected ;
5860
5961 public SnowSimulator (Extent extent , boolean stack ) {
60-
6162 this .extent = extent ;
6263 this .stack = stack ;
63-
6464 this .affected = 0 ;
6565 }
6666
@@ -70,20 +70,21 @@ public int getAffected() {
7070
7171 @ Override
7272 public boolean isGround (BlockVector3 position ) {
73- BlockState block = this .extent .getBlock (position );
73+ final BlockState block = this .extent .getBlock (position );
74+ final BlockType blockType = block .getBlockType ();
7475
75- // We're returning the first block we can place *on top of*
76- if (block . getBlockType (). getMaterial ().isAir () || (stack && block . getBlockType () == BlockTypes .SNOW )) {
76+ // We're returning the first block we can (potentially) place *on top of*
77+ if (blockType . getMaterial ().isAir () || (stack && blockType == BlockTypes .SNOW )) {
7778 return false ;
7879 }
7980
8081 // Unless it's water
81- if (block . getBlockType () == BlockTypes .WATER ) {
82+ if (blockType == BlockTypes .WATER ) {
8283 return true ;
8384 }
8485
8586 // Stop searching when we hit a movement blocker
86- return block . getBlockType () .getMaterial ().isMovementBlocker ();
87+ return blockType .getMaterial ().isMovementBlocker ();
8788 }
8889
8990 @ Override
@@ -93,18 +94,17 @@ public boolean apply(BlockVector3 position, int depth) throws WorldEditException
9394 return false ;
9495 }
9596
96- BlockState block = this .extent .getBlock (position );
97+ final BlockState block = this .extent .getBlock (position );
98+ final BlockType blockType = block .getBlockType ();
9799
98- if (block .getBlockType () == BlockTypes .WATER ) {
99- if (block .getState (waterLevelProperty ) == 0 ) {
100- if (this .extent .setBlock (position , ice )) {
101- affected ++;
102- }
100+ // If affected block is water, replace with ice
101+ if (blockType == BlockTypes .WATER ) {
102+ if (shouldFreeze (position , block ) && this .extent .setBlock (position .x (), position .y (), position .z (), ICE )) {
103+ affected ++;
103104 }
104105 return false ;
105106 }
106107
107-
108108 // Can't put snow this far up
109109 if (position .y () == this .extent .getMaximumPoint ().y ()) {
110110 return false ;
@@ -113,57 +113,91 @@ public boolean apply(BlockVector3 position, int depth) throws WorldEditException
113113 BlockVector3 abovePosition = position .add (0 , 1 , 0 );
114114 BlockState above = this .extent .getBlock (abovePosition );
115115
116- // Can only replace air (or snow in stack mode)
117- if (!above .getBlockType ().getMaterial ().isAir () && (!stack || above .getBlockType () != BlockTypes .SNOW )) {
118- return false ;
119- //FAWE start
120- } else if (!block .getBlockType ().id ().toLowerCase (Locale .ROOT ).contains ("ice" ) && this .extent .getEmittedLight (
121- abovePosition ) > 10 ) {
116+ if (!shouldSnow (block , above )) {
122117 return false ;
123- } else if (!block .getBlockType ().getMaterial ().isFullCube ()) {
124- BlockType type = block .getBlockType ();
125- if (type .hasProperty (slab ) && block .getState (slab ).equalsIgnoreCase ("bottom" )) {
126- return false ;
127- } else if ((type .hasProperty (trapdoorOpen ) && block .getState (trapdoorOpen )) ||
128- (type .hasProperty (trapdoor ) && block .getState (trapdoor ).equalsIgnoreCase ("bottom" ))) {
118+ }
119+
120+ // in stack mode, we want to increase existing snow layers
121+ if (stack && above .getBlockType () == BlockTypes .SNOW ) {
122+ int layers = above .getState (PROPERTY_SNOW_LAYERS );
123+ // if we would place the last possible layer (in current versions layer 8) we just replace with a snow block and
124+ // set the block beneath snowy (if property is applicable, example would be grass with snow texture on top)
125+ if (layers == MAX_SNOW_LAYER - 1 && !this .extent .setBlock (abovePosition , SNOW_BLOCK )) {
129126 return false ;
130- } else if (type .hasProperty (stair ) && block .getState (stair ).equalsIgnoreCase ("bottom" )) {
127+ }
128+ // we've not reached the top snow layer yet, so just add another layer
129+ if (!this .extent .setBlock (abovePosition , above .with (PROPERTY_SNOW_LAYERS , layers + 1 ))) {
131130 return false ;
132- } else {
131+ }
132+ } else {
133+ if (!this .extent .setBlock (abovePosition , SNOW )) {
133134 return false ;
134135 }
135- //FAWE end
136- } else if (!BlockCategories .SNOW_LAYER_CAN_SURVIVE_ON .contains (block .getBlockType ())) {
136+ }
137+ // set block beneath snow (layers) snowy, if applicable
138+ if (block .getBlockType ().hasProperty (SNOWY )) {
139+ this .extent .setBlock (position , block .with (SNOWY , true ));
140+ }
141+ this .affected ++;
142+ return false ;
143+ }
144+
145+ /**
146+ * Check if snow should be placed at {@code above}
147+ *
148+ * @param blockState The block under the snow layer
149+ * @param above The block which will hold the snow layer
150+ * @return if snow should be placed
151+ */
152+ private boolean shouldSnow (BlockState blockState , BlockState above ) {
153+ // simplified net.minecraft.world.level.biome.Biome#shouldSnow
154+ // if the block, where the snow should be actually placed at, is not air or snow (if in stack mode), we can't place
155+ // anything
156+ if (!(above .isAir () || (above .getBlockType () == BlockTypes .SNOW && stack ))) {
157+ return false ;
158+ }
159+ // net.minecraft.world.level.block.SnowLayerBlock#canSurvive
160+ if (BlockCategories .SNOW_LAYER_CANNOT_SURVIVE_ON .contains (blockState )) {
137161 return false ;
138162 }
163+ if (BlockCategories .SNOW_LAYER_CAN_SURVIVE_ON .contains (blockState )) {
164+ return true ;
165+ }
166+ BlockType type = blockState .getBlockType ();
139167
140- if (stack && above .getBlockType () == BlockTypes .SNOW ) {
141- int currentHeight = above .getState (snowLayersProperty );
142- // We've hit the highest layer (If it doesn't contain current + 2 it means it's 1 away from full)
143- if (!snowLayersProperty .getValues ().contains (currentHeight + 2 )) {
144- if (this .extent .setBlock (abovePosition , snowBlock )) {
145- if (block .getBlockType ().hasProperty (snowy )) {
146- this .extent .setBlock (position , block .with (snowy , true ));
147- }
148- this .affected ++;
149- }
150- } else {
151- if (this .extent .setBlock (abovePosition , above .with (snowLayersProperty , currentHeight + 1 ))) {
152- if (block .getBlockType ().hasProperty (snowy )) {
153- this .extent .setBlock (position , block .with (snowy , true ));
154- }
155- this .affected ++;
156- }
157- }
168+ // net.minecraft.world.level.block.Block.isFaceFull (block has 1x1x1 bounding box)
169+ if (type .getMaterial ().isFullCube ()) {
170+ return true ;
171+ }
172+ // if block beneath potential snow layer has snow layers, we can place snow if all possible layers are present.
173+ if (type == BlockTypes .SNOW && blockState .getState (PROPERTY_SNOW_LAYERS ) == MAX_SNOW_LAYER ) {
174+ return true ;
175+ }
176+ // return potential non-full blocks, which could hold snow layers due to block states
177+ // if block is a slab, needs to be on the upper part of the block
178+ if (type .hasProperty (PROPERTY_SLAB )) {
179+ return PROPERTY_VALUE_TOP .equals (blockState .getState (PROPERTY_SLAB ));
180+ }
181+ // if block is a trapdoor, the trapdoor must NOT be open
182+ if (type .hasProperty (TRAPDOOR_OPEN ) && blockState .getState (TRAPDOOR_OPEN )) {
158183 return false ;
159184 }
160- if (this .extent .setBlock (abovePosition , snow )) {
161- if (block .getBlockType ().hasProperty (snowy )) {
162- this .extent .setBlock (position , block .with (snowy , true ));
163- }
164- this .affected ++;
185+ // if block is a closed trapdoor, the trapdoor must be aligned at the top part of the block
186+ if (type .hasProperty (TRAPDOOR )) {
187+ return PROPERTY_VALUE_TOP .equals (blockState .getState (TRAPDOOR ));
188+ }
189+ // if block is a stair, it must be "bottom" (upside-down)
190+ if (type .hasProperty (PROPERTY_STAIR )) {
191+ return PROPERTY_VALUE_BOTTOM .equals (blockState .getState (PROPERTY_STAIR ));
165192 }
166193 return false ;
167194 }
168195
196+ // net.minecraft.world.level.biome.Biome#shouldFreeze
197+ private boolean shouldFreeze (BlockVector3 position , BlockState blockState ) {
198+ return blockState .getBlockType () == BlockTypes .WATER &&
199+ blockState .getState (PROPERTY_WATER_LEVEL ) == 0 &&
200+ this .extent .getEmittedLight (position ) < 10 ;
201+ }
202+
169203}
0 commit comments