2020package com .sk89q .worldedit ;
2121
2222import com .google .common .collect .ImmutableList ;
23+ import com .google .common .collect .Maps ;
24+ import com .google .common .collect .Sets ;
2325import com .google .errorprone .annotations .InlineMe ;
2426import com .sk89q .worldedit .entity .BaseEntity ;
2527import com .sk89q .worldedit .entity .Entity ;
124126import com .sk89q .worldedit .world .World ;
125127import com .sk89q .worldedit .world .biome .BiomeType ;
126128import com .sk89q .worldedit .world .block .BaseBlock ;
129+ import com .sk89q .worldedit .world .block .BlockCategory ;
127130import com .sk89q .worldedit .world .block .BlockState ;
128131import com .sk89q .worldedit .world .block .BlockStateHolder ;
129132import com .sk89q .worldedit .world .block .BlockType ;
130133import com .sk89q .worldedit .world .block .BlockTypes ;
131134import com .sk89q .worldedit .world .generation .TreeType ;
135+ import com .sk89q .worldedit .world .registry .BlockMaterial ;
132136import com .sk89q .worldedit .world .registry .LegacyMapper ;
133137import org .apache .logging .log4j .Logger ;
134138
135139import java .util .ArrayDeque ;
136140import java .util .ArrayList ;
137141import java .util .Arrays ;
142+ import java .util .Collection ;
138143import java .util .Collections ;
139144import java .util .HashMap ;
140145import java .util .HashSet ;
@@ -2657,6 +2662,43 @@ public int deformRegion(final Region region, final Transform targetTransform, fi
26572662 return affected ;
26582663 }
26592664
2665+ private static Direction [] getBlockedDirections (Extent extent , BlockVector3 position ) {
2666+ BlockState blockState = extent .getBlock (position );
2667+ BlockType blockType = blockState .getBlockType ();
2668+ BlockMaterial material = blockState .getMaterial ();
2669+
2670+ if (material .isAir ()) {
2671+ return NO_DIRECTIONS ;
2672+ }
2673+ if (material .isLiquid ()) {
2674+ return NO_DIRECTIONS ;
2675+ }
2676+ Direction [] blockedDirections = BLOCKED_DIRECTIONS_OVERRIDE .get (blockType );
2677+ if (blockedDirections != null ) {
2678+ return blockedDirections ;
2679+ }
2680+ if (material .isFullCube ()) {
2681+ return CARDINAL_UPRIGHT_DIRECTIONS ;
2682+ }
2683+
2684+ Direction [] result = new Direction [CARDINAL_UPRIGHT_DIRECTIONS .length ];
2685+ int count = 0 ;
2686+
2687+ for (Direction direction : CARDINAL_UPRIGHT_DIRECTIONS ) {
2688+ if (material .isFullFace (direction )) {
2689+ result [count ++] = direction ;
2690+ }
2691+ }
2692+
2693+ // Short-cut for blocks that are blocked in all directions but for some reason not isFullCube
2694+ // This enables == comparison later
2695+ if (count == 6 ) {
2696+ return CARDINAL_UPRIGHT_DIRECTIONS ;
2697+ }
2698+
2699+ return Arrays .copyOf (result , count );
2700+ }
2701+
26602702 /**
26612703 * Hollows out the region (Semi-well-defined for non-cuboid selections).
26622704 *
@@ -2666,59 +2708,107 @@ public int deformRegion(final Region region, final Transform targetTransform, fi
26662708 *
26672709 * @return number of blocks affected
26682710 * @throws MaxChangedBlocksException thrown if too many blocks are changed
2711+ * @deprecated Use {@link EditSession#hollowOutRegion(Region, int, Pattern, boolean, Collection, boolean)} instead.
26692712 */
2670- public int hollowOutRegion (Region region , int thickness , Pattern pattern ) throws MaxChangedBlocksException {
2713+ @ InlineMe (replacement = "this.hollowOutRegion(region, thickness, pattern, true, null, false)" )
2714+ @ Deprecated
2715+ public final int hollowOutRegion (Region region , int thickness , Pattern pattern ) throws MaxChangedBlocksException {
2716+ return hollowOutRegion (region , thickness , pattern , true , null , false );
2717+ }
2718+
2719+ /**
2720+ * Hollows out the region (bounding-box mode is semi-well-defined for non-cuboid selections).
2721+ * The startingPositions parameter takes precedence over usePlacementPosition.
2722+ *
2723+ * @param region the region to hollow out.
2724+ * @param thickness the thickness of the shell to leave (manhattan distance)
2725+ * @param pattern The block pattern to use
2726+ * @param openSides Open up faces touching the bounding box. This matches the legacy behaviour.
2727+ * @param startingPositions Positions to consider as 'outside'. If null, use the selection bounding box
2728+ * @param useBlockGeometry Consider block geometry for visibility calculation
2729+ * @return number of blocks affected
2730+ * @throws MaxChangedBlocksException thrown if too many blocks are changed
2731+ */
2732+ public int hollowOutRegion (Region region , int thickness , Pattern pattern , boolean openSides , Collection <BlockVector3 > startingPositions , boolean useBlockGeometry ) throws MaxChangedBlocksException {
26712733 int affected = 0 ;
26722734
26732735 final Set <BlockVector3 > visible = new HashSet <>();
2736+ if (startingPositions == null ) {
2737+ // Initialize BFS with selection bounding box
2738+ final BlockVector3 min = region .getMinimumPoint ();
2739+ final BlockVector3 max = region .getMaximumPoint ();
2740+
2741+ final int minX = min .x ();
2742+ final int minY = min .y ();
2743+ final int minZ = min .z ();
2744+ final int maxX = max .x ();
2745+ final int maxY = max .y ();
2746+ final int maxZ = max .z ();
26742747
2675- // Initialize BFS with selection bounding box
2676- final BlockVector3 min = region .getMinimumPoint ();
2677- final BlockVector3 max = region .getMaximumPoint ();
2678-
2679- final int minX = min .x ();
2680- final int minY = min .y ();
2681- final int minZ = min .z ();
2682- final int maxX = max .x ();
2683- final int maxY = max .y ();
2684- final int maxZ = max .z ();
2748+ for (int x = minX ; x <= maxX ; ++x ) {
2749+ for (int y = minY ; y <= maxY ; ++y ) {
2750+ visible .add (BlockVector3 .at (x , y , minZ ));
2751+ visible .add (BlockVector3 .at (x , y , maxZ ));
2752+ }
2753+ }
26852754
2686- for (int x = minX ; x <= maxX ; ++x ) {
26872755 for (int y = minY ; y <= maxY ; ++y ) {
2688- visible .add (BlockVector3 .at (x , y , minZ ));
2689- visible .add (BlockVector3 .at (x , y , maxZ ));
2756+ for (int z = minZ ; z <= maxZ ; ++z ) {
2757+ visible .add (BlockVector3 .at (minX , y , z ));
2758+ visible .add (BlockVector3 .at (maxX , y , z ));
2759+ }
26902760 }
2691- }
26922761
2693- for (int y = minY ; y <= maxY ; ++y ) {
26942762 for (int z = minZ ; z <= maxZ ; ++z ) {
2695- visible .add (BlockVector3 .at (minX , y , z ));
2696- visible .add (BlockVector3 .at (maxX , y , z ));
2763+ for (int x = minX ; x <= maxX ; ++x ) {
2764+ visible .add (BlockVector3 .at (x , minY , z ));
2765+ visible .add (BlockVector3 .at (x , maxY , z ));
2766+ }
26972767 }
2698- }
26992768
2700- for (int z = minZ ; z <= maxZ ; ++z ) {
2701- for (int x = minX ; x <= maxX ; ++x ) {
2702- visible .add (BlockVector3 .at (x , minY , z ));
2703- visible .add (BlockVector3 .at (x , maxY , z ));
2769+ if (openSides ) {
2770+ // Remove movement blockers from visible list
2771+ visible .removeIf (blockVector3 -> getBlock (blockVector3 ).getBlockType ().getMaterial ().isMovementBlocker ());
27042772 }
2773+ } else {
2774+ visible .addAll (startingPositions );
27052775 }
27062776
2707- // Remove movement blockers from visible list
2708- visible .removeIf (blockVector3 -> getBlock (blockVector3 ).getBlockType ().getMaterial ().isMovementBlocker ());
2709-
27102777 // Do BFS to find more visible blocks
27112778 final Queue <BlockVector3 > queue = new ArrayDeque <>(visible );
27122779 while (!queue .isEmpty ()) {
27132780 final BlockVector3 current = queue .poll ();
27142781
2715- final BlockState block = getBlock (current );
2716- if (block .getBlockType ().getMaterial ().isMovementBlocker ()) {
2717- continue ;
2782+ Direction [] blockedDirections ;
2783+ if (useBlockGeometry ) {
2784+ // Get blocked directions for this block
2785+ blockedDirections = getBlockedDirections (this , current );
2786+
2787+ // Short-cut if blocked in all directions
2788+ if (blockedDirections == CARDINAL_UPRIGHT_DIRECTIONS ) {
2789+ continue ;
2790+ }
2791+ } else {
2792+ final BlockState block = getBlock (current );
2793+ if (block .getBlockType ().getMaterial ().isMovementBlocker ()) {
2794+ // In non-geometry mode, all movement blockers are assumed to be blocked in all directions, so short-cut here
2795+ continue ;
2796+ }
2797+
2798+ // All other blocks are assumed to have no blocked directions
2799+ blockedDirections = NO_DIRECTIONS ;
27182800 }
27192801
2720- for (BlockVector3 recurseDirection : CARDINAL_UPRIGHT_OFFSETS ) {
2721- final BlockVector3 neighbor = current .add (recurseDirection );
2802+ outer :
2803+ for (Direction direction : CARDINAL_UPRIGHT_DIRECTIONS ) {
2804+ // Check if this direction is blocked
2805+ for (Direction blockedDirection : blockedDirections ) {
2806+ if (blockedDirection == direction ) {
2807+ continue outer ; // skip this direction
2808+ }
2809+ }
2810+
2811+ final BlockVector3 neighbor = current .add (direction .toBlockVector ());
27222812
27232813 if (!region .contains (neighbor )) {
27242814 continue ;
@@ -3171,6 +3261,10 @@ public int morph(BlockVector3 position, double brushSize, int minErodeFaces, int
31713261 return changed ;
31723262 }
31733263
3264+ /**
3265+ * Contains no directions
3266+ */
3267+ private static final Direction [] NO_DIRECTIONS = {};
31743268 /**
31753269 * Contains all cardinal and upright directions
31763270 */
@@ -3184,6 +3278,77 @@ public int morph(BlockVector3 position, double brushSize, int minErodeFaces, int
31843278 .map (Direction ::toBlockVector )
31853279 .toArray (BlockVector3 []::new );
31863280
3281+ /**
3282+ * Some blocks need a special case for one reason or another
3283+ */
3284+ private static final Map <BlockType , Direction []> BLOCKED_DIRECTIONS_OVERRIDE = Maps .asMap (
3285+ Sets .newHashSet (
3286+ // fullcubes that you can see through on all 6 sides
3287+ BlockTypes .SPAWNER ,
3288+ BlockTypes .CHEST ,
3289+ BlockTypes .BEACON ,
3290+ BlockTypes .KELP ,
3291+ BlockTypes .KELP_PLANT ,
3292+ BlockTypes .MANGROVE_ROOTS ,
3293+ BlockTypes .ICE ,
3294+
3295+ BlockTypes .OAK_DOOR ,
3296+ BlockTypes .OAK_TRAPDOOR ,
3297+ // BlockTypes.SPRUCE_DOOR,
3298+ // BlockTypes.SPRUCE_TRAPDOOR,
3299+ // BlockTypes.BIRCH_DOOR,
3300+ // BlockTypes.BIRCH_TRAPDOOR,
3301+ BlockTypes .JUNGLE_DOOR ,
3302+ BlockTypes .JUNGLE_TRAPDOOR ,
3303+ BlockTypes .ACACIA_DOOR ,
3304+ BlockTypes .ACACIA_TRAPDOOR ,
3305+ // BlockTypes.DARK_OAK_DOOR,
3306+ // BlockTypes.DARK_OAK_TRAPDOOR,
3307+ // BlockTypes.MANGROVE_DOOR,
3308+ BlockTypes .MANGROVE_TRAPDOOR ,
3309+ BlockTypes .CHERRY_DOOR ,
3310+ BlockTypes .CHERRY_TRAPDOOR ,
3311+ // BlockTypes.PALE_OAK_DOOR,
3312+ // BlockTypes.PALE_OAK_TRAPDOOR,
3313+ BlockTypes .BAMBOO_DOOR ,
3314+ BlockTypes .BAMBOO_TRAPDOOR ,
3315+ BlockTypes .CRIMSON_DOOR ,
3316+ BlockTypes .CRIMSON_TRAPDOOR ,
3317+ BlockTypes .WARPED_DOOR ,
3318+ BlockTypes .WARPED_TRAPDOOR ,
3319+ BlockTypes .IRON_DOOR ,
3320+ BlockTypes .IRON_TRAPDOOR
3321+ ),
3322+ _ -> NO_DIRECTIONS
3323+ );
3324+
3325+ static {
3326+ BLOCKED_DIRECTIONS_OVERRIDE .put (BlockTypes .TRIAL_SPAWNER , new Direction [] { Direction .UP });
3327+ BLOCKED_DIRECTIONS_OVERRIDE .put (BlockTypes .VAULT , new Direction [] { Direction .UP , Direction .DOWN });
3328+ addSeeThroughBlockCategory ("minecraft:fall_damage_resetting" );
3329+ addSeeThroughBlockCategory ("minecraft:replaceable_by_trees" );
3330+
3331+ java .util .regex .Pattern pattern = java .util .regex .Pattern .compile ("^.*:(?:.*_)?(?:glass|grate|copper_door|copper_trapdoor)(?:_.*)?$" );
3332+ for (BlockType blockType : BlockType .REGISTRY ) {
3333+ if (pattern .matcher (blockType .id ()).matches ()) {
3334+ BLOCKED_DIRECTIONS_OVERRIDE .put (blockType , NO_DIRECTIONS );
3335+ }
3336+ }
3337+ }
3338+
3339+ private static void addSeeThroughBlockCategory (String blockCategoryKey ) {
3340+ BlockCategory blockCategory = BlockCategory .REGISTRY .get (blockCategoryKey );
3341+ if (blockCategory == null ) {
3342+ WorldEdit .logger .warn ("BlockCategory {} not found during initialization" , blockCategoryKey );
3343+ return ;
3344+ }
3345+
3346+ for (BlockType blockType : blockCategory .getAll ()) {
3347+ BLOCKED_DIRECTIONS_OVERRIDE .put (blockType , NO_DIRECTIONS );
3348+ }
3349+
3350+ }
3351+
31873352 private static double lengthSq (double x , double y , double z ) {
31883353 return (x * x ) + (y * y ) + (z * z );
31893354 }
0 commit comments